From: Jari Aalto Date: Mon, 23 Dec 1996 17:02:34 +0000 (+0000) Subject: Imported from ../bash-2.0.tar.gz. X-Git-Tag: devel-base-dist~9 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=ccc6cda312fea9f0468ee65b8f368e9653e1380b;hp=726f63884db0132f01745f1fb4465e6621088ccf;p=platform%2Fupstream%2Fbash.git Imported from ../bash-2.0.tar.gz. --- diff --git a/.distribution b/.distribution index 63738cc..cd5ac03 100644 --- a/.distribution +++ b/.distribution @@ -1 +1 @@ -1.14 +2.0 diff --git a/.patchlevel b/.patchlevel index 7f8f011..573541a 100644 --- a/.patchlevel +++ b/.patchlevel @@ -1 +1 @@ -7 +0 diff --git a/CHANGES b/CHANGES new file mode 100644 index 0000000..4f17c9f --- /dev/null +++ b/CHANGES @@ -0,0 +1,575 @@ +This document details the changes between this version, bash-2.0-release, +and the previous version, bash-2.0-beta3. + +1. Changes to Bash + +a. Fix to the `getopts' builtin so that it does the right thing when a + required option argument is not present. + +b. The completion code now updates the common prefix of matched names + after FIGNORE processing is done, since any names that were removed + may have changed the common prefix. + +c. Fixed a bug that made messages in MAILPATH entries not work correctly. + +d. Fixed a serious documentation error in the description of the new + ${parameter:offset[:length]} expansion. + +e. Fixes to make parameter substring expansion ({$param:offset[:length]}) + work when within double quotes. + +f. Fixes to make ^A (CTLESC) survive an unquoted expansion of positional + parameters. + +g. Corrected a misspelling of `unlimited' in the output of `ulimit'. + +h. Fixed a bug that caused executable scripts without a leading `#!' to + occasionally pick up the wrong set of positional parameters. + +i. Linux systems now have a working `ulimit -v', using RLIMIT_AS. + +j. Updated config.guess so that many more machine types are recognized. + +k. Fixed a bug with backslash-quoted slashes in the ${param/pat[/sub]} + expansion. + +l. If the shell is named `-su', and `-c command' is supplied, read and + execute the login shell startup files even though the shell is not + interactive. This is to support the `-' option to `su'. + +m. Fixed a bug that caused core dumps when the DEBUG trap was ignored + with `trap "" DEBUG' and a shell function was subsequently executed. + +n. Fixed a bug that caused core dumps in the read builtin when IFS was + set to the null string and the input had leading whitespace. + +2. Changes to Readline + +a. Fixed a bug that caused a numeric argument of 1024 to be ignored when + inserting text. + +b. Fixed the display code so that the numeric argument is displayed as it's + being entered. + +c. Fixed the numeric argument reading code so that `M-- command' is + equivalent to `M--1 command', as the prompt implies. + +3. New Features in Bash + +a. `ulimit' now sets both hard and soft limits and reports the soft limit + by default (when neither -H nor -S is specified). This is compatible + with versions of sh and ksh that implement `ulimit'. + +b. Integer constants have been extended to base 64. + +4. New Features in Readline + +a. The `home' and `end' keys are now bound to beginning-of-line and + end-of-line, respectively, if the corresponding termcap capabilities + are present. + +------------------------------------------------------------------------------ +This document details the changes between this version, bash-2.0-beta3, +and the previous version, bash-2.0-beta2. + +1. Changes to Bash + +a. System-specific changes for: AIX 4.2, SCO 3.2v[45], HP-UX. + +b. When in POSIX mode, variable assignments preceding a special builtin + persist in the shell environment after the builtin completes. + +c. Changed all calls to getwd() to getcwd(). Improved check for systems + where the libc getcwd() calls popen(), since that breaks on some + systems when job control is being used. + +d. Fixed a bug that caused seg faults when executing scripts with the + execute bit set but without a leading `#!'. + +e. The environment passed to executed commands is never sorted. + +f. A bug was fixed in the code that expands ${name[@]} to the number of + elements in an array variable. + +g. A bug was fixed in the array compound assignment code ( A=( ... ) ). + +h. Window size changes now correctly propagate down to readline if + the shopt `checkwinsize' option is enabled. + +i. A fix was made in the code that expands to the length of a variable + value (${#var}). + +j. A fix was made to the command builtin so that it did not turn on the + `no fork' flag inappropriately. + +k. A fix was made to make `set -n' work more reliably. + +l. A fix was made to the job control initialization code so that the + terminal process group is set to the shell's process group if the + shell changes its own process group. + +2. Changes to Readline + +a. System-specific changes for: SCO 3.2v[45]. + +b. The behavior of the vi-mode `.' when redoing an `i' command was changed + to insert the text previously inserted by the `i' command rather than + simply entering insert mode. + +3. New features in Bash + +a. There is a new version of the autoload function package, in + examples/functions/autoload.v2, that uses arrays and provides more + functionality. + +b. Support for LC_COLLATE and locale-specific sorting of the results of + pathname expansion if strcoll() is available. + +4. New Features in Readline + +a. Support for locale-specific sorting of completion possibilities if + strcoll() is available. + +------------------------------------------------------------------------------ +This document details the changes between this version, bash-2.0-beta2, +and the previous version, bash-2.0-beta1. + +1. Changes to Bash + +a. `pushd -' is once again equivalent to `pushd $OLDPWD'. + +b. OS-specific changes for: SCO 3.2v[45]. + +c. A change was made to the fix for the recently-reported security hole + when reading characters with octal value 255 to make it work better on + systems with restartable system calls when not using readline. + +d. Some changes were made to the test suite so that it works if you + configure bash with --enable-usg-echo-default. + +e. A fix was made to the parsing of conditional arithmetic expressions. + +f. Illegal arithmetic bases now cause an arithmetic evaluation error rather + than being silently reset. + +g. Multiple arithmetic bases now cause an arithmetic evaluation error + instead of being ignored. + +h. A fix was made to the evaluation of ${param?word} to conform to POSIX.2. + +i. A bug that sometimes caused array indices to be evaluated twice (which + would cause errors when they contained assignment statements) was fixed. + +j. `ulimit' was rewritten to avoid problems with getrlimit(2) returning + unsigned values and to simplify the code. + +k. A bug in the command-oriented-history code that caused it to sometimes + put semicolons after right parens inappropriately was fixed. + +l. The values inserted into the prompt by the \w and \W escape sequences + are now quoted to prevent further expansion. + +m. An interactive shell invoked as `sh' now reads and executes commands + from the file named by $ENV when it starts up. If it's a login shell, + it does this after reading /etc/profile and ~/.profile. + +n. The file named by $ENV is never read by non-interactive shells. + +2. Changes to Readline + +a. A few changes were made to hide some macros and functions that should not + be public. + +b. An off-by-one error that caused seg faults in the history expansion code + was fixed. + +3. New Features in Bash + +a. The ksh-style ((...)) arithmetic command was implemented. It is exactly + identical to let "...". This is controlled by a new option to configure, + `--enable-dparen-arithmetic', which is on by default. + +b. There is a new #define available in config.h.top: SYS_BASH_LOGOUT. If + defined to a filename, bash reads and executes commands from that file + when a login shell exits. It's commented out by default. + +c. `ulimit' has a `-l' option that reports the maximum amount of data that + may be locked into memory on 4.4BSD-based systems. + +------------------------------------------------------------------------------ +This document details the changes between this version, bash-2.0-beta1, +and the previous version, bash-2.0-alpha4. + +1. Changes to Bash + +a. A bug that sometimes caused traps to be ignored on signals the + shell treats specially was fixed. + +b. The internationalization code was changed to track the values of + LC_* variables and call setlocale() as appropriate. The TEXTDOMAIN + and TEXTDOMAINDIR variables are also tracked; changes cause calls + to textdomain() and bindtextdomain(), if available. + +c. A bug was fixed that sometimes caused double-quoted strings to be + parsed incorrectly. + +d. Changes were made so that the siglist code compiles correctly on + Solaris 2.5. + +e. Added `:' to the set of characters that cause word breaks for the + completion code so that pathnames in assignments to $PATH can be + completed. + +f. The `select' command was fixed to print $PS3 to stderr. + +g. Fixed an error in the manual page section describing the effect that + setting and unsetting GLOBIGNORE has on the setting of the `dotglob' + option. + +h. The time conversion code now uses CLK_TCK rather than CLOCKS_PER_SEC + on systems without gettimeofday() and resources. + +i. The getopt static variables are now initialized each time a subshell + is started, so subshells using `getopts' work right. + +j. A sign-extension bug that caused a possible security hole was fixed. + +k. The parser now reads characters between backquotes within a double- + quoted string as a single word, so double quotes in the backquoted + string don't terminate the enclosing double-quoted string. + +l. A bug that caused `^O' to work incorrectly when typed as the first + thing to an interactive shell was fixed. + +m. A rarely-exercised off-by-one error in the code that quotes variable + values was fixed. + +n. Some memory and file descriptor leaks encountered when running a + shell script that is executable but does not have a leading `#!' + were plugged. + +2. Changes to Readline + +a. A bug that sometimes caused incorrect results when trying to read + typeahead on systems without FIONREAD was fixed. + +3. New Features in Bash + +a. The command timing code now uses the value of the TIMEFORMAT variable + to format and display timing statistics. + +b. The `time' reserved word now accepts a `-p' option to force the + POSIX.2 output format. + +c. There are a couple of new and updated scripts to convert csh startup + files to bash format. + +d. There is a new builtin array variable: BASH_VERSINFO. The various + members hold the parts of the version information in BASH_VERSION, + plus the value of MACHTYPE. + +4. New Features in Readline + +a. Setting LANG to `en_US.ISO8859-1' now causes readline to enter + eight-bit mode. + +------------------------------------------------------------------------------ +This document details the changes between this version, bash-2.0-alpha4, +and the previous version, bash-2.0-alpha3. + +1. Changes to Bash + +a. There is better detection of rsh connections on Solaris 2. + +b. Assignments to read-only variables preceding a command name are now + variable assignment errors. Variable assignment errors cause + non-interactive shells running in posix mode to exit. + +c. The word tokenizer was rewritten to handle nested quotes and pairs + ('', "", ``, ${...}, $(...), $[...], $'...', $"...", <(...), >(...)) + correctly. Some of the parameter expansion code was updated as a + consequence. + +d. A fix was made to `test' when given three arguments so that a binary + operator is checked for first, before checking that the first argument + is `!'. + +e. 2''>/dev/null is no longer equivalent to 2>/dev/null. + +f. Parser error messages were regularized, and in most cases the name of + the shell script being read by a non-interactive shell is not printed + twice. + +g. A fix was made to the completion code so that it no longer removes the + text the user typed in some cases. + +h. The special glibc `getopt' environment variable is no longer put into + the environment on machines with small values of ARG_MAX. + +i. The expansion of ${...} now follows the POSIX.2 rules for finding the + closing `}'. + +j. The shell no longer displays spurious status messages for background + jobs in shell scripts that complete successfully when the script is + run from a terminal. + +k. `shopt -o' now correctly updates $SHELLOPTS. + +l. A bug that caused the $PATH searching code to return a non-executable + file even when an executable file with the same name appeared later in + $PATH was fixed. + +m. The shell now does tilde expansions on unquoted `:~' in assignment + statements when not in posix mode. + +n. Variable assignment errors when a command consists only of assignments + now cause non-interactive shells to exit when in posix mode. + +o. If the variable in a `for' or `select' command is read-only, or not a + legal shell identifier, a variable assignment error occurs. + +p. `test' now handles `-a' and `-o' as binary operators when three arguments + are supplied, and correctly parses `( word )' as equivalent to `word'. + +q. `test' was fixed so that file names of the form /dev/fd/NN mean the same + thing on all systems, even Linux. + +r. Fixed a bug in the globbing code that caused patterns with multiple + consecutive `*'s to not be matched correctly. + +s. Fixed a bug that caused $PS2 to not be printed when an interactive shell + not using readline is reading a here document. + +t. Fixed a bug that caused history expansion to be performed inappropriately + when a single-quoted string spanned more than one line. + +u. `getopts' now checks that the variable name passed by the user as the + second argument is a legal shell identifier and that the variable is + not read-only. + +v. Fixed `getopts' to obey POSIX.2 rules for setting $OPTIND when it + encounters an error. + +w. Fixed `set' to display variable values in a form that can be re-read. + +x. Fixed a bug in the code that keeps track of whether or not local variables + have been declared at the current level of function nesting. + +y. Non-interactive shells in posix mode now exit if the name in a function + declaration is not a legal identifier. + +z. The job control code now ignores stopped children when the shell is not + interactive. + +aa. The `cd' builtin no longer attempts spelling correction on the directory + name if the shell is not interactive, regardless of the setting of the + `cdspell' option. + +bb. Some OS-specific changes were made for SCO 3.2v[45] and AIX 4.2. + +cc. `time' now prints its output to stderr, as POSIX.2 specifies. + +2. Fixes to Readline + +a. After printing possible completions, all lines of a multi-line prompt + are redisplayed. + +b. Some changes were made to the terminal handling code in rltty.c to + work around AIX 4.2 bugs. + +3. New Features in Bash + +a. There is a new loadable builtin: sprintf, with calling syntax + sprintf var format [args] + This provides an easy way to simulate ksh left- and right-justified + variable values. + +b. The expansions of \h and \H in prompt strings were swapped. \h now + expands to the hostname up to the first `.', as in bash-1.14. + +4. New Features in Readline + +a. The bash-1.14 behavior when ^M is typed while doing an incremental + search was restored. ^J may now be used to terminate the search without + accepting the line. + +b. There is a new bindable variable: disable-completion. This inhibits + word completion and causes the completion character to be inserted as + if it had been bound to self-insert. + +------------------------------------------------------------------------------ +This document details the changes between this version, bash-2.0-alpha3, +and the previous version, bash-2.0-alpha2. + +There is now a file `COMPAT' included in the distribution that lists the +user-visible incompatibilities between 1.14 and 2.0. + +1. Changes to Bash + +a. Some work was done so that word splitting of the rhs of assignment + statements conforms more closely to historical practice. + +b. A couple of errant memory frees were fixed. + +c. A fix was made to the test builtin so it recognizes `<' and `>' as + binary operators. + +d. The GNU malloc in lib/malloc/malloc.c now scrambles memory as it's + allocated and freed. This is to catch callers that refer to freed + memory or assume something about newly-allocated memory. + +e. Fixed a problem with conversion to 12-hour time in the prompt + expansion code. + +f. Fixed a problem with configure's argument parsing order. Now you can + correctly turn on specific options after using --enable-minimal-config. + +g. The configure script now automatically disables the use of GNU malloc + on systems where it's appropriate (better than having people read the + NOTES file and do it manually). + +h. There are new prompt expansions (\v and \V) to insert version information + into the prompt strings. + +i. The default prompt string now includes the version number. + +j. Most of the builtins that take no options were changed to use the + internal getopt so they can produce proper error messages for -? + and incorrect options. + +k. Some system-specific changes were made for SVR4.2 and Solaris 2.5. + +l. Bash now uses PATH_MAX instead of MAXPATHLEN and NAME_MAX instead of + MAXNAMLEN. + +m. A couple of problems caused by uninitialized variables were fixed. + +n. There are a number of new loadable builtin examples: logname, basename, + dirname, tty, pathchk, tee, head, and rmdir. All of these conform to + POSIX.2. + +o. Bash now notices changes in TZ and calls tzset() if present, so + changing TZ will alter the time printed by prompt expansions. + +p. The source was reorganized a bit so I don't have to wait so long for + some files to compile, and to facilitate the creation of a `shell + library' at some future point. + +q. Bash no longer turns off job control if called as `sh', since the + POSIX.2 spec includes job control as a standard feature. + +r. `bash -o posix' now works as intended. + +s. Fixed a problem with the completion code: when completing a filename + that contained globbing characters, if show-all-if-ambiguous was set, + the completion code would remove the user's text. + +t. Fixed ulimit so that (hopefully) the full range of limits is available + on HPUX systems. + +u. A new `shopt' option (`hostcomplete') enables and disables hostname + completion. + +v. The shell no longer attempts to save the history on an abort(), + which is usually called by programming_error(). + +w. The `-s' option to `fc' was changed to echo the command to be executed + to stderr instead of stdout. + +x. If the editor invoked by `fc -e' exits with a non-zero status, no + commands are executed. + +y. Fixed a bug that made the shopt `histverify' option work incorrectly. + +z. There is a new variable `MACHTYPE' whose value is the GNU-style + `cpu-company-system' system description as set by configure. (The + values of MACHTYPE and HOSTTYPE should really be swapped.) + +aa. The `ulimit' builtin now allows the maximum virtual memory size to be + set via setrlimit(2) if RLIMIT_VMEM is defined. + +bb. `bash -nc 'command'' no longer runs `command'. + +2. Changes to Readline + +a. Fixed a typo in the code that checked for FIONREAD in input.c. + +b. Fixed a bug in the code that outputs keybindings, so things like C-\ + are quoted properly. + +c. Fixed a bug in the inputrc file parsing code to handle the problems + caused by inputrc files created from the output of `bind -p' in + previous versions of bash. The problem was due to the bug fixed + in item b above. + +d. Readline no longer turns off the terminal's meta key, and turns it on + once the first time it's called. + +------------------------------------------------------------------------------ +This file documents the changes between this version, bash-2.0-alpha2, +and the previous version, bash-2.0-alpha. + +1. Changes to Bash + +a. The shell no longer thinks directories are executable. + +b. `disown' has a new option, `h', which inhibits the resending of SIGHUP + but does not remove the job from the jobs table. + +c. The varargs functions in error.c now use ANSI-C `stdarg' if available. + +d. The build process now treats the `build version' in .build as local to + the build directory, so different versions built from the same source + tree have different `build versions'. + +e. Some problems with the grammar have been fixed. (It used `list' in a few + productions where `compound_list' was needed. A `list' must be terminated + with a newline or semicolon; a `compound_list' need not be.) + +f. A fix was made to keep `wait' from hanging when waiting for all background + jobs. + +g. `bash --help' now writes its output to stdout, like the GNU Coding Standards + specify, and includes the machine type (the value of MACHTYPE). + +h. `bash --version' now prints more information and exits successfully, like + the GNU Coding Standards specify. + +i. The output of `time' and `times' now prints fractional seconds with three + places after the decimal point. + +j. A bug that caused process substitutions to screw up the pipeline printed + by `jobs' was fixed. + +k. Fixes were made to the code that implements $'...' and $"..." so they + work as documented. + +l. The process substitution code now opens named pipes for reading with + O_NONBLOCK to avoid hanging. + +m. Fixes were made to the trap code so the shell cleans up correctly if the + trap command contains a `return' and we're executing a function or + sourcing a script with `.'. + +n. Fixes to doc/Makefile.in so that it doesn't try to remake all of the + documentation (ps, dvi, etc.) on a `make install'. + +o. Fixed an auto-increment error that caused bash -c args to sometimes dump + core. + +p. Fixed a bug that caused $HISTIGNORE to fail when the history line + contained globbing characters. + +2. Changes to Readline + +a. There is a new string variable, rl_library_version, available for use by + applications. The current value is "2.1". + +b. A bug encountered when expand-tilde was enabled and file completion was + attempted on a word beginning with `~/' was fixed. + +c. A slight change was made to the incremental search termination behavior. + ESC still terminates the search, but if input is pending or arrives + within 0.1 seconds (on systems with select(2)), it is used as a prefix + character. This is intented to allow users to terminate searches with + the arrow keys and get the behavior they expect. diff --git a/COMPAT b/COMPAT new file mode 100644 index 0000000..af6c127 --- /dev/null +++ b/COMPAT @@ -0,0 +1,78 @@ +This document details the incompatibilites between this version of bash, +bash-2.0, and the previous version, bash-1.14. These were discovered +by alpha and beta testers, so they will likely be encountered by a +significant number of users. + +1. Bash now uses a new quoting syntax, $"...", to do locale-specific + string translation. Users who have relied on the (undocumented) + behavior of bash-1.14 will have to change their scripts. For + instance, if you are doing something like this to get the value of + a variable whose name is the value of a second variable: + + eval var2=$"$var1" + + you will have to change to a different syntax. + + This capability is directly supported by bash-2.0: + + var2=${!var1} + + This alternate syntax will work portably between bash-1.14 and bash-2.0: + + eval var2=\$${var1} + +2. One of the bugs fixed in the YACC grammar tightens up the rules + concerning group commands ( {...} ). The `list' that composes the + body of the group command must be terminated by a newline or + semicolon. That's because the braces are reserved words, and are + recognized as such only when a reserved word is legal. This means + that while bash-1.14 accepted shell function definitions like this: + + foo() { : } + + bash-2.0 requires this: + + foo() { :; } + + This is also an issue for commands like this: + + mkdir dir || { echo 'could not mkdir' ; exit 1; } + + The syntax required by bash-2.0 is also accepted by bash-1.14. + +3. The options to `bind' have changed to make them more consistent with + the rest of the bash builtins. If you are using `bind -d' to list + the readline keybindings in a form that can be re-read, use `bind -p' + instead. If you were using `bind -v' to list the keybindings, use + `bind -P' instead. + +4. The `long' invocation options must now be prefixed by `--' instead + of `-'. (The old form is still accepted, for the time being.) + +5. There was a bug in the version of readline distributed with bash-1.14 + that caused it to write badly-formatted key bindings when using + `bind -d'. The only key sequences that were affected are C-\ (which + should appear as \C-\\ in a key binding) and C-" (which should appear + as \C-\"). If these key sequences appear in your inputrc, as, for + example, + + "\C-\": self-insert + + they will need to be changed to something like the following: + + "\C-\\": self-insert + +6. A number of people complained above having to use ESC to terminate an + incremental search, and asked for an alternate mechanism. Bash-2.0 + allows ^J to terminate the search without accepting the line. Use + ^M to terminate the search and accept the line, as in bash-1.14. + +7. Some variables have been removed: MAIL_WARNING, notify, history_control, + command_oriented_history, glob_dot_filenames, allow_null_glob_expansion, + nolinks, hostname_completion_file, noclobber, no_exit_on_failed_exec, and + cdable_vars. Most of them are now implemented with the new `shopt' + builtin; others were already implemented by `set'. + +8. The `ulimit' builtins now sets both hard and soft limits and reports the + soft limit by default (when neither -H nor -S is specified). This is + compatible with versions of sh and ksh that implement `ulimit'. diff --git a/COPYING b/COPYING index d642012..b6daf7d 100644 --- a/COPYING +++ b/COPYING @@ -1,9 +1,8 @@ - GNU GENERAL PUBLIC LICENSE - Version 1, February 1989 + Version 2, June 1991 - Copyright (C) 1989 Free Software Foundation, Inc. - 675 Mass Ave, Cambridge, MA 02139, USA + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. @@ -17,30 +16,33 @@ based primarily on Bash as opposed to other GNU software. Preamble - The license agreements of most software companies try to keep users -at the mercy of those companies. By contrast, our General Public + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free -software--to make sure the software is free for all its users. The -General Public License applies to the Free Software Foundation's -software and to any other program whose authors commit to using it. -You can use it for your programs, too. +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. When we speak of free software, we are referring to freedom, not -price. Specifically, the General Public License is designed to make -sure that you have the freedom to give away or sell copies of free -software, that you receive source code or can get it if you want it, -that you can change the software or use pieces of it in new free -programs; and that you know you can do these things. +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. - For example, if you distribute copies of a such a program, whether + For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the -source code. And you must tell them their rights. +source code. And you must show them these terms so they know their +rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, @@ -53,120 +55,207 @@ want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - 0. This License Agreement applies to any program or other work which -contains a notice placed by the copyright holder saying it may be -distributed under the terms of this General Public License. The -"Program", below, refers to any such program or work, and a "work based -on the Program" means either the Program or any work containing the -Program or a portion of it, either verbatim or with modifications. Each -licensee is addressed as "you". - - 1. You may copy and distribute verbatim copies of the Program's source -code as you receive it, in any medium, provided that you conspicuously and -appropriately publish on each copy an appropriate copyright notice and -disclaimer of warranty; keep intact all the notices that refer to this -General Public License and to the absence of any warranty; and give any -other recipients of the Program a copy of this General Public License -along with the Program. You may charge a fee for the physical act of -transferring a copy. - - 2. You may modify your copy or copies of the Program or any portion of -it, and copy and distribute such modifications under the terms of Paragraph -1 above, provided that you also do the following: - - a) cause the modified files to carry prominent notices stating that - you changed the files and the date of any change; and - - b) cause the whole of any work that you distribute or publish, that - in whole or in part contains the Program or any part thereof, either - with or without modifications, to be licensed at no charge to all - third parties under the terms of this General Public License (except - that you may choose to grant warranty protection to some or all - third parties, at your option). - - c) If the modified program normally reads commands interactively when - run, you must cause it, when started running for such interactive use - in the simplest and most usual way, to print or display an - announcement including an appropriate copyright notice and a notice - that there is no warranty (or else, saying that you provide a - warranty) and that users may redistribute the program under these - conditions, and telling the user how to view a copy of this General - Public License. - - d) You may charge a fee for the physical act of transferring a - copy, and you may at your option offer warranty protection in - exchange for a fee. - -Mere aggregation of another independent work with the Program (or its -derivative) on a volume of a storage or distribution medium does not bring -the other work under the scope of these terms. + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) - 3. You may copy and distribute the Program (or a portion or derivative of -it, under Paragraph 2) in object code or executable form under the terms of -Paragraphs 1 and 2 above provided that you also do one of the following: - - a) accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of - Paragraphs 1 and 2 above; or, - - b) accompany it with a written offer, valid for at least three - years, to give any third party free (except for a nominal charge - for the cost of distribution) a complete machine-readable copy of the - corresponding source code, to be distributed under the terms of - Paragraphs 1 and 2 above; or, - - c) accompany it with the information you received as to where the - corresponding source code may be obtained. (This alternative is +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you - received the program in object code or executable form alone.) - -Source code for a work means the preferred form of the work for making -modifications to it. For an executable file, complete source code means -all the source code for all modules it contains; but, as a special -exception, it need not include source code for modules which are standard -libraries that accompany the operating system on which the executable -file runs, or for standard header files or definitions files that -accompany that operating system. - - 4. You may not copy, modify, sublicense, distribute or transfer the -Program except as expressly provided under this General Public License. -Any attempt otherwise to copy, modify, sublicense, distribute or transfer -the Program is void, and will automatically terminate your rights to use -the Program under this License. However, parties who have received -copies, or rights to use copies, from you under this General Public -License will not have their licenses terminated so long as such parties -remain in full compliance. - - 5. By copying, distributing or modifying the Program (or any work based -on the Program) you indicate your acceptance of this license to do so, -and all its terms and conditions. + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the original -licensor to copy, distribute or modify the Program subject to these -terms and conditions. You may not impose any further restrictions on the -recipients' exercise of the rights granted herein. +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. - 7. The Free Software Foundation may publish revised and/or new versions + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program -specifies a version number of the license which applies to it and "any +specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of -the license, you may choose any version ever published by the Free Software +this License, you may choose any version ever published by the Free Software Foundation. - 8. If you wish to incorporate parts of the Program into other free + 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes @@ -176,7 +265,7 @@ of promoting the sharing and reuse of software generally. NO WARRANTY - 9. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED @@ -186,7 +275,7 @@ TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - 10. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING @@ -201,22 +290,21 @@ POSSIBILITY OF SUCH DAMAGES. Appendix: How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest -possible use to humanity, the best way to achieve this is to make it -free software which everyone can redistribute and change under these -terms. +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. - To do so, attach the following notices to the program. It is safest to -attach them to the start of each source file to most effectively convey -the exclusion of warranty; and each file should have at least the -"copyright" line and a pointer to where the full notice is found. + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. - Copyright (C) 19yy + Copyright (C) 19yy This program 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 1, or (at your option) - any later version. + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -225,33 +313,35 @@ the exclusion of warranty; and each file should have at least the You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: - Gnomovision version 69, Copyright (C) 19xx name of author + Gnomovision version 69, Copyright (C) 19yy name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. -The hypothetical commands `show w' and `show c' should show the -appropriate parts of the General Public License. Of course, the -commands you use may be called something other than `show w' and `show -c'; they could even be mouse-clicks or menu items--whatever suits your -program. +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here a sample; alter the names: +necessary. Here is a sample; alter the names: - Yoyodyne, Inc., hereby disclaims all copyright interest in the - program `Gnomovision' (a program to direct compilers to make passes - at assemblers) written by James Hacker. + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice -That's all there is to it! +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/CWRU/PLATFORMS b/CWRU/PLATFORMS index a792966..e479a29 100644 --- a/CWRU/PLATFORMS +++ b/CWRU/PLATFORMS @@ -1,18 +1,28 @@ The version of bash in this directory has been compiled on the following systems: -Sun 690 SunOS 4.1.2 -Sparcstation SunOS 5.3 -Sparcstation NetBSD 0.9a -386 BSDI BSD/386 1.0, 1.1 -NeXTstation NeXT OS 2.1 -IBM RT IBM/4.3 (AOS) -Motorola Delta 88K SVR3.2 -Decstation 3100 Ultrix 4.3 -Dec 4000 Alpha AXP DEC OSF/1 V1.3 -386 ISC UNIX 3.0.1 -386 FreeBSD 1.1 -IBM RS/6000 AIX 3.2 -Amiga Amiga UNIX 2.1 -Sony NEWS 841 NEWS OS -HP 9000/834 HP/UX 7.0 +By chet: + +SunOS 4.1.4 +SunOS 5.5 +BSDI BSD/OS 2.1 +Motorola SVR3.2 +FreeBSD 2.1.5 +AIX 4.2 +HP/UX 9.05, 10.01, 10.10, 10.20 + +By other testers: + +SCO ODT 2.0 +SCO 3.2v5.0, 3.2v4.2 +SunOS 5.3 +SunOS 5.5 +BSD/OS 2.1 +FreeBSD 2.2 +SunOS 4.1.3 +Irix 5.3 +Irix 6.2 +Linux 2.0 (unknown distribution) +Digital OSF/1 3.2 +GNU Hurd 0.1 +SVR4.2 diff --git a/CWRU/POSIX.NOTES b/CWRU/POSIX.NOTES index bc9a969..304289e 100644 --- a/CWRU/POSIX.NOTES +++ b/CWRU/POSIX.NOTES @@ -1,63 +1,86 @@ -Starting bash with the `-posix' command-line option or setting the variable -POSIXLY_CORRECT while bash is running will cause bash to conform more -closely to the Posix.2 standard by changing the behavior to match that -specified by Posix.2 in areas where the bash default differs. +Bash POSIX Mode +=============== -The following list is what's changed when `posixly_correct' is enabled: +Starting Bash with the `--posix' command-line option or executing `set +-o posix' while Bash is running will cause Bash to conform more closely +to the POSIX.2 standard by changing the behavior to match that +specified by POSIX.2 in areas where the Bash default differs. -1. When a command in the hash table no longer exists, bash will re-search - $PATH to find the new location. +The following list is what's changed when `POSIX mode' is in effect: -2. The >& redirection does not redirect stdout and stderr. + 1. When a command in the hash table no longer exists, Bash will + re-search `$PATH' to find the new location. This is also + available with `shopt -s checkhash'. -3. The message printed by the job control code and builtins when a job - exits with a non-zero status is `Done(status)'. + 2. The `>&' redirection does not redirect stdout and stderr. -4. The <> redirection does not open a file for both stdin and stdout, but - rather opens it for read-write on fd 0. + 3. The message printed by the job control code and builtins when a job + exits with a non-zero status is `Done(status)'. -5. Reserved words may not be aliased. + 4. Reserved words may not be aliased. -6. The Posix.2 PS1 and PS2 expansions of `!' -> history number and `!!' -> `!' - are enabled. + 5. The POSIX.2 `PS1' and `PS2' expansions of `!' to the history + number and `!!' to `!' are enabled, and parameter expansion is + performed on the value regardless of the setting of the + `promptvars' option. -7. Interactive comments are enabled by default. (Note that this version has - them on by default anyway.) + 6. Interactive comments are enabled by default. (Note that Bash has + them on by default anyway.) -8. The Posix.2 startup files are executed ($ENV) rather than the normal bash - files. + 7. The POSIX.2 startup files are executed (`$ENV') rather than the + normal Bash files. -9. Tilde expansion is only performed on assignments preceding a command name, - rather than on all assignment statements on the line. + 8. Tilde expansion is only performed on assignments preceding a + command name, rather than on all assignment statements on the line. -10. The default history file is ~/.sh_history (default value of $HISTFILE). + 9. The default history file is `~/.sh_history' (this is the default + value of `$HISTFILE'). -11. The output of `kill -l' prints all the signal names on a single line, - separated by spaces. + 10. The output of `kill -l' prints all the signal names on a single + line, separated by spaces. -12. Non-interactive shells exit if `file' in `. file' is not found. + 11. Non-interactive shells exit if FILENAME in `.' FILENAME is not + found. -13. Redirection operators do not perform pathname expansion on the word - in the redirection unless the shell is interactive + 12. Redirection operators do not perform filename expansion on the word + in the redirection unless the shell is interactive. -14. Function names must be valid shell identifiers. That is, they may not - contain characters other than letters, digits, and underscores, and - may not start with a digit + 13. Function names must be valid shell `name's. That is, they may not + contain characters other than letters, digits, and underscores, and + may not start with a digit. Declaring a function with an illegal + name causes a fatal syntax error in non-interactive shells. -There is other Posix.2 behavior that bash does not implement. Specifically: + 14. POSIX.2 `special' builtins are found before shell functions during + command lookup. -1. There are no `special builtins' and `regular builtins'. All builtins - are equivalent. This means that: + 15. If a POSIX.2 special builtin returns an error status, a + non-interactive shell exits. The fatal errors are those listed in + the POSIX.2 standard, and include things like passing incorrect + options, redirection errors, variable assignment errors for + assignments preceding the command name, and so on. - o assignment statements affect the execution environment of all - builtins, not just special ones - o temporary assignments do not persist after Posix.2 special - builtins complete - o Functions are found before Posix.2 special builtins - o The shell does not exit upon errors while executing Posix.2 - special builtins + 16. If the `cd' builtin finds a directory to change to using + `$CDPATH', the value it assigns to the `PWD' variable does not + contain any symbolic links, as if `cd -P' had been executed. -2. $LINENO does not represent the line number of a command within a function + 17. A non-interactive shell exits with an error status if a variable + assignment error occurs when no command name follows the assignment + statements. A variable assignment error occurs, for example, when + trying to assign a value to a read-only variable. + + 18. A non-interactive shell exits with an error status if the iteration + variable in a `for' statement or the selection variable in a + `select' statement is a read-only variable. + + 19. Process substitution is not available. + + 20. Assignment statements preceding POSIX.2 `special' builtins persist + in the shell environment after the builtin completes. + + +There is other POSIX.2 behavior that Bash does not implement. +Specifically: + + 1. Assignment statements affect the execution environment of all + builtins, not just special ones. -3. The arithmetic evaluator does not implement the `e ? e1 : e2' conditional - expression diff --git a/CWRU/README b/CWRU/README index 8e3398d..01c721a 100644 --- a/CWRU/README +++ b/CWRU/README @@ -1,26 +1,17 @@ -Notes: - -ISC 386 machines must compile test.c without -O. The resultant shell dumps -core when test is invoked. - -There have been reports that SCO 3.2v4.2 requires -DPRGP_PIPE in SCO_CFLAGS, -and that it has too many -D defines for SCO's cc (rcc works). - Contents of this directory: -CWRU.chlog - my change log since the last release - -KSH.README - list of similarities with ksh. Slightly out of date - -PLATFORMS.113 - list of platforms I have built this release on +changelog - my change log since the last release POSIX.NOTES - list of what changes for `posix mode' README - this file -RSH.README - explanation of the bash `restricted shell' mode +misc - directory with some useful tools + +The following are distributed `as-is'. They will not apply without some +modification. +sh-redir-hack - diff to parse.y to get redirections before + compound commands -misc - directory with some useful tools -OS-BUGS - directory with messages detailing some OS bugs and - the bash workarounds +mh-folder-comp - diffs that reportedly add MH folder completion diff --git a/CWRU/changelog b/CWRU/changelog index 11d6775..d09a5b5 100644 --- a/CWRU/changelog +++ b/CWRU/changelog @@ -781,6 +781,7619 @@ builtins/read.def make sure we call dequote_string on each word of the input before calling bind_variable with that string + 8/6 + --- +lib/readline/readline.h + - removed definition of rl_show_star -- the variable no longer + exists + +lib/readline/readline.h, lib/readline/history.h + - reorganized to follow texinfo manual structure + +lib/readline/bind.c + - rl_function_dumper is now static + - rl_list_funmap names does not take any arguments + +builtins/bind.def + - rl_list_funmap names does not take any arguments + +lib/readline/readline.c, lib/readline/signals.c + - rl_init_argument ->_rl_init_argument + +lib/readline/rltty.c + - remove declaration and references to output_was_flushed + +support/getcppsyms.c + - if __uxps__ is defined, define __uxps__ and __svr4__ + + 8/9 + --- +support/mkdist + - added a -r option to set the `root name' of the distribution + (e.g., `bash' or `readline') + + 8/10 + ---- +input.c + - if check_bash_input sees that default_buffered_input is about + to be the target of a redirection, but the buffered input stream + is not the current input stream (e.g. as the result of an + `eval' while in a script, change default_buffered_input to a + new fd and use a new variable `bash_input_fd_changed' to note + the change + +parse.y + - if pop_stream sees that default_buffered_input has changed while + a buffered stream was on the save stack (because + bash_input_fd_changed is non-zero), then make the popped stream + and the corresponding buffer use the new fd + +test.c + - fixed an off-by-one error in test_stat when testing /dev/fd/n. + +cpp-Makefile + - add -I$(incdir) to CPPFLAGS + - add `incdir = $(prefix)/include' assignment + + 8/11 + ---- +lib/readline/signals.c + - changed some calls to signal () to call rl_set_sighandler() + - call _rl_redisplay_after_sigwinch from the sigwinch handler + to do better redisplay of wrapped command lines and multi-line + prompts + +builtins/suspend.def + - changed some calls to signal () to call set_signal_handler() + +lib/readline/*.c + - include config.h before anything else if HAVE_CONFIG_H is defined + +lib/readline/readline.c + - renamed rl_set_mark to _rl_set_mark_at_pos + - call _rl_vi_initialize_line from rl_initialize if the current + editing mode is vi mode + - only output a term_cr in crlf if term_cr is non-null + +lib/readline/readline.h + - added declarations for rl_vi_set_mark and rl_vi_goto_mark + +lib/readline/readline.c, lib/readline/readline.h + - added a new bindable command to set the mark, rl_set_mark + +lib/readline/funmap.c + - new bindable function with name `set-mark', bound to rl_set_mark + - new bindable vi-mode functions with names `vi-set-mark' and + `vi-goto-mark' + +documentation/{bash.1,readline.3}, lib/readline/doc/rluser.texinfo + - added documentation for `set-mark' (unbound) + +lib/readline/vi_mode.c + - new vi-command mode commands to save marks (the vi `m' command) + and go to saved marks (the ``' command) + - new function _rl_vi_initialize_line called from rl_initialize + to set up the line state in vi mode. Right now this just resets + all the marks + +lib/readline/vi_keymap.c + - new vi command-mode bindings to set the mark (`m') and to go to + a saved mark (``') + +documentation/readline.3 + - added vi-set-mark and vi-goto-mark to list of key bindings for + vi command mode + +lib/readline/{readline.c,display.c} + - renamed term_xn to _rl_term_autowrap + +lib/readline/display.c + - new function _rl_redisplay_after_sigwinch to encapsulate the + necessary redisplay code after a SIGWINCH is received + +variables.c + - only call find_user_command on the shell name in shell_initialize + if shell_name is not an absolute program name + - call canonicalize_pathname on the full shell pathname after + calling make_absolute on it if the shell name starts with a `.' + +siglist.h + - FreeBSD does not need a definition of sys_siglist[] + + 8/12 + ---- +lib/readline/rltty.c + - don't try to use FLUSHO unless FLUSHO is defined + +cpp-Makefile + - make sure to pass $(CC) to the make in the lib/malloc subdirectory + +lib/readline/readline.c + - don't declare PC, UP, and BC as extern; it causes too many problems + + 8/13 + ---- +machines.h + - add -DNO_SBRK_DECL to SYSDEP_CFLAGS for SVR4.2 on i386 + +support/mksysdefs + - new variable UNAME_S for the output of `uname -s' + - if uname -s does not output the same thing as uname, and uname -s + outputs UNIX_SV, then set UNAME to UNIX_SV. Some versions of i386 + SVR4.2 make `uname' equivalent to `uname -n' + +lib/readline/memalloc.h + - removed from the library; not needed since readline does not use + alloca + +lib/readline/{history.c,isearch.c,search.c,rldefs.h}, lib/tilde/tilde.c + - no longer include memalloc.h + +lib/readline/Makefile + - remove dependencies on memalloc.h + +lib/readline/signals.c + - overhauled signal handling based on ideas from Bruno Haible + (haible@ma2s2.mathematik.uni-karlsruhe.de) so that readline + saves and restores the signal mask and flags on Posix systems + - don't include fcntl.h, sys/file.h, errno.h, or stdlib.h + - ignore SIGALRM during rl_signal_handler like SIGINT until the + old handler is installed, on non-Posix or non-BSD systems + - new define SIGHANDLER_RETURN, dependent on the value of + VOID_SIGHANDLER + - use RETSIGTYPE instead of `sighandler' as the signal handler + return type; it's the name autoconf uses. If not defined, + set up from VOID_SIGHANDLER + +lib/readline/rltty.c + - call control_meta_key and control_keypad from rl_deprep_terminal + before putting the terminal back into ICANON mode to avoid + messing up the tty driver + + 8/15 + ---- +cpp-Makefile + - changes so that fewer -Idir arguments are passed to the make + in ./builtins + + 8/16 + ---- +lib/readline/bind.c + - use KEYMAP_SIZE instead of 128 in rl_invoking_keyseqs_in_map + +lib/readline/complete.c + - qsort the array of matches omitting matches[0], which must stay + in place no matter what, even if strcmp doesn't compare unsigned + chars correctly + - some fixes to the loop that prints the list of completions + +lib/readline/keymaps.c + - run the loop up to 127 when creating a new keymap in rl_make_keymap + +input.h, general.h, lib/readline/keymaps.h, lib/readline/tilde.h + - use _FUNCTION_DEF instead of __FUNCTION_DEF + +lib/readline/parens.c + - include "config.h" if HAVE_CONFIG_H is defined + - include if HAVE_SYS_SELECT_H is defined + - use HAVE_SELECT instead of FD_SET as the `configuring define'; + define HAVE_SELECT if it is not already defined but FD_SET is + +lib/readline/readline.c, lib/readline/rltty.c + - the __GO32__ include file is + +lib/tilde/tilde.c + - rewrote tilde_expand_word, eliminated static u_name array in + favor of using xmalloc + +lib/tilde/tilde.h + - use single leading underscore for file inclusion guard + +lib/readline/vi_mode.c + - use KEYMAP_SIZE rather than a literal 127 as the loop limit when + creating the overstrike keymap + +support/install.sh + - new file, from the make-3.71 distribution + + 8/17 + ---- +lib/readline/complete.c, lib/readline/readline.h + - new variable, rl_basic_quote_characters, used to see + if a word break character was a quoting character, so we can + do appropriate quoting after the completion + +lib/readline/parens.c + - use rl_basic_quote_characters when trying to find a matching + open paren + +lib/readline/doc/rltech.texinfo + - description of rl_basic_quote_characters + + 8/18 + ---- +newversion.c + - renamed to support/mkversion.c, which builds to mkversion + +cpp-Makefile + - changed to use support/mkversion + - removed instances of $< except in suffix rules -- some makes don't + handle those right + +lib/readline/rldefs.h + - make sure to #undef HAVE_DIRENT_H on NeXT machines + + + 8/19 + ---- +lib/readline/readline.h + - removed some duplicate function declarations + +trap.h + - define DEBUG_TRAP as NSIG for the last slot in trap_list + - define EXIT_TRAP as 0 + - declare trap_list as array of unknown size, since this is just a + header file + +trap.c + - extend trap_list and sigmodes to NSIG+1 + - initialize DEBUG_TRAP to do nothing; changes to functions to handle + DEBUG_TRAP + - let decode_signal return OK if NSIG is given, even though this will + vary between systems, for DEBUG_TRAP + - make reset_signal_handlers and restore_original_signals loop from + 1 to NSIG, not 0 to NSIG + - change GET_ORIGINAL_SIGNAL to try to get the original signal handler + only if `sig' is less than NSIG + - restore_default_signal just frees the trap string for both EXIT_TRAP + and DEBUG_TRAP + - run_debug_trap: new function to run traps on DEBUG + - free_trap_command: new function to free a trap string if it is + really a command and not one of the special trap values + - if a SIGINT trap resets the SIGINT trap string, free the old string + - new function: set_debug_trap(char *), which will reset the DEBUG + trap string, suitable for calling from an unwind-protect handler + +signames.c + - arrange things so that signal_names[NSIG] == "DEBUG" + +builtins/trap.def + - make sure traps on DEBUG are printed + +execute_cmd.c + - call run_debug_trap at the end of the `cm_simple' case in + execute_command_internal + - change execute_function so that traps on DEBUG do not propagate + into the function + +documentation/bash.1, documentation/features.texi + - documented the new DEBUG trap + + 8/20 + ---- +shell.c, config.h + - made the name of the restricted shell configurable in config.h; + the option is RESTRICTED_SHELL_NAME + +shell.c + - if the shell is invoked as `sh', enter Posix.2 mode after running + /etc/profile and ~/.profile + +builtins/read.def + - added a -p option for a prompt string, which is displayed before + trying to read anything + +documentation/bash.1 + - description of `read -p' + - description of new -r and -s options to `jobs' + +documentation/features.texi + - description of new -r and -s options to `jobs' + +jobs.c + - new functions: list_running_jobs, list_stopped_jobs + - list_jobs -> list_all_jobs + - new function `print_job' to do the work for all of the list*jobs + functions + - list_one_job type now void, calls print_job to do the work + +jobs.h + - new declarations for list_running_jobs, list_stopped_jobs + - list_one_job now void + - list_jobs -> list_all_jobs + +builtins/jobs.def + - new options: -r to print only running jobs, -s to print only + stopped jobs + + 8/22 + ---- +lib/readline/readline.c + - don't try to expand a null prompt string + +subst.c + - remove special handling of hostname_completion_file and + history_control; HOSTFILE and HISTCONTROL are the acceptable + names + - new function sv_histignore; call if HISTIGNORE variable is + assigned to + +bashhist.c + - new functions and declarations for handling HISTIGNORE variable + and its specifications for command lines to ignore + - change maybe_add_history to call history_should_ignore if the + HISTCONTROL tests are passed + +documentation/bash.1, documentation/features.texi + - removed mention of history_control and hostname_completion_file + - added description of HISTIGNORE + + 8/23 + ---- +array.c, array.h + - promoted to the shell mainline code; the `array' subdir is now + gone + +variables.h + - include `array.h' for the ARRAY typedef + +variables.c + - changes to assignment() to handle array assignments a[x]=b + - split off the creation of new variables into a new function: + make_new_variable + - split off the construction of variable values for assignments and + bindings into a new function: make_variable_value + - new function: bind_array_variable, to handle the addition of + new array variables and indices + +subst.c + - changes to do_assignment_internal to handle a[x]=b: + parse the subscript out of the name and call evalexp() on it + call bind_array_variable to do the value assignment + - change the printing of assignment statements when -x is in effect + to before the variable binding is attempted, so any error messages + look better + - new functions for referencing indexed arrays and to find the length + of arrays or array indices + + 8/24 + ---- +expr.c + - fixed up error reporting to use get_name_for_error if not executing + a builtin + +subst.c + - everywhere evalexp() is called, use maybe_expand_string to expand + the expression (calls expand_string if necessary) + +subst.h + - extern declarations for array convenience functions exported to the + rest of the shell + +variables.c + - more new convenience array functions: make_new_array_variable and + convert_var_to_array + +builtins/declare.def + - additions to declare_internal to add a -a flag which makes array + variables, and the requisite semantics (declare +a does not work, + declare -a name=value does not work, etc.) + - code to support the ksh-like declare a[] syntax to make array + variables + +builtins/setattr.def + - made set_or_show_attributes understand array variables and `-a' + +builtins/set.def + - changes to make `unset name' work, where name is an array variable + - changes to make `unset name[xxx]' work + + 8/25 + ---- + +lib/readline/readline.c + - make sure meta characters are added to a keyboard macro as + ESC-char if we are converting meta chars to ascii + - change rl_unix_word_rubout to handle repeat counts + - move the check of LC_CTYPE from rl_initialize to + readline_initialize_everything, where it should have been + all along + +error.c + - make sure is included before + +machines.h + - new entry for Bull DPX2 + +lib/tilde/tilde.c + - include before + +variables.c + - PS1 and PS2 are no longer non-unsettable + + 8/26 + ---- +variables.c + - PPID, UID, and EUID, since they are read-only, need not appear on + the `non-unsettable' list + - PATH and IFS now have the `nounset' attribute set rather than use + a separate `non-unsettable' list + - the non-unsettable list and non_unsettable() are gone + +variables.h + - new define `non_unsettable_p' to test nounset attribute + +builtins/set.def + - `unset' now uses non_unsettable_p to tell whether a variable can + be unset even if it's not readonly + +builtins/read.def + - read -a arrayname will read a list of values from stdin and assign + them to the array `arrayname', splitting on " \t\n" (honoring + backslash quoting if -r is not supplied) + +builtins/declare.def + - print values of arrays when `display -a' is invoked + +builtins/exit.def + - remove references to `bye' + + 8/28 + ---- +lib/readline/rltty.c + - removed calls to control_keypad; they cause problems on some + machines and should not really be performed by an application + +cpp-Makefile + - support for optionally linking array.o into the shell + +lib/glob/glob.c + - when returning an error after glob_filename on the directory name + returns an error result, make sure to free `result'. This fixes + a memory leak for names passed to glob_filename which contain + globbing characters before the first `/' but do not match any + existing files + + 8/29 + ---- +execute_cmd.c + - the `for' and `select' commands should expand their word lists + using expand_words_no_vars + +command.h, execute_cmd.c, general.c, make_cmd.c, print_cmd.c, subst.c,parse.y + - changed the `dollar_present', `quoted', and `assignment' members + of WORD_DESC to a single flags word + + 8/30 + ---- +variables.c + - make get_string_value return array[0] if called with a variable + that is an array + + 8/31 + ---- +lib/readline/display.c + - don't take the value of _rl_term_autowrap into account when + computing which screen line the cursor should be on; it screws + up wrapping on terminals without the `xn' capability + +lib/readline/examples/rltest.c + - new file, test code moved here from readline.c + +documentation/features.texi, lib/readline/doc/hsuser.texinfo + - fixed up printing of some of the shell options and the history + commands and modifiers + +subst.c + - make sure $name, where `name' is an array variable, returns + ${name[0]} + +variables.c + - convert a variable to an array even if index 0 is being assigned to, + instead of leaving it a `normal' variable + + 9/1 + --- + +builtins/setattr.def + - make sure that array variables printed by `declare' single-quote + the value after the `=' so the statement can be reused as input + +variables.c + - make sure array variables can be exported (name=(assignments)), and + that the export code works. The code is commented out because of + the possible confusion between an array and a regular string that + looks like an array assignment string. + + 9/2 + --- +variables.c + - make sure there is an executable file with the same name as + `shell' name in the current directory before assigning it to + $BASH at startup. If there is not, just make $BASH the login + shell name + + 9/3 + --- +parse.y + - removed a reduction from the `list0' production that could cause + statements which require semicolons to be allowed without error + (like before a `}' in a group command) + +lib/readline/display.c + - new functions: _rl_save_prompt and _rl_restore_prompt to save and + restore prompt invisible character info + - if the redisplay code encounters a line shorter than the old one + and containing invisible characters, make sure that the cursor is + at the end of the new text before calling clear_to_eol + - new variable last_invisible containing the index in the prompt + string of the last invisible character. We only have to redraw + the prompt string of _rl_last_c_pos is < last_invisible + - new function _rl_make_prompt_for_search to take care of setting + up the prompt string for a non-incremental search when the prompt + contains invisible characters + - fix so that a prompt string with invisible characters is not + redrawn each time through update_line (don't tputs term_cr unless + the cursor is before the last invisible character in the prompt + and will be moving past the last invisible char of the prompt + +lib/readline/isearch.c + - call _rl_save_prompt and _rl_restore_prompt when changing the prompt + to do i-search + + 9/4 + --- +lib/readline/readline.c + - doing_an_undo -> _rl_doing_an_undo for use by the vi-mode code + - rewrote rl_do_undo to reformat and eliminate a clumsy goto + - new split the add-to-kill-ring code off into a separate function, + _rl_copy_to_kill_ring + - added a new bindable function rl_copy_region_as_kill + - added a new bindable function rl_kill_region + - moved _rl_char_search_internal to here from vi_mode.c + - new bindable function rl_char_search + +lib/readline/vi_mode.c + - made `.' work for the `cw' and `[Ss]' commands, which implicitly + put the editor into insertion mode after they run + - split rl_vi_char_search code that actually searches for a character + into a new function, _rl_char_search_internal + +lib/readline/emacs_keymap.c + - bind M-= to possible-completions for ksh compatibility + - bind M-* to insert-completions + - bind C-x C-x to exchange-point-and-mark + - bind C-] to character-search + - bind C-@ to set-mark + +lib/readline/funmap.c + - new bindable function names: exchange-point-and-mark, kill-region, + copy-region-as-kill, character-search + +lib/readline/readline.h + - declare rl_exchange_point_and_mark, rl_copy_region_to_kill, + rl_kill_region, and rl_char_search externally + +documentation/{bash.1,readline.3}, lib/readline/doc/rluser.texinfo + - document new exchange-point-and-mark bindable command + - documented M-* default emacs-mode binding to insert-completions + - documented new copy-region-as-kill and kill-region commands + - documented new character search emacs-mode command + - documented new binding for set-mark + +lib/readline/rldefs.h + - moved values for `dir' when searching for characters in the line + from vi_mode.c to here + + 9/6 + --- +general.c + - new function ansicstr, which decodes ANSI-C backslash-escaped + characters (with the addition of \e and \E to mean escape) and + returns a new string + +subst.c + - new expansion $'...' which translates ANSI-C backslash escapes + in `...' and expands to the result + +builtins/echo.def + - ifdefs for ANSI-C for \a and \v rather than just expanding to + literal ASCII values + +documentation/bash.1 + - documented new $'...' expansion + + 9/7 + --- +builtins/enable.def + - fixed up the help text + - added a -s flag to restrict operation to Posix.2 `special' builtins + - removed -all option; -a is the way to do it now + - converted to use the builtin getopt + +builtins/common.c + - changed builtin_address_internal to return a pointer to a + struct builtin, which makes it much more useful. Changed + find_shell_builtin and builtin_address accordingly + - new function find_special_builtin, which returns special builtins + ((flags & SPECIAL_BUILTIN) != 0) + +execute_cmd.c + - in Posix.2 mode, find special builtins before shell functions + when performing command lookup + - in find_user_command_internal, return NULL if there is no $PATH + - in Posix.2 mode, failure of a special builtin causes a non- + interactive shell to exit + +variables.c + - allow $PATH to be unset + + 9/8 + --- +input.h + - added a new `input type': st_stdin, for use when using readline, + since readline is not properly a string + +parse.y + - surgery on the grammar: + o added new `compound_list' production: a list that can end + without a newline, `;' or `&' (used in subshell commands + and case clause commands) + o removed shell_command_1, folded rules into command + o eliminated pattern_list_1; changed case_clause_sequence to + directly incorporate the SEMI_SEMI token (a pattern_list_1 + was just a pattern_list with a trailing SEMI_SEMI) + o new `for_command' and `case_command' productions + o redirections -> redirection_list + o newlines -> newline_list + o redid the code that attaches redirections to the function + command rather than the function definition and eliminated + all of the shift/reduce conflicts + - changed with_input_from_stdin in the readline case to set + bash_input.type to st_stdin + +print_cmd.c + - a couple of changes to the way functions are printed + +shell.c + - only execute the PROMPT_COMMAND if input is not coming from a + string (bash_input.type != st_string). This fixes the problem + of PROMPT_COMMAND being executed by `eval' commands in an + interactive shell + + 9/12 + ---- +shell.c + - all interactive shells SIGHUP running jobs when exiting due to + a SIGHUP, not just login shells + + 9/13 + ---- +config.h, config.h.mini + - changed the default primary prompt (PPROMPT) to "\s\$ " + - removed the INTERACTIVE_COMMENTS define + +flags.c + - interactive comments are now enabled by default, regardless of the + INTERACTIVE_COMMENTS define + +input.h + - a new enum: stream_type, used in the BASH_INPUT struct + +parse.y + - bash_input.type is now initialized to st_none + +bashhist.c + - command_oriented_history is now the default + +documentation/bash.1 + - removed description of `nolinks' variable, updated set -P + description + - removed description of `notify' variable, updated set -b + description + - removed description of `noclobber' variable, updated set -C + description + +variables.c + - IFS may now be unset + +builtins/read.def + - now does the right thing if IFS is unset (acts as if it is + set to " \t\n") + +builtins/cd.def + - added a new parameter to change_to_directory () which says + whether or not to follow symlinks, instead of using the + global no_symbolic_links + - changed cd_builtin to accept a -P option to disable symlink + following temporarily + +builtins/ulimit.def + - instead of using a hardcoded `long' for the return type of the + rlimit functions, use RLIMTYPE, which defaults to long + - new defines string_to_rlimtype -> string_to_long and + print_rlimtype for systems which do not need `RLIMTYPE' defined + to something other than long + +general.c + - function replacements for string_to_rlimtype and print_rlimtype + for machines which have RLIMTYPE defined in the machine description + +general.h + - extern declarations for string_to_rlimtype and print_rlimtype + +shell.c + - don't source file named by $ENV at script startup if act_like_sh + is turned on + +machines.h + - new entry for amiga/netbsd + - change all the netbsd entries to add -DRLIMTYPE=quad_t to + SYSDEP_CFLAGS + +siglist.h + - define sys_siglist as _sys_siglist on the amiga only if USGr4 is + defined + +print_cmd.c + - change so that printf is not prototyped on LynxOS with gcc + +lib/readline/Makefile + - changed the `installdirs' target to not fail if the directories + do not need creating + +lib/readline/history.c + - fixed a bug in history_arg_extract which manifested itself when + !* was used after a command without arguments (e.g., pwd ; echo !*) + + 9/15 + ---- +subst.c + - expand_word_internal should preserve the flags (other than + W_QUOTED) from the word passed as a parameter on the word it returns + - expand_words_internal renamed to expand_word_list_internal + - expand_word_list_internal does not perform word splitting or + globbing on words with the W_ASSIGNMENT bit set + - removed special treatment of `notify', `command_oriented_history', + `history_control', and `nolinks' + - rewrote some of the sv_* functions to remove or avoid calls to + sscanf, one of the most expensive C library functions + +variables.c + - don't look for $command_oriented_history at startup, since it now + defaults to `on' + +general.h, general.c + - new function posix_initialize to do whatever is necessary to enable + `Posix mode' + +shell.c, subst.c + - call posix_initialize + +general.c + - rewrote replacements for strchr, strrchr to make them faster + +builtins/enable.def + - new -f option and necessary support to load builtins from a shared + object file on systems supporting both dlopen() and dlsym(). New + builtins loaded this way can replace existing shell builtins or + add completely new functionality + +builtins.h + - mkbuiltins.c creates `static_shell_builtins', which is a fixed + array, `shell_builtins' points to this array initially + - extern declaration for current_builtin + +builtins/mkbuiltins.c + - change to creat static_shell_builtins[] and declare shell_builtins + as a pointer to it + - change to declare `current_builtin' in created builtins.c + +builtins/source.def + - print an error message and return failure if no filename argument + is supplied + +builtins/common.c + - current_builtin is set by find_shell_builtin, find_special_builtin, + and builtin_address_internal + - new function builtin_usage, which prints the contents of + current_builtin->short_doc + +builtins/{bind,declare,enable,fc,getopts,hash,history,jobs,kill,read,set, + setattr,trap,ulimit,umask}.def + - changed the builtins in these files to use builtin_usage() to + print usage messages + +cpp-Makefile + - support for the HAVE_DLOPEN and HAVE_DLSYM defines + +machines.h + - added -ldl and -Bdynamic to the SunOS4 entry + +documentation/{bash.1,features.texi} + - documented new enable -f option to dynamically load builtins + + 9/16 + ---- +test.c + - added `==' as a synonym for `=' + + 9/18 + ---- +bashline.c + - include readline/rlconf.h so that VI_MODE is defined if + appropriate + +shell.c + - removed `-nobraceexpansion' option + +flags.c, flags.h + - added new -B flag; enabled if brace expansion is turned on + +subst.c + - use brace_expand instead of !no_brace_expand + +builtins/set.def + - change set -o braceexpand to be equivalent to set -B + +parse.y + - in with_input_from_stdin, do nothing if bash_input.type already + is st_stdin or if there is already a stream with type st_stdin + on the saved stream stack + - new function stream_on_stack to find out if there is a saved + stream of a specified type + +documentation/bash.1, documentation/features.texi + - doeumented new set -B option + - removed -nobraceexpansion shell startup option + + 9/19 + ---- +builtins/reserved.def + - made `help select' work + +cpp-Makefile + - removed references to the nonexistant `load.def' + - removed conditionals based on GETOPTS_BUILTIN + +builtins/getopts.def + - no longer $DEPENDS_ON GETOPTS_BUILTIN + +config.h, config.h.mini, builtins/help.def + - made the `help' builtin dependent on the HELP_BUILTIN define + - removed GETOPTS_BUILTIN + +builtins/mkbuiltins.c + - made the `$DEPENDS_ON' clause work for reserved words and + shell control structures in reserved.def by writing out + dependencies to builtext.h even if there is no `function' + - made the long_doc for each builtin and reserved word get + written out to builtins.c with #ifdef HELP_BUILTIN surrounding + the doc strings -- this makes the minimal shell much smaller + +shell.c, documentation/bash.1 + - removed `-quiet' long option + +parse.y + - make sure that word splitting is not performed on the prompt + string after expanding in prompt_string_decode by calling + expand_string_unsplit instead of expand_string + +lib/readline/bind.c + - new readline variable `mark-directories': if set, completed + directory names have a slash appended + +lib/readline/complete.c + - support for `mark-directories' + +documentation/{bash.1,readline.3}, lib/readline/doc/rluser.texinfo + - documented the new `mark-directories' variable + +builtins/bind.def + - new option `-r' to remove a binding for a specified key sequence + - make sure that a failure return from bind resets the keymap + correctly if a -m option was supplied + +documentation/{bash.1,features.texi} + - documented new bind -r option + + 9/20 + ---- +builtins/jobs.def + - new `disown' builtin + +documentation/{bash.1,features.texi} + - documented new `disown' builtin + +cpp-Makefile + - removed support for `MAKE_SHELL' cpp variable + - renamed endian.aux to mkendian, look for endian.c in support dir + - link in array.o, alias.o, braces.o, bracecomp.o + unconditionally, rely on cpp defines in the files to exclude code + - pass -DHAVE_SYS_SIGLIST if sys_siglist is defined + - pass -DHAVE_GETCWD if HAVE_GETCWD is defined in machines.h + - pass -DHAVE_VFPRINTF_EMUALTION through from machines.h to + compilation + +array.c + - don't compile in body of file unless ARRAY_VARS is defined + +braces.c + - don't compile in body of file unless BRACE_EXPANSION is defined + +alias.c + - don't compile in body of file unless ALIAS is defined + +bracecomp.c + - don't compile in body of file unless BRACE_EXPANSION and READLINE + are defined + +bashline.c + - don't compile in body of file unless READLINE is defined + +bashhist.c + - don't compile in body of file unless HISTORY is defined + +siglist.c + - don't compile in body of file unless HAVE_SYS_SIGLIST is not + defined + +getcwd.c + - don't compile in body of file unless HAVE_GETCWD is not defined + +vprint.c + - don't compile in body of file unless USE_VFPRINTF_EMULATION + is defined + +support/mksysdefs + - for SCO machines, define SYSDEF as SCO or SCOv4 + +lib/readline/readline.[ch] + - new function rl_push_macro_input (s), which makes s the current + macro input string + +endian.c + - renamed to support/endian.c + + 9/21 + ---- +lib/readline/complete.c + - more file types for the VISIBLE_STATS code: + | FIFOs + % character special devices + # block special devices + +lib/readline/isearch.c + - made RETURN an alternate search string terminator + +builtins/read.def + - removed use of stdio -- unbuffered stdio on a dup of fd 0 is + a big loss + +builtins/set.def + - new function: minus_o_option_value, returns 1, 0, or -1 given + a -o option name (-1 means a bad name) + - reorganized list_minus_o_options to be more efficient + +execute_cmd.c + - when expanding a here document, use maybe_expand_string rather + than a simple expand_string to try a speed things up a bit + +input.c + - don't compile in the body of the file unless BUFFERED_INPUT + is defined in config.h + + 9/22 + ---- +jobs.h, siglist.h + - replaced instances of Solaris with SunOS5 + +shell.c + - changed long option parsing code so that --arg is equivalent + to -arg, when `arg' is one of the recognized multichar options + +builtins/history.def + - rewrote to regularize the option parsing and use internal_getopt + - now allows only one of -awrn to be specified + - added a new -p option that adds each of its arguments to the + end of the history list, and deletes the `history -p' history + entry + +builtins/trap.def + - added new -p option to display specified trap values, or all + trap values if no other arguments supplied + +documentation/{bash.1,features.texi} + - documented new history -p option + - documented new trap -p option + + 9/25 + ---- +lib/readline/display.c + - fixed up the calcluation of the correct cursor line number (a `+' + and `-' were transposed in the calculation of `nleft') + + 9/26 + ---- +general.c + - moved isint() here from test.c, renamed to legal_number + +general.h + - extern declaration of legal_number + +test.c + - only compile isint() if SHELL is not defined, define it as + legal_number otherwise + +trap.c + - use legal_number in decode_signal instead of sscanf() + +builtins/common.c + - moved list_sigs to here from trap.def, renamed to + display_signal_list + - changed get_numeric_arg to use legal_number instead of doing + the parsing and calculation itself + +builtins/common.h + - extern declaration for display_signal_list + +builtins/{trap.def + - changed to use display_signal_list for trap -l + +builtins/kill.def + - changed to use display_signal_list for kill -l + - added new kill -n signum option + +documentation/bash.1 + - added description of new kill -l signame functionality + - added description of new kill -n signum feature + - added description of new enable -d option + +builtins.h + - added a char *handle member to `struct builtin' for later use + - new flags value: BUILTIN_DELETED + +builtins/mkbuiltins.c + - added code to inintialize the `handle' member to null in the + static builtin array definition + +builtins/common.c + - don't `find' a builtin if the BUILTIN_DELETED flag is set in the + flags word of the struct builtins array + +builtins/enable.def + - new option -d to remove a builtin loaded with -f, depends on + HAVE_DLCLOSE + +cpp-Makefile + - pass -DHAVE_DLCLOSE through from machines.h to compilation + +machines.h + - change SunOS4 machine description to define HAVE_DLCLOSE + + 9/27 + ---- +shell.c + - split shell exit code off into a separate function: exit_shell(status) + +builtins/exec.def + - rewrote for clarity and speed and to use the builtin getopt() + - added new -a, -c, and -l options + - now calls exit_shell if shell_execve fails and the shell is not + interactive + +documentation/bash.1 + - documented the new options to `exec' + + 9/28 + ---- +builtins/exec.def + - if the execve fails and the shell is not going to exit, reinitialize + traps and signals + - only call end_job_control if subshell_environment != 0 + - exec should exit unconditionally if the execve fails and + subshell_environment != 0 + +subst.c + - if valid_brace_expansion_word fails, make sure `temp' is set to + NULL before trying to free it after the `goto bad_substitution' + +cpp-Makefile + - add $(CPPFLAGS) to the compilation flags when making `mksignames' + +documentation/features.texi + - fixed a typo in the tilde expansion section + + 9/29 + ---- +machines.h + - DEC OSF/1 has the dlopen/dlsym/dlclose set of library functions + +shell.c + - don't execute /etc/profile if -noprofile given + +builtins/pushd.def + - new file, pushd/popd/dirs split off from cd.def + - replaced calls to sscanf with calls to legal_number + +builtins/Makefile, cpp-Makefile + - changes for pushd.def + +config.h, config.h.mini + - ALLOW_RIGID_POSIX_COMPLIANCE is no longer used + +subst.c, variables.c + - GETOPTS_BUILTIN is no longer used + +variables.c + - if the first character of argv[0] is not a `/', search the path + and canonicalize the result to find out how to set $BASH + + 10/2 + ---- +builtins/enable.def + - changed enable_shell_builtin to use builtin_address_internal to find + the builtin rather than searching the list itself + - list_some_builtins skips a builtin if flags & BUILTIN_DISABLED != 0 + - rewrote dyn_load_builtin to take a list of names to load from a + single filename + - don't dlclose the shared object in dyn_unload_builtin unless its + reference count drops to 0 + +builtins/test.def + - don't bother making new copies of everything in the argument list + when constructing the argc and argv for test_command; just make + sure not to free anything but ARGV + + 10/3 + ---- +bashline.c + - remove C-e binding in vi movement mode which switches into emacs + mode + +general.c + - make xfree only try to call free on non-null strings + + 10/4 + ---- +builtins/read.def + - new `-e' option that uses readline to read the line + - if one of the arguments is not a legal variable name, print an + error message and return failure + +builtins/reserved.def + - changed the `Variables' to `variables' so `help variables' works + +subst.c + - set startup_state to 2 in child of command substitution to try to + avoid some unneeded forks + +trap.c + - removed call to reset_terminating_signals in restore_original + signals; callers are now required to take care of that themselves, + if necessary + +execute_cmd.c, subst.c + - added necessary calls to reset_terminating_signals before calls + to restore_original_signals + +execute_cmd.c + - when executing a null command in a subshell, don't bother passing + a string to make_child; just pass NULL + - in execute_builtin_or_function, don't add so many unwind-protects + if `subshell' == 1 + - in command_substitute, call cleanup_the_pipeline to discard the + old pipeline, so pipeline_pgrp does not get set to 0 in + start_pipeline, which is called by make_child via making_children + +jobs.c, nojobs.c + - new function, ignore_tty_job_signals, to set SIGTTIN, SIGTTOU, and + SIGTSTP to SIG_IGN + - new function, default_tty_job_signals, to set those signals + to SIG_DFL + - new function, cleanup_the_pipeline to free up the_pipeline and + set it to NULL + + 10/5 + ---- +builtins/history.def + - the history -p option is now -s (to sort of parallel the ksh + print -s option) + - the -s option now combines all of its arguments into a single + string and appends the string to the history list + - new history -p option to history expand each argument and print + the result without modifying the history list + +documentation/bash.1, documentation/features.texi + - documented the new -e option to read + - documented the new history -s and -p options + - documented the new cd and pwd -L options + +builtins/cd.def + - changed cd and pwd to use internal_getopt + - added the -L option to cd and pwd to follow symlinks (like if + set +P were issued) + +builtins/pushd.def + - added text for dirs +N and dirs -N to the dirs builtin long doc + - added -v option to dirs to print dirstack one dir per line with + stack index prepended + + 10/6 + ---- +execute_cmd.c + - split the command searching code into a new function: + search_for_command + - removed a bunch of dead code from shell_execve + - removed call to reset_terminating_signals when executing a function + or builtin in a subshell (either via (xxx) or xxx &) + - don't add unwind protects at all in execute_function if subshell == 1 + +lib/readline/chardefs.h + - new macro ALPHABETIC(c), returns 1 if c is a letter or digit + +lib/readline/readline.c + - don't call abort() in rl_change_case(); it's impolite in a + library function + - new macro, SWAP, used to swap values of two integers + - changed alphabetic to use ALPHABETIC, made it slightly faster + - modified rl_change_case() so that word capitalization is the + same as GNU Emacs + +lib/readline/search.c + - in noninc_dosearch, don't reset the history positition to what + it was if we're currently in vi editing mode (as per Posix.2 + `/' and `?' vi-mode editing commands) + + 10/7 + ---- +builtins/common.c + - changed single_quote and double_quote to use char pointers + rather than string indexing + - new function backslash_quote(string), which quotes special + characters in STRING using backslashes + + 10/8 + ---- +alias.h + - added an extern declaration for alias_expand_word + +parse.y + - broke the alias expansion code off into a function + alias_expand_token; its return value says whether to re-read + a token or go on + - changed the alias expansion code to handle aliases that expand + to nothing better + - broke the code that does special-case token recognition off into + a function: special_case_tokens + - used the new functions to make sure that the special-case tokens + can be the expansion of an alias + - made sure that if in `posix mode' that reserved words cannot be + aliased and that all reserved words can be the values of aliases + and be recognized after expansion + + 10/10 + ----- +lib/readline/complete.c + - replaced #ifdef SHELL code with two new exported readline interfaces: + rl_filename_quoting_function and rl_filename_dequoting_function. + Both return a pointer to char. + - new extern variable rl_filename_quote_characters, containing a list + of characters that cause a word to be quoted by the completer if + they appear in a file name + +bashline.c + - new functions for rl_filename_quoting_function and + rl_filename_dequoting_function. + - initialize rl_filename_quoting_function and rl_filename_dequoting_function + in initialize_readline + - initialize rl_filename_quote_characters + +lib/readline/readline.h + - extern declarations for new public interfaces + rl_filename_quoting_function and rl_filename_dequoting_function + - added declarations for NO_MATCH, SINGLE_MATCH, and MULT_MATCH for + use by the filename quoting functions + - new extern declaration for rl_filename_quote_characters + +lib/readline/history.c + - made a version of single_quote be compiled in if SHELL is not + defined + - the `q' and `x' modifiers are now compiled in by default, not + just if SHELL is defined + + 10/11 + ----- +subst.c + - string_quote_removal was being a little overzealous in stripping + things within embedded quoted strings when `quoted' was == 1. + Only remove one level of quotes each time through the function + This fixes the problem of quotes being stripped incorrectly in + var="The text \"hello\" should show up inside double quotes." + +lib/readline/history.c + - made the behavior of single quotes inhibiting history expansion + configurable with a variable: history_quotes_inhibit_expansion, + not just shell-specific + - added a new variable: history_search_delimiter_chars, which is a + list of characters that can also delimit a history search string + +lib/readline/history.h + - extern declaration of history_quotes_inhibit_expansion + - extern declaration of history_search_delimiter_chars + +bashhist.c + - set history_quotes_inhibit_expansion to 1 in bash_initialize_history + - initialize history_search_delimiter_chars to ";&()|<>" + +lib/readline/doc/{rltech,hstech}.texinfo + - documented new readline and history library interfaces + +parse.y + - split the part of read_token that reads a single word off into + a new function: read_token_word + +lib/readline/chardefs.h + - include by default; only check HAVE_STRING_H if + HAVE_CONFIG_H is defined + + 10/12 + ----- +parse.y + - moved the `RESET' code out of read_token into reset_parser + - rewrote some of decode_prompt_string to make it more efficient + - rewrote more of read_token_word to make it more efficient + - make shell_getc cast its result to `unsigned char' before + returning it. This fixes the problem of \255 appearing in a + line + +machines.h + - new entry for m68k machines running Linux + + 10/13 + ----- +builtins/exec.def + - use search_for_command rather than find_user_command to look up + the path to exec, so the hash table and temp environment are used + +variables.c + - don't rebuild the export environment after binding a shell + function unless that function is exported + - make sure that copy_variable copies arrays correctly, using + dup_array() + - in assign_in_env, only call tilde_expand if a `~' appears somewhere + in the value + +execute_cmd.c + - if we found $PATH in the temp environment in search_for_command, + call find_user_command_in_path instead of find_user_command, so + we don't try to search the temporary env again. Call + find_user_command as normal if PATH is not in the temp environment + +subst.c + - char_is_quoted should not be compiled in if READLINE is not + defined + +lib/readline/complete.c + - add a new external interface: Function *rl_char_is_quoted_p, + which is called to find out whether a word break character is + quoted and should be skipped over when breaking words for + the completer + +lib/readline/readline.h + - extern declaration for rl_char_is_quoted_p + +bashline.c + - initialize rl_char_is_quoted_p to char_is_quoted + +lib/readline/doc/rltech.texinfo + - documented rl_char_is_quoted_p + +lib/readline/readline.c + - extend the undo records so that a `start' or `end' value of -1 + means rl_point and a value of -2 means rl_end. This is a start + to better support for undoing vi-mode commands like `C' + +lib/readline/vi_mode.c + - don't save what's entered in insert mode after a `C' command + for later insertion when doing a `redo' + + 10/16 + ----- +test.c + - rewrote unop() to use a switch statement instead of a call to + strchr + - remove #ifdef SHELL blocks by defining getuid, geteuid, getgid + and getegid as references to current_user.{uid,euid,gid,egid} + respectively + - change group_member to only fetch the group list once and to use + NGROUPS_MAX or NGROUPS to find the maximum number of groups + +documentation/bash.1 + - fixed description of ${#@} expansion + + 10/17 + ----- +support/bashbug.sh + - add a `From:' line to the mail message handed to rmail + + 10/18 + ----- +test.c + - rewrote binary_operator for speed and clarity + - removed age_of, added arithcomp(), filecomp() to support new + binary_operator + - removed support for `-l string' + +documentation/bash.1 + - removed mention of `-l string' from `test' description + + 10/19 + ----- +cpp-Makefile + - pass PROGRAM as the double-quoted shell name to compilation of + shell.c and error.c + + 10/20 + ----- +support/bashbug.sh + - don't try to use ${word:-expansion}; ultrix sh doesn't understand it + +hash.c + - new function: flush_hash_table (table, free_data) to delete the + contents of a given hash table. *free_data is called to free + each item's data, if free() is inappropriate + +builtins/hash.def + - new functions free_hashed_filenames and free_filename_data to + flush the table of hashed filenames + +subst.c + - change sv_path to call flush_hashed_filenames directly + +variables.c + - only sort arrays of variables or functions for the environment or + `set' output if `posixly_correct' is set. sh does it; ksh does + not, and there's no real requirement to do so + - rewrote delete_all_variables so it looks like flush_hash_table + +trap.c + - two new flag values for the `sigmodes' array: SIG_INPROGRESS, + which is set for sigmodes[sig] while a trap handler for sig + is executing, and SIG_CHANGED, which is set if a new trap + value is set when SIG_INPROGRESS is set. This should obviate + the need to set the trap value to IMPOSSIBLE_TRAP_HANDLER while + the trap handler is executing + +alias.c + - rewrote delete_all_aliases so it looks like flush_hash_table + + 10/21 + ----- +alias.c + - changed delete_all_aliases to call flush_hash_table directly + and use free_alias_data as the `free function' argument + +variables.c + - changed delete_all_variables to call flush_hash_table directly + +tests/run-test, tests/test-tests + - new scripts to run tests of the `test' builtin as part of the + regression test + + 10/24 + ----- +bashline.c + - initialize_hostname_list needs to look for HOSTFILE first + - hostname list is no longer sorted + - replaced binary search in hostnames_matching with a simple + linear search + - made the code that reads hostnames skip over the first word on + a line only if its first character is a digit, assuming it's + an Internet address + +copy_cmd.c + - removed copy_select_command; overload copy_for_command, since the + select and for command structs are exactly the same + +make_cmd.c + - combined make_for_command and make_select_command into a new + function, make_for_or_select + - rewrote make_here_document to remove the unneeded `switch' statement + +builtins/common.c, builtins/hash.def + - moved remove_hashed_filename from common.c to hash.def + +builtins/common.c + - remove the \r from error message printed by get_working_directory + - change parse_and_execute to call dispose_fd_bitmap directly then + discard the `pe_dispose' unwind-protect frame rather than running + the frame + +builtins/set.def + - changed how set -o options are set and retrieved, using set and get + functions to avoid all that special-case inline code + + 10/26 + ----- +test.c + - added unary operator `-o', which returns true of the shell option + name given as an argument is set + +lib/readline/readline.c + - added a definition of set_lines_and_columns to be called if the + library is not compiled -DSHELL + +shell.c + - added a --verbose startup long option + - renamed `--nolineediting' to `--noediting' + + 10/27 + ----- +lib/readline/util.c + - new file, for readline utility functions + +lib/readline/readline.c + - moved a bunch of functions to util.c + +subst.c + - make sure set_sigint_handler is called only by the subshells doing + command and process substitution + +builtins/read.def + - make sure that rlbuf is initialized to null + +trap.c + - new flag for sigmodes[] members: SIG_IGNORED, set when signal is + ignored, even if it's special or untrappable + - new function: signal_is_ignored (sig), which returns 1 if SIG + has been ignored with trap '' + +builtins/trap.def + - changed to use the builtin getopt + +shell.c + - added a check to sigint_sighandler for whether or not SIGINT has + been ignored with trap '' in an interactive shell. This fixes + the problem with `read' being interruptible in an interactive + shell even if SIGINT is being ignored + + 11/8 + ---- +lib/readline/Makefile + - added definition of INSTALLED_HEADERS, just in case + + 11/11 + ----- +variables.c + - change assign_in_env so that it doesn't use savestring ("") to + set `value' to a dummy value; don't call strcpy if there's + nothing to copy + + 11/15 + ----- +general.h + - new defines, legal_variable_starter and legal_variable_char + - new define SIGRETURN(n) which encapsulates the VOID_SIGHANDLER + differences when returning from a signal handler + +general.c, variables.c, subst.c, expr.c + - use legal_variable_starter and legal_variable_char + +shell.c, nojobs.c, trap.c, jobs.c, builtins/suspend.def + - change to use SIGRETURN macro + +subst.c + - massive changes to clean up the code and remove unused code and + variables + - expanded the ${#param} code so that all of the shell special + variables may have their length taken + +tests/run-tilde + - new test for tilde expansion + +bashline.c + - fix a bug in command_subst_completion_matches: make sure that + `matches' is static + +parse.y + - don't print a prompt when not using readline if the current + input type is st_string + +machines.h + - add -DINT_GROUPS_ARRAY to SYSDEP_CFLAGS on ultrix + - fixes to the cray machine description from Bill Jones + +braces.c + - fixed a bug in brace_gobbler that prevented a backslash from + escaping an open brace + + 11/16 + ----- +tests/braces-tests, tests/run-braces + - new regression tests for brace expansion + +builtins/pushd.def + - new -p option for `dirs' that prints dirstack on per line + without numbers + + 11/17 + ----- +command.h + - move redirection error values here from execute_cmd.c + - new defines INPUT_REDIRECT and OUTPUT_REDIRECT + +shell.c + - make the default MAINTAINER `bash-maintainers@prep.ai.mit.edu' + +execute_cmd.c + - many changes to clean up the code and remove unused variables and + functions + - new functions: redirection_error, find_in_path_element, + find_absolute_program + - fixes to redirection error reporting, so things like exec 4<&y* + and exec 4<&$FOO are displayed correctly + - removed the `lexical_scoping' code + +flags.c, flags.h + - removed the lexical_scoping code and variable + +documentation/{bash.1,features.texi} + - removed the description of the `-l' option to `set' + +jobs.c + - don't try to open /dev/tty to get the controlling tty, use + fd 2 like other job control shells + +lib/readline/vi_mode.c + - when using `d%', make sure the matching character found by + the `%' is deleted by the `d'. Ditto for `c%'. + - stub function for vi undo: rl_vi_undo. Right now it just + calls rl_undo_command + +lib/readline/vi_keymap.c + - change to call rl_vi_undo instead of rl_undo_command + +lib/readline/readline.h + - extern declaration for rl_vi_undo + + 11/21 + ----- +execute_cmd.c + - fix to print_select_list to avoid a possible divide-by-zero error + and subsequent core dump + - fix to execute_select_command to just return 0 if there is no + select list + +parse.y + - remove `in' from the list of tokens that cannot take trailing + semicolons + +builtins/read.def + - make sure that leading IFS whitespace is removed before calling + get_word_from_string the first time. This matters when IFS is + not " \t\n" but non-null + - make sure the array code uses IFS to split the input string + before assigning it to the array + + 11/22 + ----- +parse.y + - make sure that if \nnn expands to CTLESC or CTLNUL, the char + is protected by a CTLESC + - new variable `promptvars', which, if non-zero, causes all the + variable expansions to be performed in decode_prompt_string. + If zero, only quote removal is performed. + +builtins/source.def + - new variable: `source_uses_path', set to 1 by default. If + non-zero, the `.' builtin uses $PATH to find the script to + source + +builtins/getopt.h + - cut out everything not needed by bash + +builtins/getopt.c + - cut out everything not needed by bash + +builtins/getopts.def + - removed the call to getopt_set_posix_option_order, which is no + longer necessary + +execute_cmd.c + - split the code that writes out here documents to files out into + a separate function + + 11/23 + ----- +builtins/getopt.c, builtins/getopt.h, builtins/getopts.def, subst.c + - prefix all of the getopt variables and functions with `sh_' + (that is, optind becomes sh_optind and getopt becomes sh_getopt) + to avoid confusion with a system's getopt(3) implementation + +subst.c + - new functions: parameter_brace_substring and verify_substring_values + and changes to expand_word_internal to support the ksh-93 + ${var:exp1:exp2} substring syntax + +documentation/bash.1 + - documented the new ${var:exp1[:exp2]} syntax + + 11/25 + ----- +builtins/setattr.def + - don't allow readonly -n at all + +array.c + - split array_to_string into two parts; a new function + array_to_string_internal does the real work + - new function array_subrange () to return a subset of the elements + in an array + +subst.c + - augmented the substring code to handle the positional parameters + and array variables + - made quote_list and dequote_list return their WORD_LIST * + arguments so they can be used like + + z = string_list ((quoted ? quote_list (l) : l), xxx); + + - augmented the ${xxx} expansion code to do indirect variable + references if the first character of the variable name is `!' + +tests/new-exp.tests + - added regression tests for substring expansion + - added regression tests for indirect variable references + + 11/28 + ----- +builtins/set.def + - added set -o hashfunc and set -o onecmd, synonyms for set -h + and set -t, respectively + +builtins/shift.def + - changed shift so that the positional parameters are not changed + if the argument is > $# (this is ksh and Posix.2, unlike sh) + +documentation/bash.1 + - documented true behavior of `shift' + +lib/readline/kill.c + - split the kill ring management code and the kill commands out + from readline.c into this file + +lib/readline/undo.c + - split the code that does undoing out of readline.c into this file + +shell.c + - force the shell to exit with status 127 if a longjmp back to + run_one_command occurs with bash -c + - force the last command exit status to 1 if a + longjmp (top_level, DISCARD) is performed + +builtins/read.def + - don't throw away partial lines after reading EOF + +subst.c + - command substitution should not inherit the -e flag + +builtins/source.def + - make sure to set the exit status correctly when in posix mode + and the filename argument to `.' does not exist + + 11/29 + ----- +lib/readline/input.c + - split the input buffering and character input code out of + readline.c to here + +lib/readline/macro.c + - moved the keyboard macro management code to here from readline.c + +lib/readline/readline.c + - removed the STATIC_MALLOC code + +lib/readline/rltty.c + - return -1 in POSIX get_tty_settings if tcgetattr returns -1 and + errno != EINTR, even if output is being flushed + + 12/1 + ---- +machines.h + - fixes to the hpux_8 and hpux_9 machine descriptions + +trap.c + - make run_exit_trap return the right exit status + (last_command_exit_value) + - run_exit_trap no longer preserves the value of last_command_exit_value + around the execution of the trap commands + - run_exit_trap now turns off SIG_TRAPPED and sets SIG_INPROGRESS + and will not try to run anything if SIG_INPROGRESS is set + +trap.h + - change definition for run_exit_trap + +shell.c + - call run_exit_trap only if trap[0] is set and not ignored + +builtins/exit.def + - make sure we only source the .bash_logout file once, even if it + contains a call to `exit' + +execute_cmd.c + - if we run an exit trap in a (...) user subshell, allow it to + override the exit status of the subshell + +lib/readline/readline.c + - made rl_delete_text bounds check its `to' argument, and limit + it at rl_end + +lib/readline/vi_mode.c + - make rl_vi_subst call `rl_delete_text' directly for the `s' + command + +support/mksysdefs + - define a new variable for the sysdefs.h file for ISC machines: + ISC_release, which can be ISC_2, ISC_3, or ISC_4 + +machines.h + - don't `#undef' HAVE_GETCWD on ISC 4.x machines + - `#undef' HAVE_RESOURCE on ISC 4.x machines + +support/mkversion.c + - include "posixstat.h" rather than for the benefit + of ISC machines + + 12/5 + ---- +lib/readline/complete.c + - changed username_completion_function so that a null username + generates a list of all users as possible completions + +lib/readline/readline.h + - added definitions for STREQ, STREQN + +lib/readline/{search.c,isearch.c,kill.c} + - removed private definitions of STREQ, STREQN + +execute_cmd.c + - in find_user_command_internal, just return a copy of the pathname + passed as an argument if there is no PATH + + 12/6 + ---- +siglist.h + - NetBSD 1.0 does not need a define for strsignal() + + 12/8 + ---- +subst.c + - removed assignment_name, word_list_quote_removal, word_quote_removal, + and sub_append_number -- unused functions + - removed some unexecuted code from expand_word_internal + + 12/9 + ---- +execute_cmd.c + - if PATH is set to the empty string, find executables in the + current directory + +shell.c, parse.y, trap.c + - before setting the SIGINT sighandler unconditionally to one of + sigint_sighandler or termination_unwind_protect, check that it + is not ignored. Now trap '' 2 really sets the SIGINT signal + handler to SIG_IGN. [In 1.14.3] + +trap.c + - rewrote set_sigint_handler to use SIG_IGNORED rather than checking + against IGNORE_SIG + - changed ignore_signal, run_exit_trap, maybe_call_trap_handler, and + run_trap_internal to check SIG_IGNORED + +shell.c + - removed the check for signal_is_ignored(SIGINT) in sigint_sighandler + + 12/11 + ----- +sig.c, sig.h + - new files, moved signal-related definitions and code here from + shell.c, general.h, general.c, jobs.c, jobs.h, externs.h + +unwind_prot.c, shell.h, nojobs.c + - include sig.h + + 12/12 + ----- +jobs.c + - only break out of loops if SIGTSTP was used to stop a job in the + loop, the shell is currently interactive, and job control is on. + SIGSTOP does not break loops. [In 1.14.3] + + 12/13 + ----- +expr.c + - bases < 2 or > 36 are now accepted without silently being reset + to 10 + +braces.c + - make sure array_concat copies the array it returns if one of + the arguments is null [In 1.14.3] + + 12/14 + ----- +subst.c + - split the ${...} expansion code out into a separate function, + static char *parameter_brace_expand() + - changes to array_value so that any variable can be referred to + as an array with an integer subscript. The value will be + returned if a non-array variable is referred to as ${var[0]}; + if the subscript is > 0 a null string is returned + + 12/15 + ----- +machines.h + - fixes to freebsd description for FreeBSD 2 [In 1.14.3] + +support/bashbug.sh + - changed to use /usr/lib/sendmail if present or /usr/sbin/sendmail + if present, defaulting to rmail [In 1.14.3] + +bashhist.c + - HISTFILESIZE now controls how large the history file is after + it is written. After saving the shell history, sv_histfilesize + will truncate it if necessary. history -w can override this. + +documentation/bash.1 + - documented change to treatment of HISTSIZE when saving history + +lib/malloc/malloc.c + - removed the calls to sigsetmask() in malloc(). This should + result in a speed improvement + + 12/19 + ----- +builtins/enable.def + - don't allow -f or -d in a restricted shell + +builtins/alias.def + - rewrote alias and unalias to use the internal getopt + - added -p option to print the alias list to alias + - fixed up the documentation for `alias' + +documentation/{bash.1,features.texi} + - updated the documentation for `alias' + - updated the documentation for $_ + +array.c,array.h + - new function `empty_array (ARRAY *a)' removes all of the + elements in a without destroying the array variable in + preparation for overwriting it. Used by read -a. + +builtins/read.def + - call empty_array() before assigning list of values with read -a + - changed dispose_array to use empty_array to destroy the + array elements + +variables.c + - set $_ to argv[0] at variable initialization time + + 12/20 + ----- +subst.c + - broke the pattern removal code into a few separate functions: + getpatspec to get the pattern specifier, getpattern to do the + necessary word expansions and return the pattern to be matched + - new function: parameter_list_remove_pattern(), which implements + the ${param[#%][[%#]]pattern} where param is `@' or `*' + +documentation/bash.1 + - documented new pattern removal functionality for the positional + paramters + +general.c + - new function strsub (s, pat, rep, gflag) replaces PAT with REP + in S. All occurrences are replaced if GFLAG != 0; the first is + replaced otherwise + - changed strindex() to avoid multiple calls to strnicmp by + checking first character of the string + +builtins/fc.def + - changed to use builtin_getopt with a check for fc numbers as + arguments + - some code rearranging for efficiency and clarity + - fc_dosubs now just calls strsub(); fc_replace is gone + + 12/21 + ----- +subst.c + - new function, match_pattern, which matches a shell globbing + pattern anywhere in a string and returns the boundaries of the + match + +lib/readline/readline.h + - declarations for rl_insert_command and rl_backward_char_search + +lib/readline/readline.c + - new function rl_insert_comment, no longer vi-mode-specific + - new function rl_backward_char_search + +lib/readline/bind.c + - comment-begin now sets the comment char for emacs and vi modes + - variable holding the value is now _rl_comment_begin + +lib/readline/vi_mode.c + - move the `comment-begin' stuff to readline.c and bind.c + +lib/readline/funmap.c + - vi-comment is now insert-comment + - new bindable command character-search-backward + +lib/readline/vi_mode.c + - command mode `#' now invokes rl_insert_comment + +lib/readline/emacs_keymap.c + - M-# now bound to insert-comment + - M-space now bound to set-mark + - M-^] now bound to character-search-backward + +bashline.c + - posix_readline_initialize now calls rl_variable_bind to set the + value of comment-begin rather than directly modifying + _rl_comment_begin + +documentation/{bash.1,readline.3}, lib/readline/doc/rluser.texinfo + - added description of new bindable `insert-comment' command + - documented new M-space emacs mode binding + - documented new character-search-backward command and default + emacs mode binding to M-C-] + +shell.c + - only call posix_initialize if posixly_correct is set + + 12/22 + ----- +cpp-Makefile + - make $(Program) depend on $(srcdir)/.distribution, for the + benefit of systems where `make' does not have VPATH support + [In 1.14.3] + +jobs.c + - if a foreground job is killed by SIGINT while job control is + active, print a newline to compensate for the kernel printing + ^C without one [in 1.14.3] + +bashline.c + - make sure bashline_reinitialize resets rl_completion_entry_function + to NULL, as the comment says it should [In 1.14.3] + + 12/23 + ----- +test.c + - fix a problem that caused core dumps if a `)' was missing in a + parenthesized expression [In 1.14.3] + +jobs.c + - broke the code the manages the manipulation of the job table and + process status out of flush_child into a new function waitchld() + - flush_child now just calls waitchld() with a parameter that tells + it not to block + - wait_for calls waitchld() with the pid it's looking for and tells + it to block (don't call it with WNOHANG) + - cleaned up wait_for considerably -- turned the wait_loop: label + stuff into a do-while loop and removed the setting of job status + (that's now done only by waitchld). wait_for now calls + waitchld continuously until the job it is interested in is + marked JDEAD. + + 12/28 + ----- +subst.c + - fixed expand_word_internal so that any word that expands into + nothing and contains a double-quoted $@ is removed, like sh + and ksh + - new function: expand_string_for_rhs, which calls expand_word_internal + with a variable that lets it find out whether or not a $@ appeared + in the WORD in ${paramOPword} when expanding it, so that "$@" + and various other things are handled correctly on the rhs + - added params for parameter_brace_expand to tell expand_word_internal + if a quoted $@ was processed as part of the rhs (or even the lhs); + these new params are passed along to parameter_brace_expand_rhs + - pass the right value of quoted to parameter_brace_expand_rhs from + parameter_brace_expand. expand_string_for_rhs doesn't need to know + whether the brace expression is quoted + + 12/31 + ----- +support/printenv + - now an official part of the distribution, moved from CWRU/misc + [in 1.14.3] + +cpp-Makefile + - copy support/printenv into the `tests' directory when making tests + [in 1.14.3] + - change to understand GCC_STANDARD [in 1.14.3] + +support/bashbug.sh + - fixed a typo that caused it to not parse correctly [in 1.14.3] + +machines.h + - define GCC_STANDARD if the standard `cc' is gcc and you don't want + to use the compiler named `gcc' for some reason [in 1.14.3] + + 1/2 + --- +general.h + - added FS_DIRECTORY to the list of flags that file_status returns + +execute_cmd.c + - changed find_in_path_element to return null if the flags argument + specifies FS_EXEC_ONLY and the file is not executable + - return FS_DIRECTORY from file_status if the argument specifies a + directory + - new function, is_directory (char *), which returns non-zero if the + filename argument is a directory + +execute_cmd.h + - extern declaration for is_directory + +flags.c, flags.h + - hashing_disabled and locate_commands_in_functions were removed, + hashing_enabled added + +execute_cmd.c, builtins/common.c. builtins/hash.def + - use hashing_enabled instead of hashing_disabled, and reverse + the sense of tests of it + +documentation/bash.1, documentation/features.texi + - changed description of `set -h/set -o hashcmds', removed + set -d/set -o nohash + +bashline.c + - changed command_word_completion_function to return matches if names + are directories as well as if they are executable files + +support/mksysdefs + - look for `ranlib' in $PATH before searching the file system; + look in /usr/gnu/bin for it; default to `:' if not found + +general.c + - change ansicstr to accept a second argument telling it whether to + recognize \c and to pass back a non-zero value in it if \c is + seen + +general.h + - changed extern declaration of ansicstr + +subst.c + - call ansicstr with an extra argument + + 1/3 + --- +builtins/echo.def + - rewrote to use ansicstr() with the new argument + + 1/4 + --- +trap.c + - changed instances of signal() to set_signal_handler() [in 1.14.4] + - combined reset_signals and restore_signals into a single function, + since they were essentially identical + +subst.c + - if set -u is set, references to the positional parameters now + generate errors if that parameter is not set [in 1.14.4] + +lib/*/Makefile, builtins/Makefile + - since RANLIB can be just `ranlib', just try to run it without + checking that the file exists [in 1.14.4] + +builtins/set.def + - changed `hashcmds' to `hashall' + +documentation/{bash.1,features.texi} + - changed `hashcmds' to `hashall' + + 1/5 + --- +trap.c + - make the loop that restores signal handlers run from signal 0 to + make sure user subshells don't inherit traps on `exit' (to fix + for 1.14.3, change restore_original_signals so that the loop + starts from 0) [in 1.14.4] + +variables.c + - don't import exported function definitions at startup if the + shell is restricted + +builtins/source.def + - don't allow use of pathname arguments containing `/' in a + restricted shell + +execute_cmd.c + - when a shell is spawned to execute a shell script without a + #! line, turn off the -r flag if the shell is restricted + +shell.c + - added a new long option `--restricted' + +documentation/bash.1 + - added a section on the restricted shell, and documented the + new `--restricted' long invocation option + + 1/7 + --- +shell.c + - when using bash -c command, make run_one_command return + last_command_exit_value if a throw_to_top_level with value + EXITPROG occurs [in 1.14.4] + +print_cmd.c + - make sure to initialize arg_index in the non-varargs implementation + of cprintf [in 1.14.4] + +jobs.c + - don't try to change the state of the SIGCHLD handler before + calling waitchld() from wait_for, since SIGCHLD is blocked + while this code is executing [in 1.14.4] + + 1/11 + ---- +lib/readline/rltty.c + - call control_keypad iff the value of a new variable, + _rl_enable_keypad, is non-zero + +lib/readline/bind.c + - new readline variable `enable-keypad' to control whether readline + tries to manipulate the application keypad + +documentation/{bash.1,readline.3}, lib/readline/doc/rluser.texinfo + - documented new `enable-keypad' variable + + 1/12 + ---- +lib/readline/search.c + - make sure to call rl_unix_word_rubout and rl_unix_line_discard + with the correct arguments [in 1.14.4] + +make_cmd.h + - make sure make_select_command is declared even if SELECT_COMMAND + is not defined + +parse.y + - make sure the \[ and \] escape sequences are not recognized if + READLINE is not defined [in 1.14.4] + +config.h + - make sure HISTORY is defined if READLINE is; code moved here + from bashhist.c [in 1.14.4] + +bashhist.c + - removed check for READLINE being defined without HISTORY; now + in config.h + - new function, bash_history_reinit + +flags.h, flags.c, builtins/set.def + - the -H/-o histexpand flag should be compiled into the shell + only if BANG_HISTORY is defined [in 1.14.4] + +subst.c + - don't include sv_histchars unless BANG_HISTORY is defined + [in 1.14.4] + - if QUOTED is true in parameter_brace_expand_rhs, pre-process the + word on the rhs of the parameter expansion by a call to + string_extract_double_quoted with the STRIPDQ parameter set to 1 + - new arg for string_extract_double_quoted; causes it to strip + double quotes and alter its backslash handling behavior; designed + to be called from parameter_brace_expand_rhs + - changed all other instances of string_extract_double_quoted to + call it with STRIPDQ set to 0, to get old behavior + +shell.c + - call bash_history_reinit rather than manipulating history + variables directly + +variables.c + - don't auto-export $BASH [in 1.14.4] + +tests/rhs-exp.tests + - new test script to check for behavior fixed by changes to + string_extract_double_quoted and parameter_brace_expand_rhs + +parse.y + - `for' and `select' must now take non-empty lists between + `in' and `;' + + 1/16 + ---- +subst.c + - fixed string_quote_removal to do double-quoted string processing + itself rather than call string_extract_double_quoted, which + assumes that a call to expand_word_internal or the equivalent + will follow immediately and leaves some backslashes in place, + inappropriately for quote removal + + 1/23 + ---- +subst.c + - make sure to set `temp' to NULL after it's freed by sub_append_string + in expand_word_internal to keep it from pointing to newly-allocated + memory that will be subsequently freed, causing a `memory freed + twice' error [in 1.14.4] + +trap.c + - handle the EXIT_TRAP specially in reset_or_restore_signal_handlers, + since in both cases we simply want to free up the trap string and + mark the signal as not trapped + +shell.h + - added \n to the list of characters in slashify_in_double_quotes + + 1/26 + ---- +subst.c + - make string_extract_single_quoted and string_extract_double_quoted + `inline' + - new function skip_single_quoted, used when we used to call + string_extract_single_quoted and just throw the returned string + away + - new function skip_double_quoted for the same purpose + + 1/28 + ---- +subst.c + - fixed expand_word_internal so that if an assignment word + is expanded, no word splitting is performed [in 1.14.4] + +builtins/ulimit.def + - some systems lack RLIMIT_CPU; so `#ifdef' its use [in 1.14.4] + - some versions of cpp expand parameters like \n if `n' is an + argument to the macro; change `n' to `num' in the definition + of print_rlimtype to compensate [in 1.14.4] + +builtins/read.def + - make sure the read loop sets `saw_escape' to note that an + escape character was read if CTLESC or CTLNUL is read [in 1.14.4] + +shell.c, sig.c + - only test interactive_shell before calling maybe_save_shell_history + [in 1.14.4] +shell.c + - include if HAVE_LOCALE_H is defined + - call setlocale(LC_ALL, "") at the beginning of main() if + either _POSIX_VERSION or HAVE_SETLOCALE is defined + +support/mksysdefs + - look for , define HAVE_LOCALE_H if found + +cpp-Makefile + - pass HAVE_LOCALE_H through from sysdefs.h to the build process + +bashhist.c + - remove test against interactive_shell in maybe_save_shell_history + [in 1.14.4] + +variables.c + - moved definition of DEFAULT_MAIL_PATH to config.h + +config.h, config.h.mini + - now has definition of DEFAULT_MAIL_PATH [in 1.14.4] + - changed default value of PATH to + `/usr/gnu/bin:/usr/local/bin:/usr/ucb:/bin:/usr/bin:.' + [in 1.14.4] + +documentation/bash.1 + - updated the example of the default path in the description of + the PATH variable + +lib/readline/readline.c + - set up a table of `legal' LC_CTYPE values and match the value of + $LC_CTYPE against it when deciding whether or not to default to + eight-bit input and output + - check for LC_ALL, LC_CTYPE, and LANG, in that order, for names to + check against the legal_lc_ctype_values table + +lib/readline/bind.c + - moved strindex, stricmp, and strnicmp to lib/readline/util.c, + added _rl_ prefix to names + - some miscellaneous code cleanups and speedups + +lib/readline/rldefs.h + - define _POSIX_VDISABLE as _SVR4_VDISABLE if there is a define + for the latter and not the former [in 1.14.4] + - moved defining _rl_stricmp and _rl_strnicmp as strcasecmp and + strncasecmp, respectively, here from bind.c, since the functions + are now defined in util.c and used in two files + +builtins/common.c + - removed the \n case in double_quote, so a backslash is not added + before an existing newline. The \ pair is removed by + the parser before anything else in the shell gets hold of it + except within single quotes [in 1.14.4] + + 1/30 + ---- +general.c + - make sure the string index in canonicalize_pathname never goes + < 0 (it can, in some cases, result in `start' being -1, and `i' + being set to that) [in 1.14.4] + + 2/1 + --- +execute_cmd.c + - fix a typo in a call to `access' in AFS-specific code [in 1.14.4] + + 2/3 + --- +builtins/shopt.def + - finally added new `shopt' builtin + +builtins/umask.def + - converted to use builtin_getopt + +bashhist.c + - support for storing literal newlines in the history list when + command_oriented_history is enabled, rather than using semicolons + +builtins/Makefile + - changed rule to make a .o file from a .def file to remove the + .c file if the compilation fails + + 2/6 + --- +bashhist.c + - added new variable `force_append_history' that will force the + history list to be appended to the history file at shell exit + - new function, maybe_append_history, to append any history lines + from the current session to the history file. Used by history -a + +builtins/bind.def + - changed the `-d' option to -p + +builtins/set.def + - added `allenv' as a -o synonym for `set -k'. Now all of the + single-letter shell options have -o equivalents + +builtins/shopt.def + - added -p option to display shell options, like other builtins + - added `interactive_comments' as a shell option, like set -o + +builtins/bind.def, builtins/history.def, builtins/enable.def + - changed use of multiple variables to hold option flag settings to + one variable with bits representing flag values + +documentation/bash.1, documentation/features.texi + - changed the description of the `bind' builtin for the new -p option + - changed the description of the `set' builtin for the new + `-o allenv' option + - updated the description of the `shopt' builtin + +builtins/history.def + - changed -a option to use maybe_append_history + +subst.c + - changed the substring/subarray code to make negative offsets + count backwards from the end of the string or array + +builtins/bashgetopt.c + - added option modifiers `;' (argument is optional) and `#' + (argument is optional, but if present must be numeric) + +builtins/hash.def + - converted to use builtin_getopt + - broke code out into a new function: add_hashed_command + + 2/7 + --- +builtins/getopt.c + - changed to save state to avoid relying on `nextchar' staying the + same across calls to sh_getopt [in 1.14.4] + - added a function to restore `nextchar' from this saved state + [in 1.14.4] + - removed some dead code + +builtins/getopts.def + - call function to restore sh_getopt state when parsing explicitly + supplied arguments rather than the positional parameters [in 1.14.4] + +lib/readline/vi_mode.c + - fixed an off-by-one error in _rl_vi_done_inserting that put the + \0 in vi_insert_buf at offset `len' instead of `len - 1' + +lib/readline/complete.c + - print_filename now filters out control characters and displays + them in printable format, rather than relying on the tty driver + to do the right thing [in 1.14.4] + + 2/8 + --- +lib/posixheaders/stdc.h + - test for each special keyword being defined individually, rather + than just testing on `const' [in 1.14.4] + +lib/readline/util.c + - new function _rl_abort_internal; rl_abort just calls this + +nojobs.c + - include error.h for extern function definitions [in 1.14.4] + +builtins/ulimit.def + - include if HAVE_UNISTD_H is defined + - use HAVE_LIMITS_H to decide whether or not to include + +variables.c, subst.c, builtins/set.def + - removed special handling of `noclobber' variable + +builtins/set.def + - new function set_shellopts to set up the $SHELLOPTS variable + based on the values of the set -o options; `set' calls this + function whenever one of the options is changed + - new function parse_shellopts to take the value of SHELLOPTS and + turn on each option found therein + - new function initialize_shell_options to parse any inherited + value of $SHELLOPTS and set up $SHELLOPTS + +shell.c + - call initialize_shell_options at the end of shell_initialize() + +execute_cmd.c, general.c + - moved extract_colon_unit from execute_cmd.c to general.c + +execute_cmd.h, general.h + - moved extern declaration of extract_colon_unit from + execute_cmd.h to general.h + +documentation/{bash.1,features.texi} + - documented SHELLOPTS + + 2/18 + ---- +builtins/{shopt,pushd,jobs,umask}.def + - removed the `longjobs', `longdirs', `pushd_home' and `symbolic_umask' + options + +lib/readline/{histexpand,histsearch,histfile}.c, lib/readline/histlib.h + - new files, split off from old history library history.c + +lib/readline/history.c, lib/readline/history.h + - new function clear_history() to clear the history list + +lib/readline/doc/hstech.texinfo + - documented clear_history () + +builtins/pushd.def + - new function clear_directory_stack() to delete all elements of + the dir stack + - new -c option for `dirs' to clear directory stack + - new function get_dirstack_index for dirs -N and dirs +N to use + - new function get_dirstack_element(i, dir) for use by other parts of + the shell that want the functionality of dirs -N and dirs +N + (dir is 1 for dirs +N, -1 for dirs -N) + - new function set_dirstack_element(i, dir, val) for use by other + parts of the shell to change values in the dirstack (dir is -1 + for dirs -N, +1 for dirs +N). Used when assigning to $DIRSTACK. + +builtins/history.def + - new -c option to clear the history list + +documentation/bash.1, documentation/features.texi + - removed no-longer-valid shopt options + - documented new dirs -c option + - documented new history -c option + - documented new \T and \H prompt escape sequences + - documented new $DIRSTACK dynamic array variable + - documented the new expand-glob and list-glob readline commands + +variables.c + - set PS4 to its default value of `+ ', so that unsetting it will + disable the tracing characters [in 1.14.4] + - new framework for dynamic array variables -- each place an + array index is assigned to, a test is made. if a dynamic + assignment function exists, it is called with args `self', + the index being assigned to, and the new value + - new variable `$DIRSTACK', a dynamic array variable that holds + the current contents of the directory stack. You can even + change the stack by assigning to thie variable + +shell.c + - changed indirection_level_string to return the null string if + $PS4 is unset or null [in 1.14.4] + +parse.y + - new \H prompt escape for hostname up to first `.'; changed \h + to return full hostname (like \w/\W) + - new \T prompt escape for 12-hour time + +bashline.c + - new readline functions to expand glob patterns and insert or + list the expansions (special completion functions) + + + 2/20 + ---- +builtins/pushd.def + - new code for `pushd -n' and `popd -n' to inhibit cd when + adding or removing directories from the stack + - broke functionality off into separate functions for use by the + $DIRSTACK manipulation functions + + 2/21 + ---- +lib/readline/kill.c + - new functions to copy words to the kill ring, backward or + forward + +lib/readline/readline.h + - extern declarations for rl_copy_{backward,forward}_word + + +lib/readline/funmap.c + - new bindable readline commands: copy-backward-word and + copy-forward-word to copy portions of the line to the kill + ring without deleting them + +documentation/{bash.1,readline.3}, lib/readline/doc/hsuser.texinfo + - documented the new copy-backward-word and copy-forward-word + readline commands + +mailcheck.c, config.h + - the declaration of DEFAULT_MAIL_PATH is now only in config.h + and used by mailcheck.c and variables.c. There is no need to + use DEFAULT_MAIL_PATH_LEN; `sizeof' does the job [in 1.14.4] + + 2/22 + ---- +support/mksysdefs + - changes to fix `RELEASE' if it ends up being set to the empty string + [in 1.14.4] + - check for amdahl UTS [in 1.14.4] + - check for SGI Irix version 6.x [in 1.14.4] + +machines.h + - new entry for Amdahl UTS [in 1.14.4] + - changes to the SGI entry for Irix 6.x [in 1.14.4] + + 2/23 + ---- +machines.h + - changes for BSD/OS 2.0 (M_OS now set to `BSD_OS') [in 1.14.4] + +support/mksysdefs + - change to recognize BSD/OS 2.0 and set SYSDEF to BSDI2 [in 1.14.4] + +siglist.h + - don't declare sys_siglist on BSD/OS 2.0 [in 1.14.4] + + 2/24 + ---- +parse.y + - if reset_parser is called while the prompt command is being + executed because of a syntax error in $PROMPT_COMMAND, an + infinite loop results. set token_to_read back to 0 at the + end of execute_prompt_command to stop the looping [in 1.14.4] + + 2/25 + ---- +mailcheck.h + - new header file for mail-checking and related definitions + - declaration of DEFAULT_MAIL_PATH is now here + +mailcheck.c + - new function, make_default_mailpath, which constructs a default + $MAILPATH string from DEFAULT_MAIL_PATH [in 1.14.4] + - change remember_mail_dates to call make_default_mailpath + [in 1.14.4] + +externs.h + - moved function declarations for functions in mailcheck.c to + mailcheck.h + +variables.c + - change initialize_shell_variables to call make_default_mailpath + [in 1.14.4] + - removed some unneeded variables in initialize_shell_variables + + 2/26 + ---- +lib/readline/callback.c + - new file with readline callback function interface + +lib/readline/rlconf.h + - new READLINE_CALLBACKS define for the readline callback code to + be compiled in and available + +lib/readline/readline.c + - broke readline_internal into three functions: readline_internal_setup, + readline_internal_charloop, and readline_internal_teardown + - changes for READLINE_CALLBACKS + +lib/readline/readline.h + - extern declarations for the readline callback code + +cpp-Makefile + - added lib/readline/callback.c to the list of readline files + +lib/readline/input.c + - added a layer of indirection to allow the user to specify the + function that reads a character from rl_instream. The variable + name is rl_getc_function, set by default to rl_getc + + 2/27 + ---- +lib/readline/display.c + - added a variable rl_redisplay_function to allow an application- + specified redisplay function, for those apps that want to control + redisplay + +lib/readline/readline.c + - extern declarations for rl_getc_function and rl_redisplay_function + +lib/readline/{readline,display,isearch,search,parens}.c + - changed to call through rl_redisplay_function rather than + rl_redisplay directly + +parse.y + - try to avoid some work in reset_readline_prompt and prompt_again + if the prompt is the empty or null string [in 1.14.4] + +lib/readline/readline.c + - call rl_expand_prompt unconditionally [in 1.14.4] + +lib/readline/display.c + - short-circuit out of rl_expand_prompt if the prompt string is null + after clearing out the saved local prompt values. This allows + $PS2 to be set to "" [in 1.14.4] + +lib/readline/doc/rltech.texinfo + - documented the callback code and functions + - documented rl_getc_function and rl_redisplay_function + +lib/readline/{callback,readline,rltty,signals}.c + - added layer of indirction for terminal prep and deprep, with + rl_term_prep_function and rl_term_deprep_function. These are + set by default to rl_prep_terminal and rl_deprep_terminal, + respectively + +lib/readline/readline.h + - make rl_term_prep_function and rl_term_deprep_function available + to callers + + 3/1 + --- +lib/readline/complete.c + - broke the (long, complicated) rl_complete_internal code into a + number of separate functions: + + find_completion_word + gen_completion_matches + remove_duplicate_matches + display_matches + insert_text + insert_match + append_to_match + insert_all_matches + + - made some efficiency improvments to filename_completion_function + - the completion ignore function is now called no matter what type + of completion is being performed (as it should have been all along) + +lib/readline/rldefs.h + - use #defines for the possible values ORed into `found_quote' by + the completion code + + 3/2 + --- +make_cmd.c, general.c + - moved make_word_array from make_cmd.c to general.c, renamed to + word_list_to_argv, extended it to optionally not malloc all of + the strings and to reserve space at the start of the array + +execute_cmd.c + - changed to use word_list_to_argv, not mallocing space for the + strings + +builtins/common.c, builtins/common.h + - new function make_builtin_argv, which uses word_list_to_argv + and reserves 1 slot at the beginning for the command name + +builtins/exec.def + - changed to use word_list_to_argv + +builtins/{getopts,test}.def + - changed to use make_builtin_argv + +subst.c + - new function match_pattern_char, to see if the first char of + a string has a chance to match a given pattern (test against + the first char of the pattern); used by match_pattern in the + MATCH_ANY case + + 3/3 + --- +jobs.c + - renamed flush_child to sigchld to capture the functionality better + +array.c + - new function array_pat_subst, to do pattern substitution on each + element in an array + +array.h + - extern declaration for array_pat_subst + +subst.c + - new function pat_subst to do pattern matching and substitution on + a string + - new function parameter_brace_pat_subst to implement + ${v/[/]pat[/sub]}; calls pat_subst for simple vars, + pos_params_pat_subst to do substitution on the positional params, + and array_pat_subst for things like ${v[@]/p/r} + +subst.h + - extern declaration for pat_subst so array.c can find it + + 3/6 + --- +parse.y + - <>filename now dups filename to file descriptor 0 for both input + and output even when not in posix.2 mode + +bashline.c + - add the globbing characters to the list of characters that need + to be quoted by filename completion + +jobs.h + - new convenience macros: + RUNNING, STOPPED, DEADJOB - to test a job's state + IS_FOREGROUND, IS_NOTIFIED, IS_JOBCONTROL - flags + +jobs.c, builtins/{kill,fg_bg}.def + - changed to use new jobs.h macros + + 3/7 + --- +array.c, array.h + - new function dup_array_subrange(a, s, e) to make a new array + out of the elements of array A between S and E, inclusive + - add `quoted' parameters to array_subrange and array_pat_subst + to preserve proper quoting of elements when expanding things + like "${av[@]/xx/yy}" + - new function array_quote to quote the members of an array like + the functions in subst.c + +subst.c + - pass the quoted flag to array_subrange and array_pat_subst + - quote_string is no longer static + +subst.h + - extern declaration for quote_string + +builtins/hash.def + - added a -p pathname option to specify a pathname for the command + name to be hashed. With -p, no path search is performed. + +lib/readline/histexpand.c + - broke history_tokenize off into history_tokenize_internal and + added two arguments: a character index and a word index. If + the char index is >= 0, the word index will be modified to point + into the returned array of strings to the word surrounding that + particular character index + - new function history_find_word(line, ind) to return the word + containing the character at index IND in LINE + - new variable search_match, found by history_find_word, to hold the + word last matched by a !?string? search + - corrected a problem with the `%' modifier: it should insert the + word last matched, not the last search string + + 3/8 + --- +cpp-Makefile + - changed INSTALL_PROGRAM and INSTALL_DATA to use support/install.sh + - changed `install' target to not explicitly save the old version of + bash in `bash.old'; let install take care of it + +shell.c + - new static variable `running_under_emacs', set to 1 if the + variable `EMACS' is in the startup environment, and to 2 if + we're running under the `eterm' terminal emulator + - send an escape sequence to eterm if running_under_emacs is 2 + after executing any $PROMPT_COMMAND to tell it the current + directory + + 3/9 + --- +builtins/ulimit.def + - made getting -u work for systems that have a MAXUPRC define. + it still cannot be set without RLIMIT_NPROC + +shell.c + - include trap.h for sig definitions + +builtins/common.h, subst.h, general.h, externs.h + - more extern function declarations + +bashhist.c + - new function, bash_history_disable(), to turn off history and + history expansion + - bash_history_disable now sets history_expansion_inhibited + +bashline.h + - new file with extern declarations from bashline.c + +parse.y, bashhist.c, builtins/bind.def, subst.c, sig.c + - include bashline.h + + 3/10 + ---- +lib/glob/glob.h + - new file with extern declarations for local glob library + +shell.c + - include glob.h, mailcheck.h + +cpp-Makefile + - changes to dependencies due to mailcheck.h, bashline.h, glob.h + + 3/13 + ---- +execute_cmd.c + - new function execute_connection to execute commands of type + cm_connection + - new function execute_pipeline, to execute pipelines + +lib/readline/rltty.c + - add a `tty' argument to the set_winsize function/macro, the + non-shell version needs it + + 3/14 + ---- +parse.y + - added \a (bell) and \e (escape) prompt string escape sequences + + 3/16 + ---- +lib/readline/display.c + - fixed bug in update_line that caused stray characters to be left on + lines after the first if characters are deleted so that the first + line becomes exactly as long as the screen width [in 1.14.4] + +lib/readline/doc-support + - brought in the GNU getopt because texindex needs it + +documentation/Makefile + - adopted the BSD convention of a suffix of `.0' for formatted + manual pages + + 3/17 + ---- +support/inpath + - a script to find out if a particular command name appears in + a directory in $PATH [in 1.14.4] + +support/mksysdefs + - changed to use inpath to find `ranlib' [in 1.14.4] + + 3/18 + ---- +bashline.c + - include bashline.h + - removed the DYNAMIC_HISTORY_COMPLETION define; that code is now + included unconditionally + - renamed ETCHOSTS to DEFAULT_HOSTS_FILE; moved definition to + bashline.h + - moved definition of BRACE_COMPLETION to config.h + +config.h + - conditional definition of BRACE_COMPLETION is now here + +pathnames.h + - new file with defines that are absolute pathnames + +shell.h + - include pathnames.h + +mailcheck.h + - def of DEFAULT_MAIL_PATH now moved to pathnames.h + +shell.c + - def of SYS_PROFILE moved to pathnames.h + +alias.h + - removed a bunch of extra definitions + +lib/readline/{vi_mode.c,bind.c} + - removed superfluous STATIC_MALLOC code + +variables.c + - removed SHADOWED_ENV code + + 3/20 + ---- +machines.h + - don't define USG or USGr3 for linux machines [in 1.14.4] + - change REVERSED_SETVBUF_ARGS to SETVBUF_REVERSED for autoconf + compatibility + +shell.c + - change REVERSED_SETVBUF_ARGS to SETVBUF_REVERSED for autoconf + compatibility + +support/mksysdefs, maxpath.h + - change HAVE_SYS_PARAM to HAVE_SYS_PARAM_H for autoconf + compatibility + +support/mksysdefs, jobs.h + - use HAVE_SYS_WAIT_H + +machines.h, error.c + - change HAVE_VFPRINTF to HAVE_VPRINTF for autoconf compatibility + +test.c + - replace UID_T and GID_T with GETGROUPS_T, the size of the elements + of the array returned by getgroups + +general.c + - define HAVE_KILLPG if killpg() is present; compile in a replacement + killpg if not + +machines.h, jobs.c + - change BSD_GETPGRP to HAVE_BSD_PGRP + +sig.c + - don't call initialize_siglist if HAVE_SYS_SIGLIST is defined, no + longer use INITIALIZE_SIGLIST + +machines.h, lib/malloc/malloc.c + - change NO_SBRK_DECL to SBRK_DECLARED + + 3/22 + ---- +machines.h + - BSD/OS 2.0 does not need INT_GROUPS_ARRAY in SYSDEP_CFLAGS + +lib/readline/rldefs.h + - don't check `Linux'; just include if HAVE_TERMCAP_H + is defined + +builtins/command.def + - changed get_standard_path to use HAVE_CONFSTR + +execute_cmd.c + - execute_simple_command no longer uses alloca + - don't check RISC6000 anymore when deciding whether to use + #pragma alloca + +execute_cmd.c, shell.c + - check for ultrix instead of Ultrix when calling alloca(0) + +jobs.h + - check HAVE_UNISTD_H to see whether to declare fork, getpid, + and getpgrp + +builtins/common.c + - include for NSIG + +sig.h + - don't define SIGABRT as SIGIOT unless SIGIOT is defined + +jobs.c + - check for ultrix instead of Ultrix + + 3/23 + ---- +general.c, general.h + - new function check_dev_tty, which makes sure we can open + /dev/tty + +shell.c + - call check_dev_tty instead of having the code inline + +posixstat.h + - removed references to isc386 + +general.h + - code to define one of TERMIOS_TTY_DRIVER, TERMIO_TTY_DRIVER, + or NEW_TTY_DRIVER + +jobs.c, nojobs.c + - use the general.h code to define the tty driver types + + 3/24 + ---- +builtins/declare.def + - new -p option to display variables and their values and attributes + `declare -p xxx' displays attribs and value of var `xxx' + +builtins/setattr.def + - new function to display the attributes and value of a particular + variable; used by set_or_show_attributes + - new function to look up a variable by name and show that name's + attributes and value + +builtins/common.c + - declarations for new functions in setattr.def + +variables.c + - don't set a default value for MAILPATH in initialize_shell_variables; + let remember_mail_dates take care of it [in 1.14.4] + +mailcheck.c + - fixed an off-by-one bug in make_default_mailpath [in 1.14.4] + + 3/28 + ---- +[changes for autoconf-generated config files] + +lib/malloc/malloc.c + - use HAVE_GETPAGESIZE, HAVE_BSD_SIGNALS, HAVE_POSIX_SIGNALS + +trap.c + - remove tests for USG and USGr4 + - test on HAVE_POSIX_SIGNALS rather than _POSIX_VERSION + - use MUST_REINSTALL_SIGHANDLERS define to decide whether trap_handler + should call signal again + +getcwd.c + - redid the directory includes for autoconf compatibility + - use HAVE_LSTAT instead of testing for S_ISLNK + - use STRUCT_DIRENT_HAS_D_INO + - include memalloc.h for alloca define + +general.h + - cleaned up strchr, strrchr definitions + - removed tests against USG + - use HAVE_MEMMOVE instead of MEMMOVE_MISSING + +jobs.c + - use HAVE_WAIT3, MUST_REINSTALL_SIGHANDLERS, GETPGRP_VOID + +mailcheck.h + - removed definition of DEFAULT_MAIL_DIRECTORY; now set by + autoconf in config.h + +shell.c + - remove checks on USG, just check for HAVE_GETPW_DECLS + - use C_ALLOCA define + - redid the isnetconn() code using HAVE_SYS_SOCKET_H, + HAVE_GETPEERNAME, SVR4 and SVR4_2 + +general.c + - use HAVE_KILLPG, HAVE_RESTARTABLE_SYSCALLS, HAVE_UNAME, + ULIMIT_MAXFDS, HAVE_TIMEVAL, HAVE_TIMES + +lib/readline/rldefs.h + - redid the tty driver definitions using HAVE_TERMIOS_H, etc. + - don't define anything having to do with signal type + +lib/glob/glob.c + - redid the DIRENT defines and includes + - redid other includes to remove dependencies on USG and system + type (e.g., NeXT) + +builtins/times.def + - changed to use HAVE_GETRUSAGE, HAVE_TIMEVAL, HAVE_TIMES, and + the autoconf way to include and + +builtins/ulimit.def + - changed to use HAVE_GETRLIMIT + - removed test of USG being defined + +siglist.h + - changed to use SYS_SIGLIST_DECLARED, HAVE_UNDER_SYS_SIGLIST, and + HAVE_STRSIGNAL + +print_cmd.c + - use PRINTF_DECLARED + +builtins/command.def + - use HAVE_CONFSTR along with _CS_PATH to get the standard path + +execute_cmd.c + - only compile in execute_shell_script if HAVE_HASH_BANG_EXEC is not + defined + +nojobs.c + - use HAVE_SIGINTERRUPT, HAVE_KILLPG, HAVE_POSIX_SIGNALS, + MUST_REINSTALL_SIGHANDLERS, HAVE_WAITPID, *_TTY_DRIVER defines + +test.c + - set up a new `getmaxgroups' define, moving the code out of inline + - eliminate use of GETGROUPS_T + +variables.c + - use CAN_REDEFINE_GETENV + +sig.c, sig.h + - use HAVE_POSIX_SIGNALS, MUST_REINSTALL_SIGHANDLERS + +pathnames.h + - removed the default mail directory defines; now set by autoconf + +oslib.c + - new file, functions from general.c that are unix-version variable + +general.h + - slightly changed function declarations for use by oslib.c + +support/bashbug.sh + - changed @xxx@ to !xxx! for sed substitutions to avoid conflicts + with autoconf substitutions in the Makefile + - added MACHTYPE variable + +mailcheck.c + - changed DEFAULT_MAIL_PATH to DEFAULT_MAIL_DIRECTORY, since that + more clearly defines its function + +lib/readline/rltty.h + - new file, to include the correct tty driver #include file + +lib/readline/rltty.c + - include rltty.h + +lib/malloc/malloc.c + - make systems with Posix signals block all signals while malloc + is executing + + 3/29 + ---- +input.c + - use off_t as the type of a seek offset, rather that int or long + +variables.c, oslib.c + - moved `getenv' from variables.c to oslib.c + + 3/31 + ---- +sig.c, sig.h + - new function, jump_to_top_level, which just calls longjmp with + top_level as an argument -- here to isolate calls to longjmp + +subst.c + - replaced calls to longjmp with jump_to_top_level + +bashjmp.h + - new file with setjmp/longjmp defines and declarations + +shell.h, nojobs.c + - include bashjmp.h in place of setjmp.h + +shell.c, sig.c, execute_cmd.c, unwind_prot.h, expr.c, +builtins/{return,source}.def + - change to use new defs in bashjmp.h + +subst.c + - make sure PAT and REP in pattern substitution are run through + expand_string_unsplit + +builtins/set.def + - don't try to blindly dereference the value returned by + find_flags in set_shellopts + + 4/2 + --- +aclocal.m4, config.h.in, config.h.top, config.h.bot, configure.in, +support/install.sh, support/config.guess, support/config.sub + - new files for (now official) autoconf-based configuration + +Makefile.in, builtins/Makefile.in, +lib/{doc-support,malloc,glob,termcap,tilde,readline}/Makefile.in + - new Makefiles for autoconf + +[additionally, all source files now include config.h] + + 4/3 + --- +array.c, array.h + - index_t --> arrayind_t, because some systems define index_t in + + + 4/4 + --- +aclocal.m4 + - fix test for broken dup2 + +lib/*/Makefile.in + - make all object files depend on $(BUILD_DIR)/config.h + + 4/5 + --- +array.c + - fixed problems in empty_array: need to reset max_index + and max_size, and remove the links in the element chain + after freeing them + +jobs.c + - new functions to save an array of status values for each + foreground job that exits (degenerate case is to have a + single-process job exit and have a 1-element array) + - new function to set a shell array variable `PIPESTATUS' + which holds the status values from each member of the + last-executed pipeline that spawned children + +documentation/bash.1 + - documented $PIPESTATUS + + 4/6 + --- +configure.in + - added new --with-afs argument to #define AFS for execute_cmd.c + + 4/10 + ---- +builtins/ulimit.def + - use sysconf(_SC_CHILD_MAX) to find the maximum number of child + proceeses per user if HAVE_SYSCONF and _SC_CHILD_MAX are both + defined and RLIMIT_NPROC is not + + 4/12 + ---- +lib/readline/undo.c + - new variable, local to library, to keep track of the number of + `open' undo groups (UNDO_BEGIN without corresponding UNDO_END) + - new function _rl_fix_last_undo_of_type to modify start and end + bounds of last undo record of a specified type + +lib/readline/vi_mode.c + - _rl_vi_done_inserting now calls rl_end_undo_group if the count + of unclosed groups is > 0 + - fixed rl_vi_change_to to save an undo record when redoing and + to fix the buffer corruption when doing `u' undo after a `.' + redo of `C' + + 4/13 + ---- +unwind_prot.h + - changed to use a union { char *s; int i; } when unwind-protecting + integers to force correct alignment on machines where ints and + pointers differ in size + +lib/readline/readline.c + - new variable Keymap rl_executing_keymap, which is set to the + keymap the last function was invoked out of + +lib/readline/bind.c + - new variable Keymap rl_binding_keymap, which is set to the last + keymap a function and key sequence were bound in + + 4/17 + ---- +general.c + - removed xmalloc, xrealloc, xfree to xmalloc.c + +lib/malloc/Makefile.in + - MALLOC and ALLOCA are both set by autoconf + - need to provide some empty stub file to make up the library + in case neither malloc.c and alloca.c are compiled into the + shell + +lib/malloc/gmalloc.c + - new file, GNU libc malloc code + +Makefile.in + - new source file, xmalloc.c, new object file, xmalloc.o + +general.h + - changed type of size argument to xmalloc, xrealloc to `size_t' + +configure.in + - changes for new argument `--with-glibc-malloc' that includes + gmalloc.o in libmalloc.a + + 4/18 + ---- +xmalloc.c + - if malloc or realloc return null, report in the error message + how many bytes have been allocated + +lib/readline/display.c + - changed redisplay code to use an array of positions in the visible + and invisible lines at which to break lines instead of simply + calculating based on the screenwidth and number of invisible + characters. In the future, this will allow newlines embedded in + the lines to display to be handled better + +[Bash-1.14.4 released to net] + + 4/19 + ---- +lib/readline/signals.c + - changed last call to signal() to call rl_set_sighandler() + + 4/20 + ---- +lib/readline/display.c + - changed some ascii-specific code to use CTRL_CHAR and UNCTRL + - finished up the changes that keep an array of line breaks + +shell.h + - moved #define constants for parameter pattern substitution here + from subst.c + +subst.c + - changed the pattern substitution functions to take a `flags' + parameter, which subsumes the match type, global replacement + flag, and quoted variables + - changed the pattern substitution functions to handle the `#' + and `%' match qualifiers, which anchor the match at the + beginning and end of the string, respectively + +shell.c + - moved the code that turns off privileged mode into a function + named `disable_priv_mode' + - if the shell is running setuid or setgid and `-p' is not + supplied, turn off privileged mode and reset the effective + uid/gid + + 4/21 + ---- +subst.c + - added a `quoted' paramter to parameter_brace_remove_pattern; + Posix.2 says that the pattern is parsed differently if the + entire expression is double-quoted + - `getpattern' now takes a second argument, `quoted' + - fixed `getpattern' to correctly handles a pattern spec when + the whole expression is double-quoted. Posix.2 says that + quote characters inside the pattern spec don't quote any + special pattern chars if the whole thing is double-quoted. + For example, the `*' in "${foo#'*'}" is not quoted, and the + single quotes must appear literally. + +Makefile.in + - add `documentation' as a dependency of `.made' + + 4/24 + ---- +Makefile.in + - added `installdirs' target that makes bindir, infodir, mandir, + and man3dir [in 1.14.5 cpp-Makefile] + + 4/25 + ---- +builtins/fc.def + - fixed problem with `fc -l' that occurred when fewer than 16 lines + were in the history list [in 1.14.5] + + 5/1 + --- +Makefile.in, {builtins,documentation}/Makefile.in, lib/*/Makefile.in + - fixed up the various `clean' targets to agree with Gnu coding + standards + + 5/2 + --- +lib/readline/complete.c + - made insert_all_matches correctly quote each of the filenames + inserted into the line, if necessary + +config.h.top + - surround definitions of DEFAULT_PATH_VALUE and STANDARD_UTILS_PATH + with #ifndef/#endif to allow them to be overridden from the command + line + +builtins/set.def + - changed set -o allenv to set -o keyword for ksh88 compatibility + +documentation/{bash.1,features.texi} + - changed set -o allenv to set -o keyword + +builtins/setattr.def + - added a `nodefs' attribute to set_or_show_attributes, + show_var_attributes, and show_name_attributes to inhibit printing + of definition as well as name + +builtins/declare.def + - changed calls to set_or_show_attributes, and show_var_attributes + accordingly + + 5/3 + --- +Makefile.in + - LIBPATH -> LIBSUBDIR + + 5/4 + --- +lib/readline/bind.c + - renamed readline variable meta-flag to be input-meta + +documentation/bash.1, lib/readline/doc/rluser.texinfo + - changed meta-flag to input-meta + +documentation/Makefile.in + - use groff -Tascii to convert .1 -> .0 + +subst.c + - new function, strip_trailing_ifs_whitespace, does the obvious + +builtins/read.def + - call strip_trailing_ifs_whitespace before assigning last + variable to remainder of input string [in 1.14.5] + + 5/5 + --- +builtins/hashcom.h + - changed check_dot member of the PATH_DATA struct to flags, and + added a HASH_CHKDOT define to replace the check_dot semantics + - add HASH_RELPATH define for flags value + +builtins/hash.def, builtins/common.c + - instead of xxx->check_dot, use (xxx->flags & HASH_CHKDOT) + +builtins/hash.def + - if the full pathname to which a command is being hashed does + not begin with a `/', set the HASH_RELPATH flag for it + +builtins/common.c + - if a hashed filename as HASH_RELPATH set, check ./filename, + returning null if that filename is not executable + +execute_cmd.c, general.c, execute_cmd.h, general.h + - moved same_file and check_binary_file from execute_cmd.c to + general.c + +hashlib.c, Makefile.in + - renamed hash.c to hashlib.c + +hashlib.h, Makefile.in, builtins/Makefile.in, alias.h, variables.h, +execute_cmd.c, hashlib.c, builtins/hashcom.h + - renamed hash.h to hashlib.h + +variables.c, alias.c + - removed inclusion of `hash.h'; header files already include + correct file + +Makefile.in + - new rule to remake all the Makefiles (`make Makefiles') + - more changes to adhere to GNU coding standards for the various + flavors of `clean' targets + + 5/8 + --- +documentation/Makefile.in + - use `texi2dvi' to make dvi files rather than tex and texindex + [in 1.14.5] + - don't install `bash_builtins.1' [in 1.14.5] + +Makefile.in + - removed instances of doc-support/texindex + + 5/9 + --- +make_cmd.c + - new function make_bare_word, to make a WORD_DESC from a string but + not to set any of its flags + - broke make_word into make_bare_word and make_word_flags + - fixed a bug in make_word_flags to make backslash-quoting a quoting + character work right to not set the W_QUOTED flags + +subst.c, array.c, execute_cmd.c + - call make_bare_word instead of make_word in situations where we + don't want the flags set inadvertently + + 5/11 + ---- +subst.c + - removed special handling of $POSIX_PEDANTIC + + 5/12 + ---- +shell.c + - broke the code that fetches the uids and gids into a new + function, uidget() + +subst.c + - EUID and UID are no longer handled specially, since they're + readonly + - removed sv_uids function + - merge sv_histfilesize into sv_histsize + +variables.c + - instead of calling sv_uids from initialize_shell_variables, + call uidset() instead + - sv_uids -> uidset with mods to make it faster and avoid an + extra call to free, malloc, and itos + +bashhist.c + - call sv_histsize instead of sv_histfilesize + + 5/13 + ---- +pathexp.c + - moved setup_ignore_patterns here from bashline.c, so GLOBIGNORE + works even when readline is compiled out of the shell + - changed the ignore data structure to a `struct ignorevar', + defined in pathexp.h + - added functions to implement GLOBIGNORE + +bashline.c + - setup_ignore_patterns now in pathexp.c + - renamed _ignore_names to ignore_completion_names + +subst.c + - new function sv_globignore to be called when GLOBIGNORE changes + value + +documentation/{bash.1,features.texi} + - documented GLOBIGNORE + + 5/15 + ---- +documentation/texinfo.tex + - upgraded to version 2.145 from autoconf-2.3 distribution + + 5/16 + ---- +lib/readline/display.c + - delicate surgery on rl_redisplay, update_line, and _rl_update_final + to convert to using the line breaks array instead of assuming that + lines wrap because they're too long and using absolute buffer + positioning calculated from the screen width. Now the `lithist' + shopt option works right + +lib/readline/complete.c + - make sure insert_match doesn't double an opening quote character + after make_quoted_replacement adds an opening quote [in 1.14.5] + - make sure append_match doesn't double a closing quote character + [in 1.14.5] + +quit.h + - new macros: SETINTERRUPT, CLRINTERRUPT, ADDINTERRUPT, DELINTERRUPT + to manipulate the value of interrupt_state + +trap.c, sig.c, jobs.c + - changes to use the new macros from quit.h + +jobs.c + - make an a job that exits due to SIGINT make the shell act as if + it received the interrupt itself, but only if SIGINT is not + trapped [in 1.14.5] + + 5/18 + ---- +builtins/common.c + - fix up find_hashed_filename and the HASH_RELPATH code. still need + to use `shopt -s checkhash' to check the hashed pathnames. could + fix this up more to make that unnecessary in the HASH_RELPATH case + +subst.c + - new function get_array_value that does array subscripting for + things like aa[1], for use by other parts of the shell like the + expression evaluator + +expr.c + - changes to make things like $(( aa[1] + aa[2])) work without + using ${aa[1]} + +bashhist.c + - converted the HISTIGNORE code to use the `struct ignorevar' + framework, with a callback function histignore_item_func to + set the HIGN_EXPAND flag if needed + +pathexp.c + - made the `globignore' variable static + - redid the code that removes ignored names from the `names' array + in ignore_globbed_names to make it more efficient + +bashline.c + - made the `fignore' variable static + + 5/20 + ---- +Makefile.in + - made the `distclean' target remove the Makefiles in subdirectories + created by autoconf + + 5/22 + ---- +builtins/command.def + - don't allow `command -p' if the shell is restricted + +documentation/bash.1 + - documented the restriction on command -p for rbash + + 5/23 + ---- +aclocal.m4 + - add a new macro BASH_CHECK_TYPE, based on AC_CHECK_TYPE, that + allows the caller to specify the header files to be included + in the test program and provides for a default value to be + defined if the type is found in the system files + +configure.in + - check for getrusage and gettimeofday functions/syscalls + - use BASH_CHECK_TYPE to check for clock_t in sys/types.h and + sys/times.h + - use BASH_CHECK_TYPE to check for sigset_t instead of a special + BASH_TYPE_SIGSET_T + - use BASH_CHECK_TYPE to check for quad_t instead of BASH_QUAD_T + - new argument --enable-command-timing to compile in the `time' + reserved word and command timing + +general.c + - print_time_in_hz takes a `clock_t', not a `time_t' + +execute_cmd.c + - support for timing pipelines with a new function time_command + - execute_command_internal calls time_command if it is passed a + command with the CMD_TIME_PIPELINE bit set in command->flags + - new functions difftimeval and addtimeval to do arithmetic on + timeval structs with overflow + +parse.y + - new production: pipeline_command, used by list1 and simple_list1 + - pipeline_command includes rules to handle `!' and time + - code to recognize `time' as a reserved word + +print_cmd.c + - new code to print `time ' before a command if the CMD_TIME_PIPELINE + flag bit is turned on + +builtins/test.def + - added description of string1 < string2 and string1 > string2 to + the long doc + +test.c + - added `<' and `>' string binary operators + +documentation/bash.1 + - documented the `time' reserved word and command timing + - documented the new test `<' and `>' binary operators + +documentation/features.texi + - documented the `time' reserved word and command timing + - added more to the section detailing the differences between bash + and sh + - added descriptions of LINENO and ENV to the Ksh variables section + - added description of echo to bash builtins section + - added PPID, BASH, SHLVL to the Bash variables section + +subst.c + - added a `quoted' parameter to extract_dollar_brace_string; changed + all calls to it + + 5/24 + ---- +builtins/let.def + - wrote code for an `exp' builtin that treats all of its arguments + as an expression, concatenates them like `eval', and runs the + expression evaluator + +expr.c + - added code to do the Posix.2 conditional operator: expr?expr:expr + - added a `noeval' flag to suppress evaluation. currently it only + suppresses assignment + - added code to the && and || functions so that evaluation is + suppressed in the part of the statement that is not supposed to + be executed (a && b: set noeval if a is false; a || b; set + noeval if a is true) + + 5/25 + ---- +documentation/{bash.1,features.texi} + - documented new `expr?expr:expr' conditional expression syntax + now arithmetic evaluation is Posix.2-conformant + +lib/readline/readline.c + - added several more locale names to the list of legal $LANG + values + +subst.c + - fixed a bug in parameter_brace_patsub: when replacing a string + with nothing, rep was set to "", and the code attempted to + free "", which the GNU malloc upchucked on + +bashhist.c + - just add a line to the history if command_oriented_history is + set to 1 and the current line in the command is > 1; don't + even bother checking history_ignore + +parse.y + - new variable `two_tokens_ago' to remember the token read before + `token_before_that' + - fix to history_delimiting_chars to make sure that no semicolon + is added after `()' (assume its a function definition), but that + a semicolon is added after other `)' (assume its a parenthesized + command) + + 5/31 + ---- +tests/run-all + - put `.' first in $PATH and don't export ENV + - set THIS_SH to ../bash if it's unset + +lib/readline/complete.c + - only try to find a word break character in rl_complete_internal + if we hit the end of the input string and found_quote == 0 + (the opening quote could have been the last character in the + string) + + 6/2 + --- +subst.c + - changed make_quoted_char to return CTLNUL\0 if passed a \0 + (this is what quote_string does, too) [in 1.14.5] + - changed list_string to use make_quoted_char when adding a quoted + null argument due to a null field when ifs != ' \t\n' + - added an `expandpat' argument to getpattern, which tells it to + call string_extract_double_quoted if the pattern expression is + double-quoted, and changed all calls to initially pass `1' as + its value + +jobs.c + - changed start_job so that an attempt to start a job marked as + JDEAD elicits an error message [in 1.14.5] + +Makefile.in + - fixed `distclean' target so that it removes Makefiles in subdirs + *after* descending into them to do submakes (!) + - fixed `realclean' target to remove everything that distclean does + + 6/5 + --- +builtins/declare.def + - fixed a typo that made `declare +r var' turn off read-only status + for a variable [in 1.14.5] + - added -p option to short doc and long doc + - added code to allow `declare -f -options name' to set and unset + attributes for the named functions. Only when no other options + are supplied will the named and value of the function be displayed + [in 1.14.5] + +variables.h + - new SETVARATTR macro to set or unset attributes for a specific + SHELL_VAR * + +builtins/setattr.def + - use SETVARATTR + + 6/7 + --- +execute_cmd.c + - moved the retrieval of $PS3 inside the loop in execute_select_command + so that PS3 can be modified in the select command's body + [in 1.14.5] + +execute_cmd.c + - changed execute_builtin and execute_function to not set + builtin_env and function_env, respectively, to NULL if there is + no temporary env. This makes the temp env persist across calls + to functions from other functions [in 1.14.5] + +configure.in + - Linux needs LOCAL_LDFLAGS set to -rdynamic + + 6/8 + --- +general.c + - canonicalize_pathname should not attempt to interpret backslash + quoting `/', since Unix doesn't really allow it [in 1.14.5] + +bashline.c + - added `\', `!', and `)' to the list of characters which + cause filenames to be quoted + - changed bash_quote_filename to use any of the three shell + quoting styles based on the value of a variable, + completion_quoting_style + - if *qcp is not 0 when passed to bash_quote_filename, adjust the + type of completion we're doing based on its value (i.e., + *qcp == '"' forces double quoting, *qcp == '\'' forces single) + - bash_quote_filename now leaves the quotes intact in the filename + it returns. The readline completion code takes care of avoiding + doubled open quotes + - if a filename containing a `!' is passed to bash_quote_filename + without an opening quote character, and we are performing history + expansion, use single quoting as the quoting style + +bashhist.c + - changed bash_history_disable to not call bash_history_reinit(0), + but do what it needs to directly + - new function bash_history_enable + - make history_expansion_inhibited exist only if BANG_HISTORY + is defined + +bashhist.h + - extern declaration for bash_history_enable + +lib/readline/complete.c + - make make_quoted_replacement set should_quote to 1 if the quote + character is `'' as well as if it's `"' + +test.c + - added the csh-like `=~' and `!~' pattern-matching binary operators + which match the string on the lhs against the shell pattern on + the rhs. PATTERN_MATCHING must be defined for this to work; it is + undefined and undocumented by default + +jobs.c + - broke the code that gets the new window size and sets $LINES and + $COLUMNS out of sigwinch_sighandler into a new function, + get_window_size, which sigwinch_sighandler calls + + 6/12 + ---- +parse.y + - new function, pop_expansion, to remove the top string on the + expanded token stack + - renamed save_expansion to push_expansion + +lib/readline/complete.c + - fixed a bug in find_completion_word that tested found_quote + instead of quote_char when trying to decide if we have an unclosed + quoted string [in 1.14.6] + + 6/26 + ---- +subst.c + - fixed expand_word_internal to remove all traces of $*, even if + it's quoted, if there are no positional parameters and there are + other characters in the expansion + +bashline.c + - don't attempt hostname completion if multiple consecutive `@' + characters appear + + 6/27 + ---- +shell.c + - initialize top_level early, and exit if a longjmp sends us there + before we reinitialize + +subst.c + - more fixes to expansion of quoted $* when no positional parameters + - broke the code that assigns a value to an array element (and parses + the array element reference) into a new function, + do_array_element_assignment + +builtins/read.def + - new function, bind_read_variable, to allow binding simple variables + and array elements to strings read (uses do_array_element_assignment) + - changed occurrences of bind_variable to bind_read_variable where + it matters + +variables.c + - tentative change to bind_variable to make x=y the same as x[0]=y + if x is already an array variable. This works for `read' as well. + This is what ksh does. + + 6/28 + ---- +alias.h + - added a `flags' member to the ASSOC struct and renamed it to + `alias_t' + +alias.c, bashline.c, builtins/alias.def, builtins/type.def + - changed ASSOC to alias_t + +alias.c + - changed add_alias to set the AL_EXPANDNEXT flag when the alias is + inserted into the hash table + +parse.y + - added a third parameter to push_string: a pointer to the alias_t + that is being expanded + - push_string marks the alias it's passed as being expanded + (AL_BEINGEXPANDED) + - pop_string marks the alias being popped as no longer being + expanded + - changed shell_getc to defer popping an alias expansion until + the parser has had a chance to catch up, since the parser reads + ahead and would cause the expansion to be popped before it + fully parsed the expanded string + - changed alias_expand_word to check the AL_BEINGEXPANDED flag + instead of the expanded_token_stack when checking whether an + alias is already being expanded + +oslib.c + - make the definition of bzero be surrounded by #ifdef HAVE_BZERO + rather than lumping it in with bcopy + +configure.in + - add a test for bzero + +config.h.in + - add a template for HAVE_BZERO + + 7/3 + --- +builtins/set.def + - added new meaning for `set +o' without options, as per the latest + draft of Posix.2. It means to list -o options as a series of set + commands to recreate the current settings + +documentation/bash.1 + - augmented description of the `set' builtin + + 7/6 + --- +jobs.c + - make sure that temp_handler is not set to SIG_DFL before calling + it from waitchld + +builtins/cd.def + - rewrote cd_builtin to make the code flow clearer + - broke full directory name construction out into a separate + function: mkpath + - cd_builtin now tests that a directory constructed from a $CDPATH + entry is actually a directory before trying to chdir to it + - added an error message if $HOME is not set + - added a descriptive error message if `cd -' used and OLDPWD unset + - changed the error messages to use builtin_error, not file_error + - moved the code at the bind_and_exit label into a function, + bindpwd (no_symlinks) + - Posix.2 says that when using $CDPATH, the resultant value of PWD + should have no symlinks + + 7/7 + --- +input.c + - if fd_to_buffered_stream fails in some way and returns a NULL + buffered stream, with_input_from_buffered_stream uses a function + that does nothing but return EOF as the `getter'. This keeps + the shell from crashing if invoked with fd 0 closed + +subst.c + - made the `quoted' parameter to expand_word_internal into a flags + word with flag values defined in shell.h. Each place where + `quoted' is tested for a non-zero value was changed to test + (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) != 0 instead + +mailcheck.c, shell.c, parse.y + - change calls to the expand_string* functions to pass an explicit + Q_DOUBLE_QUOTES where appropriate + + 7/9 + --- +subst.c + - getpattern now passes Q_NOQUOTE to expand_word_internal, indicating + that quotes in the pattern spec are not to be treated specially + + 7/12 + ---- +jobs.c + - fixed up the MUST_UNBLOCK_CHILD code in wait_for so that it now + unblocks all signals and sets the signal handler for SIGCHLD to + SIG_DFL. pre-v4 SCO machines seem to require this [in 1.14.5] + +[Bash-1.14.5 released to net 7/16] + + 7/17 + ---- +documentation/features.texi + - changed the Bourne Shell builtins section to have the same format + as the bash builtins section, with usage synopses + - added a section on the restricted shell + + 7/18 + ---- +documentation/features.texi + - changed the name of this document to the Bash Reference Manual + - added sections on POSIX mode and restricted shell + +lib/readline/doc/hsuser.texinfo + - added the text from the bash manual page about the bash history + facilities if BashFeatures is set + + 7/19 + ---- +documentation/features.texi + - added more stuff to the bash basics section + +lib/readline/doc/rluser.texinfo + - added a sample inputrc file + + 7/20 + ---- +documentation/features.texi + - added section on shell expansions to bash basics section + +builtins/Makefile.in, lib/glob/Makefile.in, lib/malloc/Makefile.in, +lib/readline/Makefile.in, lib/termcap/Makefile.in, lib/tilde/Makefile.in + - ar is now called with flags `cr' when building libraries + + 7/21 + ---- +lib/readline/complete.c + - fixed a bug in find_completion_word that resulted in the found_quote + flag and the delimiter character not being passed back to the + caller (tested (*fp) instead of (fp) before assigning found_quote; + similarly for dp). With this fix, the filename dequoting function + is properly called + + 7/25 + ---- +general.c + - renamed bash_tilde_expand to bash_tilde_expansion_failure_hook + - new function, bash_tilde_expand, that just sets interrupt_immediately + and calls tilde_expand, returning what tilde_expand returns + +subst.c, general.c, shell.c, execute_cmd.c, variables.c, bashline.c, +builtins/cd.def + - changed calls to tilde_expand to calls to bash_tilde_expand instead + + 7/27 + ---- +builtins/set.def + - added a -o history option to enable and disable command history + saving. This uses bash_history_enable() and bash_history_disable() + It's keyed off of remember_on_history. With this, shell scripts + can use the command history + +bashhist.c + - bash_history_enable now calls sv_history_control and sv_histignore + +builtins/fc.def + - if history_list() returns a null pointer, immediately return + [in 1.14.6] + +documentation/{bash.1,features.texi}, lib/readline/doc/hsuser.texinfo + - added a description of the `set -o history' option and changed + text to refer to it rather than strictly interactive shells + + 8/1 + --- +variables.c + - new builtin variable $HOSTNAME, initialized to current_host_name + as set in shell.c + +documentation/bash.1, documentation/features.texi + - documented $HOSTNAME + + 8/3 + --- +support/texi2html + - new program, a texinfo-html converter + +documentation/Makefile.in + - added directives to produce features.html from features.texi + +MANIFEST.doc + - added features.html and features_toc.html to the doc distribution + + 8/10 + ---- +lib/readline/bind.c + - new functions rl_variable_dumper and rl_dump_variables to print + readline variables and their values to rl_outstream + - new functions rl_get_keymap_name and rl_get_keymap_name_from_edit_mode + to get the name of the current keymap for the variable dumper + +lib/readline/readline.h + - extern declarations for rl_variable_dumper, rl_dump_variables, and + rl_get_keymap_name + +builtins/bind.def + - added -V flag to print variable names and bindings + - added -P flag to print variable names and bindings in the syntax + of the inputrc file + +lib/readline/funmap.c + - added new bindable `dump-variables' readline command + +documentation/{bash.{1,html},readline.3,features.html}, +lib/readline/doc/rluser.texinfo + - documented new `dump-variables' readline command + +documentation/{bash.{1,html},features.{texi,html} + - documented new bind -P and -V options + +documentation/bashbug.1 + - new manual page + +documentation/Makefile.in + - changes to build and install bashbug.1 + + 8/15 + ---- +print_cmd.c + - new function `xprintf' that just calls vfprintf(stdout, ...) + to avoid having to declare printf + +parse.y + - slight change in how read_token_word computes `all_digits' + + 8/21 + ---- + +subst.c + - new function dequote_escapes to remove CTLESC escaping + CTLESC and CTLNUL in a string, returning a new string + + 8/25 + ---- +shell.c + - execute the file SYS_BASHRC for interactive shells if SYS_BASHRC + is defined, before executing ~/.bashrc + +config.h.top + - add a dummy commented definition for SYS_BASHRC, defaulting to + /etc/bash.bashrc + +lib/readline/input.c + - added code to call select() in rl_gather_tyi() and return + immediately if it indicates that there is nothing to read on + the readline input fd (#ifdef HAVE_SELECT) + +lib/posixheaders/posixdir.h + - new file to localize the / and dirent/direct + mess + +posixdir.h, lib/readline/posixdir.h + - symlinks to lib/posixheaders/posixdir.h + +lib/readline/rldefs.h + - removed the posix dir includes and defines + +lib/readline/complete.c, getcwd.c + - include posixdir.h rather than having the code inline + +builtins/cd.def + - new code to do spelling correction on the directory name + modified from patch sent by Neil Russell (caret@c-side.com) + + 8/29 + ---- +builtins/shopt.def + - new option `cdspell' to toggle cd directory name spelling + correction + +documentation/{bash.{1,html},features.texi} + - documented new shopt `cdspell' option + + 9/5 + --- +subst.c + - $'' should expand to the same thing as '' (a quoted null string) + +shell.h + - changed CTLNUL to '\177'; some scripts use ^B for things like IFS + [in 1.14.6] + + 9/7 + --- +support/config.guess + - added code to identify a PPC running Solaris 2 + +doc + - new directory replacing documentation + +Makefile.in, MANIFEST, MANIFEST.doc, configure.in + - replaced `documentation' with `doc' + + 9/8 + --- +lib/readline/display.c + - fixed the code in _rl_update_final that decides whether or not the + cursor is at character position 0 on an otherwise-empty line and + adjusts _rl_vis_botlin accordingly + + 9/13 + ---- +general.c + - fixed canonicalize_pathname to make sure that intermediate + results correspond to directories before blindly chopping + off the last component when we see a `..'. This fixes the + `cd ../.../..' being equivalent to `cd ..' problem + +subst.c + - fixed make_named_pipe so that mkfifo is called with mode 0600 + for security reasons [in 1.14.6] + - changed the /dev/fd version of add_fifo_list to zero out new + entries to the fifo_list when it resizes it larger [in 1.14.6] + - changed make_dev_fd_filename to use DEV_FD_PREFIX + +aclocal.m4 + - changed BASH_HAVE_DEV_FD to check for /proc/self/fd and define + DEV_FD_PREFIX to either "/dev/fd/" or "/proc/self/fd/" as + appropriate + + 9/14 + ---- +lib/readline/display.c + - when displaying the first line of a multiline prompt, make sure + that the final \n is followed by a \r (outputting one if necessary) + so that we know we are starting at column 0 + +variables.h + - new attribute: att_local + +variables.c + - changed make_local_variable to set the att_local attribute + - changed makunbound to just make variables marked as `local' in + the current context invisible. This makes the local variable + persist throughout the function even if it is unset, so a + subsequent assignment preserves the `local' attribute + - changed kill_all_local_variables to unset the att_local attribute + before calling makunbound + + 9/18 + ---- +lib/readline/complete.c + - make sure the cursor is on the last line of a possibly-multiple- + line command line before listing the completions in + display_matches + + 9/19 + ---- +braces.c + - fixed the non-SHELL case in brace_gobbler so the loop exits when + it should + +lib/readline/bind.c, lib/readline/readline.h + - added functions to dump key sequences bound to macros and their + values + +builtins/bind.def + - added -S and -s options to dump the readline macros and their values + - changed the options so that -p and -P dump functions, -v and -V + dump variables, and -s and -S dump macros (s for string) + +doc/{bash.{1,html},readline.3,features.texi}, lib/readline/doc/rluser.texinfo + - added documentation for the new `bind' options + - added documentation for the new readline functions to dump macros + and the key sequences that output them + + 9/22 + ---- +print_cmd.c + - new function xtrace_print_word_list (WORD_LIST *) to print the + words of a simple command when set -x is on. This prints '' + when it encounters an empty string + +externs.h + - new extern declaration for xtrace_print_word_list + +execute_cmd.c + - call xtrace_print_word_list in execute_simple_command + + 9/25 + ---- +builtins/getopts.def + - make sure that the loop counter stops at 10 when stepping through + the dollar_vars array to count the number of positional parameters + [in 1.14.6] + + 9/30 + ---- +lib/readline/histsearch.c + - fixed history_search_internal to bail immediately if it gets a + null or empty search string. This fixes the !? core dumps. + [in 1.14.6] + + 10/3 + ---- +lib/readline/histexpand.c + - if there is a null string given with a !? search specifier, use + a previous search string if one exists, else fail immediately + +trap.c + - made run_exit_trap preserve $? around the call to execute the + trap string, unless the trap string contains an `exit' + command, in which case it can set the shell's exit status + [in 1.14.6] + + In other words: + + touch /tmp/z + trap 'rm /tmp/z ; exit 5' 0 + exit 1 + + exits with status 5; while + + touch /tmp/z + trap 'rm /tmp/z' 0 + exit 1 + + exits with status 1 + +subst.c, parse.y + - moved the $'...' code from subst.c to parse.y, more like ksh + does it + +doc/bash.1, doc/bash.html, doc/features.texi + - moved the description of $'...' from the expansion section to + the quoting section + + 10/4 + ---- +command.h + - added a `line' member to the function struct for the source line + the function definition starts on + +make_cmd.c + - initialize the `line' member in Function_def to 0 + - make_function_def takes a third parameter telling which line the + function definition started on and a fourth telling which line + the function body started on + +make_cmd.h + - changed prototype for make_function_def + +parse.y + - new variable `function_dstart', set by read_token and read_token_word + to keep track of where a function definition begins + - new variable `function_bstart' to keep track of where function + body begins + - pass function_dstart and function_bstart to make_function_def + - new function strtrans to do the $"..." locale-specific translation + of `...' + - call strtrans() to translate $"string". The translated string is + double-quoted + +doc/bash.{1,html} + - updated the description of LINENO now that line numbers within + functions are correct + +configure.in + - look for the `gettext' library function + +config.h.in + - define HAVE_GETTEXT if gettext(3) exists in a findable library + + 10/5 + ---- +builtins/common.c + - changed backslash_quote so that `#' is only quoted at the start + of a word + - new function contains_shell_metas returns 1 if the argument + string contains one or more shell meta-characters that require + quoting + +builtins/common.h + - extern declaration for contains_shell_metas + +print_cmd.c + - changed xtrace_print_word_list to print words containing + shell metacharacters within single quotes + +lib/termcap + - upgraded to GNU termcap version 1.3 + + 10/9 + ---- +lib/readline/readline.c + - call setlocale(LC_CTYPE, ...) after finding a legal value for + one of LC_ALL, LC_CTYPE, or LANG + + 10/11 + ----- +lib/readline/search.c + - make rl_history_search_internal just do previous-history or + next-history as appropriate when given a null search string + (rl_point == 0) + + 10/24 + ----- +subst.c + - fixed an off-by-one error in char_is_quoted that skipped a + characters after calling skip_single_quoted or skip_double_quoted + [in 1.14.6] + - fixed an off-by-one error in string_extract_verbatim so it + leaves *sindex at the separator character if the separator + character is "'" [in 1.14.6] + + 10/27 + ----- +parse.y + - in CHECK_FOR_RESERVED_WORD, make sure that reading a `}' + decrements open_brace_awaiting_satisfaction if it is non-zero + [in 1.14.6] + +shell.c + - don't run the shell startup files if the shell is running + setuid + - don't source $ENV if the shell is running setuid + +variables.c + - new parameter to initialize_shell_variables: no_functions. If + non-zero, don't import functions from the environment + +variables.h + - change to function prototype for initialize_shell_variables + +lib/readline/complete.c + - fix for the code that decides whether or not a char is quoted for + applications that don't supply a value for rl_char_is_quoted_p + - fixed insert_match to not remove a user-supplied opening quote + character if make_quoted_replacement does not return a string + beginning with that quote character + + 11/2 + ---- +general.c + - new function ungetc_with_restart that handles the local buffering + [in 1.14.6] + +parse.y + - changed yy_stream_unget to call ungetc_with_restart if the OS + does not have restartable syscalls [in 1.14.6] + + 11/3 + ---- +bashline.c + - rewrote _ignore_completion_names to actually free and remove + names from the array if more than one names in the array + passed is acceptable, instead of just bailing [in 1.14.6] + + 11/7 + ---- +bashline.c + - if no matches are acceptable to _ignore_completion_names, + free the entries in NAMES, set NAMES[0] == 0, and let the + caller clean up [in 1.14.6] + - fixed a problem with backslash-quoted characters in + bash_dequote_filename that caused the character after the + backslash to be interpreted + - bash_dequote_filename now takes a quote_char parameter that, + if non-zero, gives the quote character (`'' or `"') that + delimits the filename. Used to initialize the quoting state + +lib/readline/complete.c + - if the completion ignore function returns with MATCHES == 0 + or MATCHES[0] == 0, ring the bell and quit the completion + attempt [in 1.14.6] + - pass quote_char to gen_completion_matches so it can pass it + along to the app-specific filename dequoting function + - have gen_completion_matches pass quote_char to whatever function + is pointed to by rl_filename_dequoting_function + +pathexp.c + - rewrote ignore_globbed_names to be more like _ignore_completion_names + +lib/readline/doc/rltech.texinfo + - updated documentation for rl_filename_dequoting_function + + 11/10 + ----- +subst.c + - fixed remove_quoted_nulls so that it is now a full function that + removes unquoted CTLNUL chars from the string it is passed + [in 1.14.6] + - fixed expand_word_internal to avoid generating some unneeded + quoted nulls (if the string is partially quoted, note that we + have seen a quoted null and add one if the rest of the string + doesn't expand to anything) + + 11/13 + ----- +variables.c + - bind HOSTTYPE, OSTYPE, and HOSTNAME unconditionally + +pathexp.c + - new function quote_globbing_chars, adds `\' before globbing + chars in its string argument, returns new string + +pathexp.h + - extern declaration for quote_globbing_chars + +bashhist.c + - if the previous line contains globbing chars, run it through + quote_globbing_chars before trying to match. This affects + only HISTIGNORE patterns containing `&' + + 11/14 + ----- +bashhist.c + - if the history line to be added contains globbing chars, quote + them with backslashes by calling quote_globbing_chars in + history_should_ignore before comparing them against the + patterns in HISTIGNORE + +bashline.c + - make sure that we erase the current readline line after running + fc on it and executing the resultant commands in + vi_edit_and_execute_command, so the original readline line + doesn't get returned [in 1.14.6] + +jobs.h + - added a new job listing format: JLIST_NONINTERACTIVE -- like + JLIST_LONG, but does not print the job number + +jobs.c + - added code to pretty_print_job to handle JLIST_NONINTERACTIVE + - call notify_and_cleanup() from wait_for even if the shell is + running a script (interactive_shell == 0) + - changed notify_and_cleanup to call notify_of_job_status if + interactive or interactive_shell == 0, so scripts report + about jobs they run + - changed notify_of_job_status to call pretty_print_job with a + JLIST_NONINTERACTIVE format if interactive_shell is 0 and a + job is marked JDEAD, after printing the script name and line + number. This message is printed only if the job dies due to + a fatal signal + +support/mkversion.c + - added support for a `-status status' argument to set the + `release status' of the shell (alpha, beta, or release). It + defines `RELSTATUS' in version.h and changes the definition + of SCCSVERSION, if present + +Makefile.in + - set a RELSTATUS variable that is included when printing the build + message and passed to mkversion with the -status option + - make RELSTATUS one of the variables sed sets when it creates + bashbug from support/bashbug.sh + +version.c + - added a `release_status' variable that's set to RELSTATUS if + it's defined + +support/bashbug.sh + - added the `RELSTATUS' variable to the report with heading + `Release Status' + - set the bug address to chet@po.cwru.edu if the release status + is `alpha' or `beta' + + 11/15 + ----- + +shell.c, execute_cmd.c + - new variable expand_aliases to control alias expansion. For now, + this is set to the same value as interactive_shell when that is + set + +parse.y + - perform alias expansion if expand_aliases is non-zero rather than + checking the value of interactive_shell + + 11/16 + ----- +builtins/shopt.def + - new option `expand_aliases' to control the value of expand_aliases + +doc/bash.1, doc/bash.html + - updated the description of `shopt' with the `expand_aliases' option + + 11/28 + ----- +bashline.c + - if there is only one completion in _ignore_completion_names, see + if it is acceptable and return right away [in 1.14.6] + +configure.in + - change to define WAITPID_BROKEN on SCO 3.2v5 + + 12/6 + ---- +parse.y + - call prompt_again in read_token_word if a newline is read in an + interactive shell and bash_input.type is either st_stdin or + st_stream + - remove superfluous call to reset_readline_prompt in yy_readline_get + + 12/7 + ---- +parse.y + - combine delimiters, delimiter_depth, and delimiter_space into a + single structure of type `struct dstack' + - replace all references to delimiter* with dstack.delimiter* + - include parser.h for struct dstack + - new define pop_delimiter(), analogous to push_delimiter + - current_delimiter, push_delimiter, and pop_delimiter defines now + include the delimiter stack struct as the first parameter + +parser.h + - now includes definition of struct dstack + +bashline.c + - include parser.h for struct dstack + - refer to dstack.delimiter_depth instead of delimiter_depth + + 12/12 + ----- +execute_cmd.c + - before doing a longjmp(subshell_top_level,...) when executing a + shell script without a leading #!, set history_lines_this_session + to 0 to forget about the history and not save it on an exec + (we don't free the memory with clear_history(), though -- that + would slow bash down) + + 12/14 + ----- +jobs.c, nojobs.c + - cause the sigwinch handling code to be compiled into the shell + even if READLINE is defined + - new functions: set_sigwinch_handler and unset_sigwith_handler + to enable and disable catching of SIGWINCH and adjusting $LINES + and $COLUMNS + - changed initialize_job_signals to install a signal handler for + SIGWINCH with set_sigwinch_handler + +jobs.h + - extern declarations for set_sigwinch_handler and + unset_sigwinch_handler + + 12/20 + ----- +doc/bash.{1,html}, doc/readline.3, lib/readline/doc/rluser.texinfo + - documented the readline `visible-stats' variable + + 12/21 + ----- +trap.c + - new global variable `running_trap' incremented and decremented + around running a trap command in _run_trap_internal + +execute_cmd.c + - new variable currently_executing_command, set to the COMMAND * + currently being processed by execute_command_internal, unless a + trap command is being run (running_trap != 0) + - new function executing_line_number, which returns the line number + of the currently executing command (which may not be the same as + line_number) + - don't run the debug trap if it was not set before the current + simple command was executed, since we don't want to run it after + the trap command that sets the DEBUG trap + +variables.c + - new function assign_lineno, to assign a value to line_number + when LINENO is set + - changed get_lineno to call executing_line_number() rather than + returning line_number + +parse.y + - new argument for push_stream telling it whether or not to reset + line_number to 0 + +builtins/common.c + - change to parse_and_execute to call push_stream with an argument + + 12/29 + ----- +subst.c + - set subshell_environment in command_substitute and process_substitute + for the child process + + 1/2 + --- +trap.c + - made decode_signal recognize signal names case insensitively + +shell.c + - make the shell exit on a longjmp (DISCARD, ...) if + subshell_environment is non-zero + + 1/16 + ---- +lib/readline/histexpand.c + - let the `!' in ${!xxx} pass through without error + +shell.c + - new --help long option + - new function show_shell_usage() for use by --help + + 1/19 + ---- +parse.y + - changes to shell_getc to make sure that lines consisting of only a + newline get added to the history correctly when they are part of + a quoted string + + 1/24 + ---- +aclocal.m4, configure.in + - added a check for -lsocket (and -lnsl) to fix solaris problems + with isnetconn() + +shell.c + - rearranged the code in isnetconn to check for a socket using + getpeername() first, before any SVR4 or SVR4.2-specific checks + - added checks for ttys (isatty) and FIFOs (S_ISFIFO) to the + SVR4/SVR4.2 case of isnetconn() + +general.h + - new macro RESIZE_MALLOCED_BUFFER to check and see whether there + is enough room in a string to add a given number of characters + and to resize it if there is not + + 1/25 + ---- +parse.y, general.c, subst.c, bashhist.c, alias.c, array.c, variables.c + - use RESIZE_MALLOCED_BUFFER where appropriate + + 1/26 + ---- +support/config.{guess,sub} + - merged in latest changes from GNU master copies + + 1/30 + ---- + +jobs.c + - make sure to freeze the jobs list when calling a trap handler + for SIGINT + - added code to waitchld() so that a SIGINT trap handler is called + if the shell is running a shell script and a SIGINT is received + while waiting for a foreground job, even if that job does not + die from the SIGINT + +jobs.c, nojobs.c + - make get_tty_state reset $LINES and $COLUMNS after each process + exits if the variable `check_window_size' is non-zero + +builtins/shopt.def + - new variable `checkwinsize', which controls the value of + check_window_size + +doc/{bash.{1,html},features.texi} + - updated description of `shopt' to include `checkwinsize' + +execute_cmd.c, lib/readline,complete.c + - some changes from the GNU WIN32 project for the bash port to + Windows NT and Windows 95 + +bashwait.h + - new file, with `union wait' defines from jobs.h + +jobs.h + - include `bashwait.h' if is not present and + _POSIX_VERSION is not defined + - removed define of pid_t for non-Posix systems; now provided by + autoconf in config.h + + 1/31 + ---- +parse.y + - new temporary delimiter stack, used when decoding prompt strings. + This is needed so command substitutions in the prompt strings + (especially PS2) don't screw up the parser's quoting state + +lib/readline/complete.c + - new variable for readline library users: + rl_completion_append_character. The value of this variable is + the character appended to a completion when it occurs at the + end of a line. Setting it to '\0' causes nothing to be + appended. + +lib/readline/readline.h + - declaration for rl_completion_append_character + +lib/readline/doc/rltech.texinfo + - documented rl_completion_append_character as int variable available + to library users + +subst.c + - new code for maintaining a string array saying which words in the + output of expand_word_list_internal are the result of globbing + +variables.c + - new function put_gnu_argv_flags_into_env (pid, flags_string) + to put Roland's GNU getopt helper variable into the export_env + +execute_cmd.c + - in execute_disk_command, after forking the child, put the GNU + getopt helper environment variable into the child's export_env + +unwind_prot.c + - changed unwind_protect_var and restore_variable to do the + bcopy of the variable's value if it's shorter than the size of + an int, as well as if it's longer. This keeps stray data + from being copied if a short is being unwind-protected + +unwind_prot.h + - new define, unwind_protect_short, to protect variables smaller + than an int + +jobs.c + - in the code that handles SIGCHLD traps, call unwind_protect_short + if that is the size of a pid_t (for last_made_pid) + + 2/5 + --- +Makefile.in + - only try make distclean in HIST_LIBDIR if Makefile exists -- could + have already been removed if HIST_LIBDIR is the same as RL_LIBDIR + +general.c + - make canonicalize_pathname be more careful about what it checks + for being a directory name when processing a full pathname + +Makefile.in, configure.in, doc/Makefile.in + - small changes to get bash to build better in a directory not the + source directory + + 2/12 + ---- +Makefile.in + - added `install-strip' target + + 2/14 + ---- +doc/bash.{1,html}, doc/features.texi + - documented the `--verbose' startup option + +lib/readline/complete.c + - fix to gen_completion_matches to fix a memory leak + - fix to rl_complete_internal to fix a memory leak + + 2/15 + ---- +bashwait.h + - changed to use WORDS_BIGENDIAN instead of LITTLE_ENDIAN or + BIG_ENDIAN + +configure.in, config.h.in + - call AC_C_BIGENDIAN, define WORDS_BIGENDIAN + +Makefile.in + - remove all references to mkendian.c, mkendian, and bash_endian.h + - added a `symlinks' target that just runs support/fixlinks + +MANIFEST + - mkendian.c is no longer in the distribution + + 2/16 + ---- +execute_cmd.c + - include if HAVE_SYS_TIMES_H and HAVE_TIMES are + defined + +bashline.c + - fix to bash_directory_completion_hook to compensate for + canonicalize_pathname returning NULL + +variables.c + - fix to initialize_shell_variables to compensate for + canonicalize_pathname returning NULL + + 2/22 + ---- +tests/test-tests, tests/test.right + - changes to avoid writing in the source directory -- all temp files + are created in /tmp + +[First alpha release at Thu Feb 22 15:59:51 EST 1996] + + 2/23 + ---- +lib/readline/rldefs.h + - work around SVR4.2 bug including and + +lib/readline/chardefs.h + - fix to CTRL_CHAR macro for chars > 128 on systems with signed + characters + +builtins/ulimit.def + - protect more of the RLIMIT_* defines with checks + - new macro RETINVALID() to set errno and return the correct + value for an invalid request + +doc/Makefile.in + - add a definition for INSTALL, set by autoconf + + 2/26 + ---- +support/bashbug.sh + - if USER is unset, assign it the value of $LOGNAME or `whoami` + +Makefile.in,{lib/*,doc,builtins}/Makefile.in + - use `test' instead of `[' to conform to GNU coding standards + - `incdir' -> `includedir' as per latest GNU coding standards + +lib/readline/Makefile.in, lib/glob/Makefile.in + - use $(srcdir)/ instead of $(srcdir) in the CSOURCES variable + +general.h + - new define, FS_NODIRS, to not find directory names when searching + $PATH + +execute_cmd.c + - fix to find_in_path_element so it does not return directories + - executable_file() no longer returns directories as executable + + 2/27 + ---- +jobs.h + - new flag value: J_NOHUP + +jobs.c + - new function: nohup_job(job). Sets J_NOHUP flag for specified + job + - change hangup_all_jobs so that jobs marked J_NOHUP are not + sent SIGHUP. If stopped, the job still gets SIGCONT. + - changed calls to report_error to call internal_error, which will + not exit the shell + - changed FIND_CHILD define to call internal_error, restore the + SIGINT handler, set termination_state to 127 and return, rather + than aborting the shell + +builtins/jobs.def + - new option for disown: `-h'. Marks the specified jobs J_NOHUP. + +doc/{bash.{1,html},features.texi} + - added description of `disown -h' + +jobs.c, nojobs.c + - include some files needed for struct winsize by SCO + +lib/readline/input.c + - added some #ifdefs to avoid including on systems + with select but without + +configure.in + - check for , define HAVE_STDARG_H in config.h if found + +config.h.bot + - define USE_VARARGS and either PREFER_STDARG or PREFER_VARARGS + if one of or is present + +aclocal.m4 + - moved default mail directory check here from configure.in, macro + name is BASH_DEFAULT_MAIL_DIR + - rewrote BASH_CHECK_DEV_FD to cache the value + - minor fixes from Bruno Haible + +shell.c + - no longer includes + +builtins/Makefile.in + - add -I$(topdir)/builtins to list of includes + +execute_cmd.c, lib/glob/glob.c + - include memalloc.h for correct alloca definitions + +error.[ch], print_cmd.c, builtins/common.[ch] + - changes to include new ANSI-C stdargs code if PREFER_STDARG is + defined + + 2/28 + ---- +aclocal.m4 + - more minor fixes from Andreas Schwab + +doc/Makefile.in + - change TEXINPUTS makefile variables to TEXINPUTDIR to avoid + conflict with shell variable of the same name + +builtins/pushd.def + - fix to avoid a bad call to free after a call to + polite_directory_format does not change its argument string + +lib/readline/bind.c + - fixes to _rl_macro_dumper_internal so that it prints whatever + prefix it's passed, if any + + 2/29 + ---- +Makefile.in + - slight change to the rule for `stamp-h': it should be created by + running `config.status', not explicitly by the makefile rule + +builtins/Makefile.in + - replace `..' in the dependencies with `$(topdir)' + - replace `.' in the dependencies with `$(srcdir)' + + 3/1 + --- +Makefile.in + - add a rule to build builtins/builtext.h for the benefit of + deficient makes like the SunOS one + +variables.c + - fix to assign_in_env so that values in the environment are + properly null-terminated + +builtins/Makefile.in + - added dependencies for object files made from .c files in this + directory: common.o, getopt.o, bashgetopt.o. SunOS /bin/make + doesn't seem to be able to handle anything else + +support/mkclone + - new script to replace clone-bash that works from MANIFEST to link + only those files contained in a distribution + +support/mkversion.c + - change so that it doesn't try to get `.build' from the source + directory when that's different from the build directory + + 3/4 + --- +bashjmp.h + - #undef setjmp and longjmp before redefining them as sigsetjmp and + siglongjmp, respectively + +bashhist.c + - fixed an uninitialized variable problem in expand_histignore_pattern + +builtins/set.def + - used `on_or_off' where `value' was needed in minus_o_option_commands + +builtins/common.h + - added extern declaration for set_var_attribute + +print_cmd.c + - include `bashansi.h' instead of just string.h or strings.h + +builtins/*.def, builtins/common.c + - include `../bashansi.h' where appropriate + +parse.y + - fixed a parenthesization problem in alias_expand_token + +general.h + - added extern declaration for `ungetc_with_restart' + +lib/readline/readline.c + - renamed LibraryVersion to rl_library_version, made it extern, + assigned `2.1' to it + +lib/readline/readline.h + - extern declaration for `rl_library_version' + +lib/readline/doc/rltech.texinfo + - added description of `rl_library_version' + +lib/glob/glob.c + - changed call to sprintf in glob_dir_to_array to a couple of + calls to strcpy, since we keep the length of the first string + we copy + + 3/7 + --- +aclocal.m4 + - added new macro `BASH_FUNC_LSTAT' to check for lstat on Linux, + which defines it as an inline function in + +configure.in + - call BASH_FUNC_LSTAT if $ac_cv_func_lstat has value `no' + + 3/8 + --- +parse.y + - changed the occurrences of `list' in the if command productions + to use `compound_list' instead + + 3/11 + ---- +parse.y + - changed the occurrences of `list' in the while and until command + productions to use `compound_list' + +lib/readline/complete.c + - fix to filename_completion_function -- off-by-one error when + expand-tilde is enabled and a filename to be completed begins + with `~/' + + 3/12 + ---- +builtins/cd.def + - made the POSIX.2 behavior of PWD not containing symlinks after + using $CDPATH part of `posix mode', not default shell behavior + +lib/readline/display.c + - fix to update_line to handle update problems when using + horizontal scroll mode. This is a dumb update solution -- it + should use a better one + + 3/14 + ---- +examples/functions/csh-compat + - replaced the defintion for `alias' with a better one posted to + usenet by Mohit Aron + + 3/15 + ---- +jobs.c + - fix to wait_for_background_pids to keep `wait' from hanging + + 3/19 + ---- +lib/readline/input.c + - new function `_rl_input_available()' returns > 0 if there is + input available on the readline input file descriptor. Only + works if select(2) or FIONREAD are available + +lib/readline/isearch.c + - slight change to the isearch termination behavior -- ESC still + terminates the search, but if there is pending input or if input + arrives within 0.1 seconds (on systems with select(2)) it is + used as a prefix character with rl_execute_next + +shell.c + - the GNU coding standards say to write the output generated by + the --help command line option to stdout, not stderr + - show_shell_version now takes an `extended' option that displays + copyright information if non-zero + - show_shell_version now prints the value of `MACHTYPE' by default + - the `--version' option now causes the shell to exit successfully + after printing the extended version information + +externs.h + - changed prototype for show_shell_version + +shell.c, bashline.c, builtins/help.def + - changed calls to show_shell_version to add appropriate argument + +Makefile.in + - pass a `MACHTYPE' define to the compiler + + 3/22 + ---- +general.c + - changed print_timeval() and print_time_in_hz() to output three + fractional digits after the decimal point + +examples/loadables/sleep.c + - changed to an implementation that will sleep fractional portions + of seconds if select() is available + + 3/25 + ---- +builtins/shopt.def + - fixes to shopt -o from Andreas Schwab. Use FLAG_ON/FLAG_OFF + instead of SETOPT/UNSETOPT + + 3/26 + ---- +Makefile.in, builtins/Makefile.in + - use `@includedir@' instead of `@incdir' for autoconf 2.9 + +Makefile.in + - the `info', `dvi', and `ps' targets do not depend on `texindex' + - add a `dist' target that just prints a message describing how + distributions are constructed + +support/mkdirs + - replace uses of [...] with `test' + + 3/28 + ---- +parse.y + - fix for a problem with \@ prompt expansion from Tim Mooney + +jobs.c + - broke the code that prints a pipeline out into a separate + function: print_pipeline(). This gets called by + pretty_print_job and can be used for debugging + - two new functions to save and restore the_pipeline around calls + to make_child that you don't want to disturb the current pipeline, + for example in process substitution + +subst.c + - changed process_substitute to call save_pipeline and + restore_pipeline in the appropriate places + + 3/29 + ---- +general.c + - ansicstr now takes an additional parameter, the length of the + string to be translated. It's the second paramter. + +builtins/echo.def + - changed call to ansicstr to pass strlen(list->word->word) + +parse.y + - redid the $'...' expansion so it works like it's supposed to: + the quoted strings may appear anywhere in a token, and multiple + ansi-c quoted strings may appear in a token + - redid the $"..." expansion so it works like it's supposed to + +tests/nquote.{tests,right}, tests/run-nquote + - tests for the $'...' and $"..." quoting stuff -- simple-minded + +subst.c + - on systems without /dev/fd, open the named pipe for a `reading + in child' process substitution (>(...)) with O_NONBLOCK + +lib/posixheaders/filecntl.h + - add code to make sure the O_NONBLOCK is defined to O_NDELAY if + it is present and O_NONBLOCK is not defined by + +general.c + - don't bother handling both O_NONBLOCK and O_NDELAY in + unset_nodelay_mode, since filecntl.h defines O_NONBLOCK as + O_NDELAY for non-Posix systems + + 4/1 + --- +lib/readline/funmap.c + - made `vi-fetch-history' a bindable command name + +doc/readline.3 + - many cleanups, updated the list of default bindings + + 4/4 + --- +doc/bash.1, doc/readline.3 + - fixed up use of \-; now it is not used unless the text is being + printed in bold or italic + +configure.in, config.h.in + - add a configuration option, --enable-usg-echo-default, to turn + on DEFAULT_ECHO_TO_USG and make `echo' expand backslash-escaped + characters by default + + 4/8 + --- +parse.y + - another small change to localeexpand to handle backslash-escaped + double quotes in the double-quoted string + + 4/9 + --- +shell.c + - add the value of MACHTYPE to the text output by `--help' + + 4/11 + ---- +parse.y + - more changes to the $"..." and $'...' code to move it into + read_token + - don't try to check token[token_index - 1] unless token_index + is greater than 0 + + 4/12 + ---- +trap.c + - new function run_trap_cleanup to clean up after _run_trap_internal + in the event that parse_and_execute does not return normally + (e.g., if a `return' is executed in the trap command) + - set running_trap to the number of the signal whose trap is being + run plus one in _run_trap_internal + +trap.h + - extern declaration for run_trap_cleanup + +jobs.c + - new function `unfreeze_jobs_list' to set freeze_jobs_list back to 0. + called from parse_and_execute_cleanup so a `return' while running + an interrupt trap does not leave the jobs list frozen + +jobs.h + - new extern declaration for unfreeze_jobs_list + +builtins/common.c + - if running_trap is non-zero in parse_and_execute_cleanup, indicating + that parse_and_execute was running a trap command when it got a + `return', call run_trap_cleanup (running_trap - 1) + - parse_and_execute_cleanup now calls unfreeze_jobs_list + + 4/16 + ---- +Makefile.in + - don't try to make `doc' as a dependency of `install' + +doc/Makefile.in + - make `info' a dependency of `install' to make sure the info + document is present and up to date before installing it + - make the `install' target install the documents with a $(srcdir)/ + prefix in case we're building in another directory + +lib/glob/glob.c + - fixed an off-by-one error in glob_dir_to_array + +shell.c + - removed an extra increment of arg_index when setting up the + arguments for -c command + + 4/17 + ---- +pathexp.c + - made quote_globbing_chars backslash-quote backslashes as well as + `?*[]'; changed it to be a little faster + +bashhist.c + - call quote_globbing_chars to quote backslashes in the previous + history line even if no other globbing chars are present. This + is done only if we're matching against a HISTIGNORE pattern of `&' + - don't bother quoting globbing characters in the current history + line in history_should_ignore -- fnmatch ignores special chars in + its `string' argument + +[bash-2.0-alpha2 frozen] + + 4/18 + ---- +command.h + - new flag value for a word: W_NOSPLIT. A word with this bit set + in its flags will not have word splitting performed + +parse.y + - turn on the W_NOSPLIT flags for assignment statements appearing + where an assignment statement is acceptable (words that would + return ASSIGNMENT_WORD rather than WORD). This means that, for + the time being, assignment statement arguments to builtins like + `declare' or `alias' will be split unless they are quoted + +subst.c + - don't split a word in expand_word_internal if the W_NOSPLIT flag + is set, rather than checking W_ASSIGNMENT; do the same thing in + expand_word_list_internal + +builtins.h + - a new flag, ASSIGNMENT_BUILTIN, indicating that this builtin takes + assignment statements as arguments + - rearranged the values of the builtin flags, so the BUILTIN_* flags + come first, then the *_BUILTIN flags + +builtins/makebuiltins.c + - added code for an array of `assignment builtins' -- builtins that + take assignment statements as arguments -- and to add the + ASSIGNMENT_BUILTIN flag for those builtins + +execute_cmd.c + - added a hack function `fix_assignment_words', which checks the + first word of a builtin command to see if it is a builtin that + has the ASSIGNMENT_BUILTIN flag set, and adds W_NOSPLIT to the + flags for all words with the W_ASSIGNMENT bit set. This means + that word splitting is not done for any of the assignment + statements in commands like `declare z=$a' + + 4/19 + ---- +execute_cmd.c + - fixed a memory-freed-twice error in find_in_path_element + +lib/readline/rltty.c + - include if GWINSZ_IN_SYS_IOCTL is defined and + SHELL is not defined + +lib/readline/input.c + - changed a stray HAVE_FIONREAD to FIONREAD + - include if FIONREAD_IN_SYS_IOCTL is defined + +aclocal.m4 + - new macro, BASH_HAVE_FIONREAD, to check for a #define of + FIONREAD in or one of the files it includes; + defines FIONREAD_IN_SYS_IOCTL if present + +config.h.in + - new line for FIONREAD_IN_SYS_IOCTL + +configure.in + - call BASH_HAVE_FIONREAD + + 4/22 + ---- +builtins/cd.def + - fixed a memory-freed-twice error in mkpath() + +jobs.c + - don't print a job termination message for a non-interactive shell + with startup_state == 2 (those shells are started to run commands + when bash is invoked with `-c command') + + 4/23 + ---- +general.h + - definition for a `generic pointer' type PTR_T -- `void *' on ANSI + C systems, `char *' otherwise + +jobs.h + - new members of job struct: `j_cleanup', a function to call when the + job is marked JDEAD, and `cleanarg', argument to pass to j_cleanup + +jobs.c + - initialize j_cleanup and cleanarg to NULL in stop_pipeline + - call j_cleanup from waitchld() when a job is marked JDEAD + +test.c + - fixed binop() so it recognizes `<' and `>' as binary operators + - fixed a bug in binary_operator so `<' works correctly + +tests/test-tests + - fixed the tests so they no longer rely on the modes of files in + the file system to test -u, -g, -r, -x, -w, and so on, except + for a few `standard' files like /dev/tty and /dev/null + - added tests for string < string and string > string + +xmalloc.c + - include if HAVE_UNISTD_H is defined for a prototype + for sbrk + - add an extern declaration for sbrk if SBRK_DECLARED is not defined + - use PTR_T to cast the return value of sbrk() when finding out where + the break is and how many bytes of memory have been allocated + +lib/malloc/malloc.c + - added code to write 0xcf into memory as it's freed, to uncover + callers that try to refer to freed memory, and writes 0xdf into + newly-allocated memory, to uncover callers that assume something + about new allocations (e.g., that newmem[0] == 0) + +lib/malloc/gmalloc.c + - latest version from GNU sources + + 4/25 + ---- +doc/bash.1 + - changed the description of `unset' to include a description of + the `-v' option + +parse.y + - fixed a problem with conversion to 12-hour time in + decode_prompt_string that made 12:00pm show up as 00:00pm + + 4/26 + ---- +builtins/common.c, subst.c + - a couple of fixes from Andreas Schwab + +configure.in + - set up the minimal configuration after checking for + --enable-minimal-config with AC_ARG_ENABLE, before checking any + of the other options, instead of after checking all options. + This makes `--enable-minimal-config --enable-prompt-string-decoding' + work as documented + - changed AC_PREREQ to require autoconf version 2.8 or higher + - added some code to disable gnu malloc by default on the systems + listed in NOTES + - set MALLOC_SRC to have the $(ALLOC_LIBSRC)/ prefix to avoid having + a directory in the dependencies when making without the gnu + malloc + +lib/malloc/Makefile.in + - make gmalloc.o depend on $(BUILD_DIR)/config.h + + 4/30 + ---- +COMPAT + - new file listing user-visible incompatibilites between bash-1.14 + and bash-2.0 + +parse.y + - new prompt expansions, \v (version) and \V (version + patchlevel) + +config.h.top + - the default value of PS1 is now '\s-\v\$ ' + +doc/{bash.{1,html},features.texi} + - added descriptions of \v and \V prompt expansions + - changed default value of PS1 + +Makefile.in + - added dependencies on config.h.top for files that use definitions + included there + +builtins/exec.def + - removed reference to `no_exit_on_failed_exec' from the help text + + 5/3 + --- +builtins/cd.def + - fixed a typo in fix from 4/22 + + 5/7 + --- +builtins/common.c + - new function `no_options (WORD_LIST *)' to be called by builtins + that do not take options to check for options and -?. It returns + 0 on success, non-zero if an unwanted option is supplied + +builtins/common.h + - extern declaration for no_options + +builtins/return.def + - corrected the error message to include returning from a sourced + script + +builtins/{getopts,eval,wait,source,fg_bg,help}.def + - changed the following builtins to either call no_options or test + explicitly for options and return EX_USAGE if any are found: + + getopts eval wait source . fg bg help + +builtins/help.def + - error messages are now printed using builtin_error + + 5/8 + --- +builtins/jobs.def + - fixed an unitialized variable problem + +tests/more-exp.tests + - added additional tests for IFS problem uncovered by `iffe' + + 5/9 + --- +lib/malloc/Makefile.in + - use $(ALLOCA_SOURCE) instead of $< in rule that builds alloca.o. + Some makes don't expand the $< in non-suffix rules + +lib/readline/rldefs.h + - fix workaround for SVR4.2 bug + +shell.c + - even though SVR4.2 has getpeername(), isnetconn() should not use it + +maxpath.h + - rework to make sure PATH_MAX and NAME_MAX are defined, and remove + the BUILDING_MAKEFILE code + +general.c, parse.y, oslib.c, jobs.c, builtins/common.c, builtins/cd.def + - change uses of MAXPATHLEN to PATH_MAX + +examples/loadables/{{log,base,dir}name,tty,pathchk,tee}.c + - new loadable builtins: + + logname basename dirname tty pathchk tee + +configuure.in, config.h.in + - look for tzset(3), define HAVE_TZSET if found + +subst.c + - new special variable function, sv_tz, which calls tzset when + TZ is changed, if tzset(3) exists and the shell is compiled + to do prompt string decoding + +subst.h + - extern declaration for sv_tz + + 5/10 + ---- +builtins/echo.def + - only call printf if the string to print is non-null + - add an fflush(stdout) after the printf call to work around a + bug in SunOS 5.5 + + 5/16 + ---- +shell.c + - moved some variable declarations out of this file to more + logical places + +support/config.guess + - small fixes from rfg@monkeys.com + +version.c + - moved functions for getting, setting, and displaying shell version + information here from shell.c + +general.c + - moved set_lines_and_columns to variables.c + - moved getc_with_restart and ungetc_with_restart to input.c + - new function argv_to_word_list(), converts an array of strings + into a WORD_LIST + - renamed find_name_in_list to find_name_in_array to match rest + of functions that operate on arrays of strings + +configure.in, Makefile.in, jobs.c, nojobs.c + - changes so that jobs.c no longer includes nojobs.c, and the correct + object file (jobs.o or nojobs.o) is selected by configure + and substituted into the Makefile + +list.c + - new file, list manipulation functions from general.c + +externs.h, general.h + - moved extern declarations for functions defined in oslib.c and + list.c to externs.h from general.h + + 5/17 + ---- +locale.c + - new file, with locale code from parse.y and shell.c + +shell.c + - don't turn off job control if act_like_sh is set + - if an unknown option is supplied at startup or if -c is + supplied without an argument, exit with EX_USAGE + - call posix_initialize after parsing all the options, to + catch `bash -o posix' + - new functions: init_interactive(), init_noninteractive() + - exit with EX_NOTFOUND if a script argument is not found + - exit with EX_NOINPUT if a script file cannot be opened for + some reason + +shell.h + - new define for EX_NOINPUT exit status (126) + + 5/18 + ---- +lib/readline/bind.c + - fixed _rl_get_keyname() so that it properly handles C-\ and outputs + it as \C-\\ and C-" as \C-\". This fixes the improper binding + commands written by `bind -p' that caused weird things to happen + when people used the output of `bind -p' as a start for their + own inputrc files + - new function _rl_init_file_error to print error messages encountered + while parsing the inputrc file + - print out an error message if parsing an inputrc line and no closing + double quote is found for a key binding + +lib/readline/complete.c + - in rl_complete_internal, if the completion function results in + multiple matches, but none match up to even the first character, + use what the user typed in (which is presumably a glob pattern + that expanded into multiple files) as matches[0]. This makes + things like show-all-if-ambiguous work right, too + +oslib.c + - if we are providing our own version of getenv(), provide a function + _getenv() as well, which just calls getenv() + +builtins/ulimit.def + - #define _KERNEL before including if HPUX is + defined. This makes the full set of limits available on hpux + version 8 and above + +bashline.c + - new function, enable_hostname_completion, sets up readline to + perform or not perform hostname completion. Hostname completion + is on by default. + - don't attempt hostname completion in attempt_shell_completion() + unless perform_hostname_completion is set + +builtins/shopt.def + - add a `set_func' member to the shopt options structure, to provide + a hook for those variables that require a little more than just + toggling a variable on or off + - new shopt variable `hostcomplete', turns hostname completion on and + off + +doc/{bash.{1,html},features.texi} + - added description of new shopt `hostcomplete' variable + + 5/21 + ---- +sig.c + - don't try to save the shell history in termination_unwind_protect + if we're dying due to SIGABRT + +bashhist.c + - new functions: last_history_entry (static), last_history_line + +bashhist.h + - extern declarations for new functions in bashhist.c + +error.c + - have programming_error() report the last command in the history + before aborting + +builtins/fc.def + - if the editor returns a non-zero exit status when using `fc -e', + return immediately without trying to execute the commands, as + per Posix.2, 5.12.2 + - when using `fc -s', echo the command to be executed to stderr, + not stdout + +lib/readline/terminal.c + - new file, with all code related to termcap/terminfo + +lib/readline/{readline,rltty,display,util}.c + - moved functions dealing with termcap to terminal.c + +lib/readline/readline.c + - readline_initialize_everything now calls _rl_enable_meta_key() + to turn on the meta key, based on the value of _rl_enable_meta + (on by default) + +lib/readline/rltty.c + - do not enable and disable the meta key each time readline is + called; do it once at initialization + + 5/23 + ---- +bashhist.c + - when `hist_verify' is set, call re_edit with the expanded line, + not the original one, and do not print the results of the + expansion before re-editing + + 5/24 + ---- +support/config.guess + - recognize linux/sparc + +configure.in + - don't use GNU malloc on linux/sparc + +variables.c + - initialize a new $MACHTYPE variable to the value of MACHTYPE as + set by autoconf + +doc/{bash.{1,html},features.texi} + - documented $MACHTYPE + + 5/30 + ---- +builtins/ulimit.def + - allow the max vm size to be set via setrlimit() if RLIMIT_VMEM + is defined + + 5/31 + ---- +shell.h + - changed EX_USAGE to 258, EX_BADUSAGE is now 2 + - added a number of execution failure statuses, so that builtins + can indicate various failures. All are greater than 256, so + they cannot be returned by other utilities + +execute_cmd.c + - new function, builtin_status(), to translate the new return + status codes to something the shell can export + - changed execute_simple_command to call builtin_status after + execute_builtin_or_function to translate error codes if a + builtin is invoked. If a function or regular builtin is + invoked, all return values greater than EX_SHERRBASE get + translated to EXECUTION_FAILURE, with the exception that + EX_USAGE gets translated to EX_BADUSAGE. If a special + builtin failed with a status > EX_SHERRBASE, special_builtin_failed + is set to cause the shell to exit in POSIX mode + - changed execute_builtin_or_function to return EX_REDIRFAIL if + redirections fail + - changed execute_subshell_builtin_or_function to translate + EX_USAGE to EX_BADUSAGE if a builtin is executed + - set this_command_name to NULL in execute_for_command before binding + each member of the word list to the loop variable, to avoid + garbled error messages if the variable has the integer attribute + +builtins/{set,unset}.def + - return EX_USAGE instead of EXECUTION_FAILURE if a bad option is + supplied + +builtins/source.def + - return EX_USAGE instead of EXECUTION_FAILURE if the required + filename argument is missing + +builtins/setattr.def + - return EX_BADASSIGN if any assignment statements given as arguments + to readonly, export, etc. return failures (assignment to + non-identifier, assignment to readonly variable) + +builtins/declare.def + - don't allow `declare var=value' to assign value to a readonly + variable + +lib/readline/rldefs.h + - include if we're going to be using stdarg instead of + varargs + +lib/readline/display.c + - added `stdarg' version of rl_message + +lib/readline/readline.h + - changed extern declaration for rl_message to be in ANSI-C format + if __STDC__ is defined and we're using stdarg + +variables.c + - make sure this_command_name is set to null before calling + make_variable_value in assign_array_var_from_string so any + error messages are not garbled + + 6/2 + --- +builtins/common.c + - don't execute the command in parse_and_execute if -n has been + enabled and the shell is not interactive + - include flags.h for read_but_dont_execute + +[bash-2.0-alpha3 released] + + 6/5 + --- +subst.c + - array_length_reference and parameter_brace_expand_length now + return -1 on errors + - parameter_brace_expand now returns &expand_param_error if + paramter_brace_expand_length returns something < 0 + +variables.c + - assign_in_env now checks for assignments to readonly shell + variables and disallows them + + 6/6 + --- +xmalloc.c + - only do pointer arithmetic on pointers cast to (char *), since + it's not required that compilers support arithmetic on void * + +shell.c + - make sure is included with the same conditions + used to call getpeername(2) in isnetconn() + +parse.y + - added a new function, paren_match, to parse the contents of $(...) + constructs. This function correctly handles embedded quoted + strings, embedded command substitutions, embedded command + substitutions with embedded quoted strings, etc. The implementation + is much closer to that described in POSIX.2, section 3.6.3. + - changed read_token_word to call paren_match where appropriate + +subst.c + - rewrote extract_delimited_string so that it correctly understands + quoted strings inside command substitutions, a la paren_match + in parse.y. Corrected the description of the function's output + in the code. extract_delimited_string is now very recursive, and + does not try to do everything in one pass without recursion + + 6/7 + --- +test.c + - fixed three_arguments() to test the second argument for a valid + binary operator before checking whether or not the first argument + is `!'. This is what POSIX.2 says to do. + +lib/malloc/malloc.c + - don't compile in the memory scrambling code (#define MEMSCRAMBLE) + if NO_MEMSCRAMBLE is defined. + +configure.in + - define NO_MEMSCRAMBLE in LOCAL_CFLAGS for SCO 3.2v[45] + + 6/9 + --- +parse.y + - renamed paren_match to parse_matched_pair + - call parse_matched_pair to parse <(...) and >(...) constructs, + since those should be treated the same as $(...) for the purposes + of matching parens and skipping embedded quoted strings + + 6/13 + ---- +parse.y + - augmented parse_matched_pair + o fixed up backslash quoting and CTLESC handling after + backslashes + o match pairs of ${...} and $[...] inside double-quoted + strings or `` strings + o keep track of line number quoted string starts on for + better error messages + o push and pop delimiters when parsing quoted strings + inside $(...), ${...}, and $[...] for use by the + history code + o set EOF_Reached to 1 if we get an EOF before finding the + match closer + - rewrote read_token_word from scratch to use parse_matched_pair: + o shell quote characters use parse_matched_pair to find + the matching quote + o fixed up backslash parsing code + o compound array assignments use parse_matched_pair + o corrected all_digits and dollar_present computations, so, + for instance, 2''>/dev/null is no longer accepted as + identical to 2>/dev/null + o converted ${...} parsing to use parse_matched_pair + o removed printing of error messages about unmatched quotes; + now handled by parse_matched_pair + o converted $'...' and $"..." to use parse_matched_pair + o removed all of the delimited_xxx and dollar_xxx variables + and embedded_quoted_string + - modified report_syntax_error to regularize error messages: + o non-interactive shells and interactive shells running + scripts with `.' now always report line numbers + o unexpected EOF is always reported when EOF_Reached is true + o non-interactive shells no longer duplicate the script name + in error messages (e.g., `./z3: ./z3: line 3: syntax error') + +bashline.c + - make sure `newnames' is freed in _ignore_completion_names + +lib/readline/complete.c + - don't insert the first match on TAB completion in + rl_complete_internal() if matches[0] is the empty string -- + that will overwrite whatever the user has typed, if dequoting + what the user typed results in the empty string + +execute_cmd.c + - include if HAVE_LIMITS_H is defined for ARG_MAX + - only put the special environment variable for GNU getopt into + the environment if ARG_MAX exceeds 10240 + +subst.c + - rewrote extract_dollar_brace_string so that it fully obeys + the POSIX.2 rules for finding the closing `}' and uses + skip_{single,double}_quoted rather than trying to do it with + inline delimiters + - removed the INC_NEST and DEC_NEST defines + + 6/14 + ---- +jobs.c + - don't print status messages for background jobs that complete + successfully when running shell scripts + +builtins/shopt.def + - when using shopt -o as a synonym for set -o, make sure $SHELLOPTS + is updated + - make sure to update $SHELLOPTS when using shopt to set or unset + interactive comments + +execute_cmd.c + - fixed find_in_path_element to not return non-executable files + when FS_EXEC_PREFERRED is one of the flags, after saving such + a file as file_to_lose_on (fix from william@nscs.fast.net) + + 6/17 + ---- +lib/readline/complete.c + - after printing possible completions, all lines of a multi-line + prompt are redisplayed using rl_forced_update_display() + +subst.c + - in expand_word_internal, only do tilde expansion on words where + (flags & (W_ASSIGNMENT|W_QUOTED)) == W_ASSIGNMENT (unquoted + assignment statements) and contain unquoted `=~' or `:~', and + only if posixly_correct is off. POSIX.2 says that only the + assignments preceding the command name should be tilde-expanded. + + 6/18 + ---- +support/config.guess + - recognize the new Pyramid DC-OSx as `mips-pyramid-sysv4' + +configure.in + - set LOCAL_CFLAGS to -Xa for mips-pyramid-sysv4 as per + Peter Chubb + +subst.c + - variable assignment errors when there is not a command name + after the assignments now causes a non-interactive shell to + exit in POSIX.2 mode + +execute_cmd.c + - if the iteration variable in a for statement is a read-only + variable, a variable assignment error occurs. This causes + non-interactive shells to exit in posix mode, and a failure + status to be returned for other non-interactive shells and + interactive shells + - if the selection variable in a select statement is a read-only + variable, a variable assignment error occurs, with the same + consequences as a for statement variable assignment error + +doc/bashref.* + - renamed features.* to bashref.*, since that more accurately + reflects the current contents + + 6/19 + ---- +test.c + - changed three_arguments() to do one-argument tests on $1 and + $3 and return the appropriate values if -a or -o is given as + the second argument + - changed three_arguments() to perform a one-argument test on + $2 if $1 == '(' and $3 == ')' and return that result + - make sure test_stat translates /dev/fd/xx to DEV_FD_PREFIX/xx + so /dev/fd/0 always means the same thing, even on linux, + which uses /proc/self/fd + +aclocal.m4 + - added a check for libncurses in BASH_CHECK_LIB_TERMCAP + +configure.in + - added an initial message saying we're configuring for bash-2.0 + +lib/glob/fnmatch.c + - made a small change to fnmatch() to fix a bug matching patterns + with multiple consecutive `*'s + + 6/20 + ---- +parse.y + - inhibit history expansion when calling pre_process_line() from + shell_getc() if the current delimiter is a single quote, even + if we're on a different line than the opening quote + - make sure read_a_line prints a prompt if we're interactive and + not using readline, and make sure we call clearerr() if we + get EOF when interactive and not using readline + +bashhist.c + - new function history_expansion_p(char *) returns 1 if the string + passed contains the history expansion or history substitution + characters + - pre_process_line() now calls history_expansion_p and calls + the history expansion code only if that returns 1 + + 6/26 + ---- +lib/readline/isearch.c + - swap the behavior of ^J and ^M when i-searching. ^J now terminates + the search without accepting the line. ^M terminates the search + and accepts the line, executing the command + +examples/loadables/sprintf.c + - new `sprintf' builtin: sprintf var format [args...] + +lib/readline/readline.c + - added a line in _rl_dispatch that sets _rl_suppress_redisplay if + the function is rl_insert and there is input available + + 6/27 + ---- +builtins/getopts.def + - new function, getopts_bind_variable(), used when assigning a value + to the user-supplied variable passed to getopts(). It makes sure + that that variable name is legal and prints an error message if it + is not + +builtins/getopt.c + - don't increment sh_optind until after we've checked whether or not + the current option character appears in the list of options passed + to getopts by the user + + 6/28 + ---- +variables.c + - added a new parameter to print_var_value: QUOTE. If it's non-zero + and the variable's value contains shell metacharacters, quote the + value so it can be read back in + +variables.h + - changed extern declaration for print_var_value + +siglist.h + - if SYS_SIGLIST_DECLARED is not defined, but HAVE_UNDER_SYS_SIGLIST + is, only declare sys_siglist as extern char *sys_siglist[] if + sys_siglist is not `#define'd + +parse.y + - make sure a reserved word is acceptable before returning `}' as + a token from special_case_tokens, even if the token read so far + is "}" + - make reset_parser set allow_open_brace to 0 + + 7/1 + --- +test.c + - fixed binop to not try to read s[3] if s[2] == '\0'. There are + no one-character binary operators that begin with `-' + +variables.c + - fixed kill_all_local_variables to do nothing if variable_context + is >= local_variable_stack_size (indicating that we do have some + local variables, but not at this level of function nesting, and + we are beyond the end of the array allocated the last time we + had local variables) + + 7/2 + --- +execute_cmd.c + - non-interactive shells in posix mode should exit if the variable + in a for command is not a valid identifier. This should really + be caught by the parser + - non-interactive shells in posix mode should exit if a function + name is not a valid identifier. This should also be caught by + the parser + + 7/3 + --- +jobs.c + - non-interactive shells should ignore stopped children, so + waitchld() should set waitpid_flags to WUNTRACED only if the + shell is interactive and it's not a subshell environment + +lib/readline/signals.c + - if not being compiled as part of the shell, readline should + catch SIGTERM and clean up + +shell.c + - change to isnetconn: on Solaris 2.5, getpeername() can return + EINVAL rather than ENOTSOCK if the fd passed as the first + argument is not a socket + + 7/5 + --- +lib/readline/complete.c + - new variable, available to library users, to inhibit completion + and cause the completion character to be inserted into the + line with self-insert: rl_inhibit_completion. Set to 0 by default. + +lib/readline/readline.h + - extern declaration for rl_inhibit_completion + +lib/readline/doc/rltech.texinfo + - documented rl_inhibit_completion + +lib/readline/bind.c + - new readline user variable: disable-completion. This provides + users a way to toggle the value of rl_inhibit_completion + +doc/{bash.{1,html},readline.3}, lib/readline/doc/rluser.texinfo + - documented disable-completion variable + +lib/readline/doc/Makefile + - added `html' target to create html from rlman.texinfo and + hist.texinfo + + 7/8 + --- +builtins/cd.def + - only try cd spelling correction if the shell is currently + interactive, regardless of value of `cdspell' option + +lib/posixheaders/alloca.h + - AIX 4.2 needs `#pragma alloca' if gcc is not being used + + 7/9 + --- +builtins/getopts.def + - return EXECUTION_FAILURE from getopts if it's trying to assign + to a read-only variable + - reset sh_badopt to zero in getopts_reset() + +builtins/getopt.c + - new variable, sh_badopt, set to 1 if we find an illegal option + - do the increment of sh_optind if sh_badopt is non-zero and we're + at the end of the option string at the beginning of sh_getopt(). + The increment is deferred until the next call so $OPTIND is + correct + +builtins/getopt.h + - extern declaration of sh_badopt + + 7/10 + ---- +Makefile.in + - don't pass ALLOCA_SOURCE or ALLOCA_OBJECT to the make in lib/malloc + - don't make libmalloc.a depend on ALLOCA_DEP -- it causes some + compilers to build alloca.o in the top directory, and if ALLOCA + is not defined, makes the malloc library depend on a directory + +aclocal.m4 + - some small changes to make the output look better + +memalloc.h + - made some small changes suggested by the autoconf documentation + + 7/11 + ---- +parse.y + - swapped meanings of \h and \H in prompt_string_decode for + bash-1.14.6 compatibility + +doc/{bash.{1,html},bashref.texi} + - updated prompt string decoding section with swap of \h and \H + +general.c + - print_timeval and print_time_in_hz now accept a FILE * as the + first argument, so `times' can print to stdout while `time' + prints to stderr + +execute_cmd.c + - changed time_command to print the timing statistics to stderr + +builtins/times.def + - added the FILE * argument to the calls to print_timeval and + print_time_in_hz + +support/texi2html + - upgraded to version 1.50 + +error.c + - include bashhist.h if HISTORY is defined for declarations of + last_history_line() and remember_on_history + +lib/glob/glob.c + - add a `#pragma alloca' as the first thing in the file if we're + not using gcc and _AIX is defined + +lib/posixheaders/memalloc.h + - remove the `#pragma alloca' stuff; it is done in the C source + files now, to avoid problems with other AIX header file + declarations + + 7/12 + ---- +lib/readline/rltty.c + - some changes to work around AIX 4.2 bugs (sometimes OPOST is unset + in termios, sometimes FLUSHO is inexplicably set in termios, etc.) + + 7/15 + ---- +lib/readline/rltty.c + - make SETATTR use TCSADRAIN on POSIX machines. This setting is + supposed to be used for changes that affect output + +[bash-2.0-alpha4 released] + + 7/16 + ---- +trap.c + - changed reset_or_restore_signal_handlers to honor traps before + special signals, so that `trap "" 2' works right and causes + children to ignore SIGINT + +locale.c + - added lc_all variable to track the value of LC_ALL + - added new functions: set_default_locale_vars, set_locale_var, + set_lang, get_locale_var, removed get_current_messages_locale + +subst.h + - added extern declaration for sv_locale + +subst.c + - LC_ALL, LC_CTYPE, LC_MESSAGES, and LANG are now special variables; + sv_locale() is called when they are assigned a value + +shell.c + - call set_default_locale_vars after initializing the shell variables + in main(), so LC_CTYPE and LC_MESSAGES (if present) have values + - shell.c does not need to include + +general.c + - changed print_timeval and print_time_in_hz to format their output + as Posix.2 specifies for `time -p' if the new POSIX_TIME argument + is non-zero + +parse.y + - new grammar production: timespec, to handle `time' and `time -p' + - change to special_case_tokens so that -p after `time' returns + TIMEOPT + +execute_cmd.c + - set posix_time in time_command if the command's flags include + CMD_TIME_POSIX + - call print_timeval and print_time_in_hz with posix_time as + the new third argument + - use a space to separate the word (`real') and the time if we're + in posix mode. This is what POSIX.2 defines for `time -p' + +builtins/times.def + - call print_timeval and print_time_in_hz with 0 as the new third + argument + +command.h + - new flag: CMD_TIME_POSIX, used to handle `time -p' + +doc/{bash.{1,html},bashref.texi} + - documented `time -p' + + 7/17 + ---- +support/mkversion.c + - include `config.h' before any other include files + +parse.y + - initialize was_dollar to 0 in parse_matched_pair + +configure.in + - removed duplicate check for from call to + AC_HAVE_HEADERS + +sig.c + - include siglist.h so we can find out if it defines HAVE_SYS_SIGLIST + +siglist.h + - define HAVE_SYS_SIGLIST if we end up defining sys_siglist as + _sys_siglist (Solaris 2.[45]) + +siglist.c + - include "siglist.h" before testing whether or not HAVE_SYS_SIGLIST + is defined; it may be defined in there (Solaris 2.[45]) + + 7/19 + ---- +examples/misc/alias-conv.sh + - updated, now uses code from examples/functions/csh-compat to do + the alias conversion, uses `command' builtin in functions it + creates, does some substitution of csh special variables to + bash equivalents + +examples/misc/cshtobash + - a more ambitious script that attempts to convert csh aliases, + environment variables, and local variables to bash equivalents + + 7/22 + ---- +bashline.c + - added `:' to the set of completion word break characters so that + individual directories in $PATH assignments can be completed + +aclocal.m4 + - added a new macro, BASH_CC_WORKS, that aborts configuration if + ${CC} can't compile a simple program successfully + +configure.in + - call BASH_CC_WORKS before doing anything else + + 7/23 + ---- +execute_cmd.c + - fixed select_query to print the prompt ($PS3) to stderr + +support/bashbug.sh + - workaround for bug in SunOS 5.x /bin/sh that causes it to + not ignore interrupts while waiting for a foreground process + to exit + + 7/24 + ---- +general.c + - added new functions to decompose `timeval's and `clock_t's into + seconds and thousandths of seconds: timeval_to_secs and + clock_t_to_secs + - changed print_timeval and print_time_in_hz to call timeval_to_secs + and clock_t_to_secs, respectively + - removed no-longer-used third argument for print_timeval and + print_time_in_hz -- `time' output is now done in execute_cmd.c + +general.h + - new extern declarations for timeval_to_secs and clock_t_to_secs + +builtins/times.def + - changed calls to print_timeval and print_time_in_hz, removing the + no-longer-used third argument + +execute_cmd.c + - changed the way time_command prints its output: it now interprets + a format string, replacing several escape sequences prefixed with + a `%' with the real, user, and system times. There are options in + the format string to ask for the `long' format that `times' uses + as well as to specify the number of places after the decimal point, + and whether to output fractional seconds at all + - time_command now uses the value of the `TIMEFORMAT' variable, if + present, to format the timing output. This is flexible enough to + encompass the bash default, posix `time -p', BSD, and SV time + formats + + 7/25 + ---- +Makefile.in + - `make clean' should delete the files listed in $(CREATED_SUPPORT); + `make mostlyclean' should not + +doc/{bash.{1,html},bashref.texi} + - fixed an error in the description of the effect that setting and + unsetting GLOBIGNORE has on the setting of the `dotglob' option + +doc/bashref.texi + - updated the section listing the major differences between bash + and the SVR4.2 shell + +lib/readline/readline.c + - removed the setting of _rl_suppress_redisplay, since it doesn't + really do anything yet + +oslib.c + - new function get_clk_tck (void), returns the value of _SC_CLK_TCK + if sysconf(3) is available, otherwise returns the value of + CLOCKS_PER_SEC (default 60) + +general.c + - moved CLOCKS_PER_SEC defines to oslib.c + - changed clock_t_to_secs to call get_clk_tck once to get the + right value to use + +externs.h + - extern declaration for get_clk_tck + +execute_cmd.c + - changed print_formatted_time so that a `%' at the end of the string + is output literally + - changed print_formatted_time to output a newline after the + translated format string, so it does not need to be included in + the format + - changed BASH_TIMEFORMAT (the default time format) to have a leading + newline to match ksh93 + +configure.in + - use `shlicc2' on BSD/OS machines + + 7/26 + ---- +doc/bash.html + - major overhaul, cleaned up text, corrected some minor HTML errors + +variables.c + - call sv_optind and sv_opterr to initialize the getopts stuff in + initialize_shell_variables + + 7/29 + ---- +shell.c + - don't let maybe_execute_file try to read files that are not + `regular files' + + 7/30 + ---- +parse.y + - cast `string' in yy_string_get() to unsigned char * to avoid + sign extension bugs. For example, bash -c $'ls\377who' + + +builtins/reserved.def + - add help text for the `time' reserved word + - deleted description of `HISTCONTROL' + - added descriptions for HISTIGNORE, PWD, HOSTNAME, GLOBIGNORE, + MACHTYPE + + 7/31 + ---- +builtins/common.c + - parse_and_execute saves and restores the line number around + calls, and resets it to 0 when pushing the string onto the + input stack + +parse.y + - added code that parses `` within a double-quoted string as a + single word + + 8/6 + --- +configure.in, config.h.in + - look for `textdomain' as well as `gettext' for internationalization + +locale.c + - when LC_MESSAGES is set, call textdomain as well as setlocale + - new variable `default_domain', used to track the value of + $TEXTDOMAIN + +subst.c + - call sv_locale when TEXTDOMAIN changes + + 8/7 + --- +error.c + - new function, sys_error(), which prints a formatted string followed + by a colon and strerror(errno) to stderr + +error.h + - extern declaration for sys_error + +jobs.c, nojobs.c, input.c, execute_cmd.c, subst.c + - changes to use sys_error() + +[many files] + - changes to many of the literal strings in the code for consistency + and easier potential translation + + 8/8 + --- +parse.y + - new function debug_parser(int) to toggle the value of yydebug + if YYDEBUG != 0 + + 8/9 + --- +oslib.c + - don't use CLOCKS_PER_SEC, just try to get CLK_TCK (60 by default) + +bashline.c + - set saved_history_line_to_use to -1 when it's not going to be used + rather than 0. A value of 0 can be confused with the first + history line + +builtins/evalstring.c + - moved parse_and_execute and auxiliary functions here from + builtins/common.c + +builtins/evalfile.c + - moved maybe_execute_file here from shell.c + +Makefile.in, builtins/Makefile.in + - changes necessitated by the new files + + 8/12 + ---- +builtins/common.c + - fixed an off-by-one bug in single_quote that could make bash + run off the end of a string if it consisted entirely of single + quotes + + 8/13 + ---- +shell.c + - moved code from main() to a new function: open_shell_script + - don't try to fclose(default_input) if BUFFERED_INPUT is defined + - moved argument binding code out of two places in main() and + open_shell_script() to a new function: bind_args(). This takes + an additional argument telling whether to bind starting at $0 + or $1 + - moved the code that calls the with_input_from_* functions into + a new function: set_bash_input + - moved the normal shell command-line option parsing code out of + main() into a new function: parse_shell_options + - moved the long option parsing code out of main() into a new + function: parse_long_options() + +general.c + - new function: move_to_high_fd(fd), which tries to move FD to a + file descriptor close to the allowed maximum, returning the new + fd and closing the old one (or returning the old one if something + goes wrong) + +general.h + - new extern declaration for move_to_high_fd + +variables.c + - moved indirection_level_string() here from shell.c + +jobs.c + - change initialize_jobs to use move_to_high_fd() instead of the + inline code to do the same thing + + 8/14 + ---- +lib/readline/readline.c + - add `en_US.ISO8859-1' to the list of legal LANG values that turns + on readline's 8-bit mode + + 8/15 + ---- +builtins/evalfile.c + - combined source_file and maybe_execute_file into a new function + _evalfile(fname, flags), where the flags select the appropriate + behavior + +eval.c + - moved the functions that perform the read-eval loop here from + shell.c + +execute_cmd.c + - changed CPU calculation for printing timing statistics using + ideas and code from Deven Corzine (deven@ties.org) + +eval.c, builtins/evalstring.c + - make sure we dispose of global_command if set -n is on and the + shell is not interactive + + 8/16 + ---- +variables.c + - make a new array variable, BASH_VERSINFO, with version information: + + BASH_VERSINFO[0] = release (2) + BASH_VERSINFO[1] = version (00) + BASH_VERSINFO[2] = patch level (0) + BASH_VERSINFO[3] = build version (1058) + BASH_VERSINFO[4] = release status (beta1) + BASH_VERSINFO[5] = $MACHTYPE (sparc-sun-sunos4.1.4) + +doc/{bash.{1,html},bashref.texi} + - Documented BASH_VERSINFO + +configure.in, config.h.in + - look for bindtextdomain(), set HAVE_BINDTEXTDOMAIN if found + +subst.c + - call sv_locale if TEXTDOMAINDIR is set or changes + +locale.c + - handle TEXTDOMAINDIR in set_locale_var; call bindtextdomain if + it is present + +tests/array.tests + - added calls to egrep to filter out BASH_VERSINFO and PIPESTATUS, + which can vary from system to system + + 8/19 + ---- +shell.c + - moved line_buffer_stream from here to oslib.c, made it into a + replacement for setlinebuf() if that is not available + +externs.h + - extern declaration for setlinebuf() + +lib/readline/input.c + - in rl_gather_tyi, punt if chars_avail < 0 after checking input fd + + 8/20 + ---- +builtins/suspend.def + - send SIGSTOP instead of SIGTSTP + + 8/21 + ---- +builtins/colon.def + - added true and false as builtins (undocumented) + +CWRU/POSIX.NOTES, doc/bashref.texi + - note that process substitution is not available in posix mode + +bashintl.h + - new header file for internationalization, included by locale.c + + 8/22 + ---- +subst.c + - in command_substitute, set istring to NULL before trying to + make the pipe, so if that fails, the code at error_exit: + doesn't try to free it + +execute_cmd.c + - when executing a shell script without a leading `#!' internally, + and the shell is not interactive, close the fd to the script + we're reading. If this is called by the exec builtin, the shell + will not have forked, and the fd will not have been closed, even + though it's marked close-on-exec + - if subshell_argv is non-null, free its members (except 0) and + subshell_argv in shell_execve before reassigning it + - dispose of currently_executing_command before jumping back to + subshell_top_level + +builtins/hash.def + - use a sentinel variable so we only initialize the hash table + once in initialize_filename_hashing + +shell.c + - don't flush the filename hash table in shell_reinitialize + - free dollar_vars[0] in set_shell_name before assigning it + - don't fetch the current hostname more than once + - don't fetch the current user information more than once unless + the uid changes + +parse.y + - initialize_bash_input should free bash_input.name if it is + non-null before zeroing it + + 8/23 + ---- +aclocal.m4 + - changed BASH_CHECK_SOCKLIB: if -lsocket is present, check for + and cache the existence of -lnsl. Define LIBS appropriately + based on the values of the cache variables rather than relying + on the autoconf tests to do it + + 8/26 + ---- +parse.y + - fix up yy_readline_get and yy_stream_get to fix the sign + extension problem + +shell.c + - move the setjmp(top_level) that catches early SIGINTs to the + first statement in main() + +Makefile.in + - added a `strip' target to strip the binary + +[bash-2.0-beta1 frozen] + + 8/27 + ---- +parse.y + - replaced several static state variables with a single flags word: + parser_state + + 8/28 + ---- +parse.y + - in read_token_word, combined the ${...} case with the other + expansion cases -- the code was identical + - added code to handle ksh-style ((...)) -- equivalent to + `let "..."'. In fact, the above construct is translated internally + into `let "..."', so error messages output by the evaluator + will contain `let' + +expr.c + - changed evalerror to call internal_error so the name of the + shell script is prefixed to the message, if necessary + +Makefile.in + - changed RELSTATUS to `beta2' + +tests/{arith,new-exp}.{tests,right} + - changed the expected error message because of the change in format + of the arithmetic evaluation error messages in expr.c + +builtins/pushd.def + - changed pushd_builtin so `pushd -' is equivalent to `pushd $OLDPWD' + +externs.h + - changed the extern declaration for setlinebuf() to avoid having + to include stdio.h before externs.h everywhere + + 8/29 + ---- +error.c + - new function, parser_error, for use by parts of the parser that + don't want to call report_syntax_error + +error.h + - extern declaration for parser_error + +parse.y + - changed some parts of the parser to use parser_error + - made the ((...)) code #ifdef'd on DPAREN_ARITHMETIC + +shell.c + - added a line to the --help output saying to use `bashbug' to + report bugs + +configure.in + - added new option: --enable-dparen-arithmetic; it controls + the DPAREN_ARITHMETIC define in config.h + - changed $host_os check for SCO to only enable -DWAITPID_BROKEN + for sco3.2v5; all other SCO versions enable -DMUST_UNBLOCK_CHILD + +config.h.in + - added line for DPAREN_ARITHMETIC, modified by configure + +doc/{bash.{1,html},bashref.texi} + - documented new ((...)) command and new configuration option + +execute_cmd.c + - shell_execve should not try to close default_buffered_input unless + it is >= 0. Other code that closes it and deallocates the buffer + should set default_buffered_input to -1 + + 8/30 + ---- +configure.in + - more changes to LOCAL_CFLAGS for sco machines + +error.c + - changed parser_error to handle all cases of the shell being + interactive, not interactive, reading from a script, and reading + from some other file + +parse.y + - changed report_syntax_error to call parser_error for consistent + messages + +dispose_cmd.c + - change dispose_command to use programming_error instead of + report_error + +execute_cmd.c, input.c, general.c + - changed calls to report_error to internal_error, since we don't + want to possibly exit in any of those cases + + 9/3 + --- +input.c + - changed the `localbuf' type to `unsigned char' + +parse.y + - changed yy_stream_get to use feof to test for end of file when + not using getc_with_restart + + 9/6 + --- +config.h.top + - added a commented-out define for SYS_BASH_LOGOUT, which is a + system-wide .bash_logout file, run when a login shell exits + - added /sbin to STANDARD_UTILS_PATH + +builtins/exit.def + - added support for SYS_BASH_LOGOUT + + 9/10 + ---- +lib/readline/{{chardefs,histlib}.h,{bind,histexpand,readline,util,vi_mode}.c} + - changed to_upper to _rl_to_upper and to_lower to _rl_to_lower + - changed digit_value to _rl_digit_value + - changed digit_p to _rl_digit_p + - changed uppercase_p and lowercase_p to _rl_uppercase_p and + _rl_lowercase_p respectively + - changed pure_alphabetic to _rl_pure_alphabetic + +support/zecho.c + - new file, implements a bare-bones echo (no -n, no \-escapes), + to be used by tests + +tests/rhs-exp.tests + - changed calls to echo to use recho to avoid errors when bash is + configured with --enable-usg-echo-default + +tests/more-exp.tests + - changed some calls to echo to use zecho to avoid errors when bash + is configured with --enable-usg-echo-default + + 9/11 + ---- +lib/readline/histexpand.c + - fixed a possible off-by-one error in history_expand_internal when + deciding whether or not to reallocate `result' + +expr.c + - fixed expcond() so that an assignment may be supplied as the + token after the `?' + - illegal bases now cause an evaluation error + - multiple base specifications now cause an evaluation error + +tests/arith.tests + - added more tests for conditional operator and associativity + +tests/{run-heredoc,heredoc.{tests,right}} + - new set of tests for here-documents + +builtins/common.c + - print out the name returned by get_name_for_error in + builtin_error() + +subst.c + - set this_command_name to NULL before processing command-line + assignment statements so arithmetic evaluation errors don't + print garbage + - according to POSIX.2, echo ${foo?$x} should print the expanded + value of $x, even when it doesn't expand into anything + + 9/12 + ---- +shell.c + - changed the execution of startup files so that $ENV is never + run by a non-interactive shell and an interactive shell begun + as `sh' reads and executes $ENV, as posix specifies + +doc/{bash.{1,html},bashref.texi} + - updated description of startup file behavior + +doc/Makefile.in + - make sure references to bashref.texi are preceded by $(srcdir)/ + so we can build the documentation in another directory just by + typing `make'; e.g. after giving configure the --srcdir option + +subst.c + - change to array_remove_pattern to avoid evaluating the `param' + part of the ${param#word} spec twice when doing things like + echo ${A[x=(i+=1)]#${A[y=(i+=2)]}} + + 9/13 + ---- +builtins/bashgetopt.c + - fixed a problem with `;' option specifier (optional argument) + +support/config.{sub,guess} + - added cases to recognize CRAY C90 and T90 + +builtins/ulimit.def + - rewritten almost from scratch to use internal_getopt and to not + mask the return value from getrlimit/setrlimit, and to make it + easier to maintain + - added `-l' option for systems with RLIMIT_MEMLOCK (4.4 BSD) + +doc/{bash.{1,html},bashref.texi} + - documented new `-l' option to `ulimit' + + 9/24 + ---- +parse.y + - added `in' to the list of tokens that should not be followed by + a semicolon when combining history lines + - removed the special-case code in history_delimiting_chars that + tried to be smart about `()' + + 9/25 + ---- +print_cmd.c + - fixes to print_group_command from Andreas Schwab + - rewrote indent() to use a single malloced string for the spaces + to print, rather than calling cprintf multiple times + +shell.c + - make sure to set the strings in current_user to NULL after freeing + their contents in uidget(). + +parse.y + - make sure decode_prompt_string quotes the values inserted by the + \w and \W escape sequences using backslashes if the string will be + expanded later because promptvars is set + +support/mkdirs + - removed leading `^' from regular expressions to be matched by + `expr' on the advice of meyering@appaloosa.asic.sc.ti.com + + 9/26 + ---- +parse.y + - added a few more possible flag values for parser_state + - changed history_delimiting_chars to not add a semicolon after a + right paren if we're parsing a case statement + + 9/27 + ---- +builtins/ulimit.def + - a few minor cleanups + + 10/1 + ---- +builtins/trap.def + - make sure first_arg is non-empty before calling signal_object_p() + +[bash-2.0-beta2 frozen] + + 10/2 + ---- +bashintl.h + - if we have setlocale(), but don't have a definition for LC_ALL, + undefine HAVE_SETLOCALE + +configure.in + - set LOCAL_LDFLAGS on AIX 4.2 to allow dynamic loading of builtins + +builtins/enable.def + - use correct flags for AIX 4.2 in dlopen call if _AIX is defined + +examples/loadables/Makefile + - add sample commands for AIX 4.2 + + 10/3 + ---- +variables.c + - new functions: merge_temporary_env(), merge_builtin_env(), to + take temporary_env and builtin_env, respectively, and create + shell variables from them + +variables.h + - new extern declarations for merge_temporary_env() and + merge_builtin_env() + +execute_cmd.c + - if variable assignments preceds a posix special builtin, and the + shell is in posix mode, those assignments should persist in the + shell environment after the builtin completes + +doc/bashref.texi + - modified description of what's changed by posix mode to include + the persistance of assignment statements preceding special builtins + +doc/mkposix + - new script to create CWRU/POSIX.NOTES directly from the `Bash + POSIX Mode' node of bashref.texi, like INSTALL is created + + 10/4 + ---- +lib/{malloc,glob,readline}/Makefile.in, builtins/Makefile.in + - don't have autoconf substitute LOCAL_CFLAGS into the CFLAGS + assignment so people on SCO 3.2v[45] can still build with + NO_MEMSCRAMBLE even when they run `make CFLAGS=...' + +test.c + - renamed eaccess() to test_eaccess() to avoid conflict with SCO + +config.h.bot + - #undef HAVE_GETCWD if GETCWD_BROKEN is defined, so we use the + replacement in getcwd.c + +general.c + - fixed a small memory leak in full_pathname that occurs if + getcwd() returns NULL + +oslib.c + - new constant string variable: bash_getcwd_errstr, to use when + getcwd() returns NULL + +{general,jobs}.c, parse.y, builtins/{cd.def,common.c} + - change calls to getwd() to use getcwd() instead + +general.c, builtins/common.c, builtins/cd.def + - changed error behavior when getcwd() returns NULL to use + bash_getcwd_errstr, sys_error(), and strerror(errno) where + appropriate + +sig.c + - change a couple of calls to signal to set_signal_handler + +aclocal.m4 + - added definitions of _popen and _pclose to the BASH_FUNC_GETCWD + macro + +configure.in + - added -DPATH_MAX=1024 to LOCAL_CFLAGS for sco3.2v[45] on the + advice of + - removed check for getwd(3) + +externs.h + - removed extern declaration for getwd(), added extern declaration + for getcwd() if HAVE_GETCWD is not defined + +oslib.c + - removed definition of getwd(); it is no longer used + +lib/readline/rltty.c + - changed SETATTR macro for SCO POSIX systems to call tcsetattr + with TCSANOW, on advice of + + 10/7 + ---- +support/mkdirs + - slight change to work around a bug in the HP-UX `expr' + + 10/8 + ---- +lib/readline/vi_mode.c + - changes so that the text inserted with an `i' command is available + to be reinserted with `.' + +examples/functions/autoload.v2 + - new implementation: uses arrays, keeps a list of autoloaded + functions, allows autoloaded functions to be removed, allows + autoloaded functions to be listed + +execute_cmd.c + - when freeing the members of subshell_argv in shell_execve(), free + only the members up to subshell_argc + + 10/9 + ---- +configure.in + - replaced calls to AC_HAVE_FUNCS with AC_CHECK_FUNCS + - replaced calls to AC_FUNC_CHECK with AC_CHECK_FUNC + - replaced calls to AC_HAVE_HEADERS with AC_CHECK_HEADERS + - added additional code to check for libintl.{a,so} for the + internationalization functions if bindtextdomain is not found + in libc + - define HAVE_WAIT3 if AC_FUNC_CHECK(wait3,...) succeeds, rather + than HAVE_FUNC_WAIT3, which is not used in the source + - added a call to AC_FUNC_STRCOLL to check for the presence of a + working strcoll(3) + +config.h.in + - removed HAVE_FUNC_WAIT3 + - added HAVE_STRCOLL + +variables.c, stringlib.c + - move sort_char_array from variables.c to stringlib.c + +variables.h, externs.h + - move extern declaration of sort_char_array from variables.h to + externs.h + +variables.c + - don't sort the exported environment, even when we're not in + posix mode + +stringlib.c + - changed qsort_string_compare to use strcoll(3) if it is available + (HAVE_STRCOLL is defined). This means that the results of glob + expansions are now sorted in the per-locale collation order + +locale.c + - track the value of $LC_COLLATE and call setlocale(LC_COLLATE,...) + when it changes. Also, set its default value + +subst.c + - LC_COLLATE is now a special variable; call sv_locale when it is + assigned to or unset + +lib/readline/util.c + - move compare_strings here from complete.c; renamed it + _rl_qsort_string_compare; made it use strcoll(3) if it's + available; made it global so other library files can use it + +lib/readline/complete.c + - use _rl_qsort_string_compare instead of static compare_strings. + This means that completions are now sorted in a locale-specific + collation order + +lib/readline/funmap.c + - removed static declaration of qsort_string_compare; qsort now + uses _rl_qsort_string_compare instead + +oslib.c + - rewrote stricmp, strnicmp; renamed them strcasecmp and + strncasecmp, since they're only compiled in if HAVE_STRCASECMP + is not defined + +externs.h + - removed extern declarations of strnicmp, stricmp, replacing them + with declarations of strcasecmp and strncasecmp if HAVE_STRCASECMP + is not defined; removed #defines of stricmp and strnicmp to + strcasecmp and strncasecmp + +trap.c + - changed calls to stricmp to direct calls to strcasecmp + +Makefile.in + - bumped RELSTATUS to `beta3' + +doc/bash.{1,html} + - added mention of LC_COLLATE + +doc/bashref.texi + - removed item about sorting environment from the section on posix + mode + + 10/16 + ----- +subst.c + - fixed array_length_reference to return 0 for an unbound variable + and 1 for a variable that is not an array + +examples/scripts.v2/cdhist.bash + - package with functions to replace cd and maintain a cd directory + stack + +examples/scripts.v2/pmtop + - a `poor man's top' for SunOS 4.x and BSD + +examples/scripts.v2/bashrand + - a script to return a random number within a specified range, with + an optional seed + +examples/scripts/zprintf + - printf(1) replacement that uses gawk to do the output + +doc/{bash.{1,html},bashref.texi}, lib/readline/doc/hsuser.texinfo + - several small corrections + + 10/17 + ----- +variables.c + - changed the calls to list_string_with_quotes and then + expand_words_no_vars in assign_array_var_from_string to a single + call to expand_string. This behaves more rationally, and closer + to ksh93 + +subst.c + - commented out list_string_with_quotes -- it is no longer used + +lib/readline/terminal.c + - new function, _rl_set_screen_size(int rows, int cols), to set + readline's idea of the screen size + +jobs.c, nojobs.c + - make sure that window size changes are propagated back down to + the readline code, by calling _rl_set_screen_size with the + new sizes. This happens when bash gets a SIGWINCH or if + `checkwinsize' is set with `shopt' + + 10/18 + ----- +support/config.guess + - added code to recognize the various NetBSD ports + +lib/readline/signals.c + - don't install a handler for SIGALRM if the containing application + has installed a handler with SA_RESTART as part of the flags. + This is in effect, obviously, only for systems with POSIX signals. + +subst.c + - make parameter_brace_expand_length expand variables in a double- + quoted environment so it takes spaces in the variable value into + account + + 10/21 + ----- +command.h + - flags for possible values of subshell_environment telling what + caused the subshell + +builtins/command.def + - the `command' builtin should not be setting CMD_NO_FORK at all; + it doesn't know enough about the execution context to do so + +execute_cmd.c, subst.c + - set subshell_environment to one of the values in command.h rather + than to `1', so we know what kind of subshell it is (just for + informational purposes; nothing actually uses this yet) + + + 10/22 + ----- +execute_cmd.c + - just return EXECUTION_SUCCESS immediately in execute_command_internal + if read_but_dont_execute is set + + 10/23 + ----- +general.c + - fixed check_dev_tty to return immediately if ttyname() returns NULL + +builtins/suspend.def + - SIGSTOP cannot be caught, so there's no reason to try to do so + +examples/loadables/{finfo,pathchk,print}.c + - minor fixes + +pathexp.c + - fix to off-by-one error in setup_ignore_patterns + +jobs.c + - try to set the tty pgrp to our pgrp if we change our pgrp to our + pid and become a process group leader. If it doesn't work, + reset our pgrp to what it was originally and disable job control + +aclocal.m4 + - new test, BASH_STRUCT_TERMIO_LDISC, to test for a c_line member + of struct termio + +config.h.in + - add a new preprocessor variable, TERMIO_LDISC, undefined by default + +configure.in + - call BASH_STRUCT_TERMIO_LDISC after BASH_STRUCT_TERMIOS_LDISC + + 10/25 + ----- +lib/readline/terminal.c + - increased the size of the termcap buffers to 4096 + + 10/29 + ----- +parse.y + - include memalloc.h for uses of alloca that the code in the + generated bison parser does not catch (e.g., HP-UX 10.10) + +aclocal.m4 + - new test, BASH_KERNEL_RLIMIT_CHECK, to check whether a given + HP-UX machine needs _KERNEL defined for the RLIMIT_* defines in + (9.05, 10.01 yes, 10.10,10.20 no) + +configure.in + - call BASH_KERNEL_RLIMIT_CHECK if $host_os begins with `hpux' + +config.h.in + - new #undef for RLIMIT_NEEDS_KERNEL + +builtins/ulimit.def + - only define _KERNEL before including if HPUX + and RLIMIT_NEEDS_KERNEL are both defined + +[bash-2.0-beta3 frozen] + + 11/1 + ---- +locale.c + - if setting LC_ALL to a null value (as is done when `unset LC_ALL' + is run), call setlocale() to set LC_ALL back to default_locale + +lib/readline/readline.c + - moved i18n code from here to nls.c + +lib/readline/Makefile.in, Makefile.in + - new readline library member, nls.c + +lib/readline/nls.c + - new file, with internationalization code from readline.c (such as + it is) + - updated legal_lang_values to just contain a list of codesets + - added code modified from a diff sent by Ulrich Drepper + to parse a locale specification and isolate + and normalize the codeset part, for checking against the values + in legal_lang_values + + 11/4 + ---- +builtins/setattr.def, locale.c, aclocal.m4, oslib.c + - minor cleanups + + 11/5 + ---- +lib/readline/complete.c, test.c, trap.c + - more minor cleanups + + 11/6 + ---- +parse.y + - added a `flags' parameter to parse_matched_pair, currently unused + + 11/7 + ---- +configure.in, config.h.in + - add a check for time_t, defaulting to `long' if it's not + defined in + +builtins/fc.def + - use `time_t *' instead of `long *' in call to time() + + 11/8 + ---- +configure.in + - removed check for getpwent in libsun.a; it's not necessary for + recent versions of irix (irix[56].?) + + 11/11 + ----- +test.c + - used `&&' where `||' was needed when testing if HAVE_LSTAT and + S_IFLNK are both defined + +[bash-2.0-beta3 net release version frozen] + + 11/12 + ----- +builtins/getopt.c + - when sh_getopt detects that a required argument is not present, + set sh_optarg to "" so that getopts does the right thing + + 11/15 + ----- +builtins/ulimit.c + - made the default (without -H or -S) report the soft limit and set + both soft and hard limits (like sh and ksh) + +expr.c + - changed the maximum base in base#num constants to 64, implemented + just like ksh93 + +doc/{bash.{1,html},bashref.texi} + - updated description of ulimit builtin to new behavior when + neither -H nor -S is supplied + - updated arithmetic evaluation section with new maximum base and + explanation of how numbers between 10 and 63 are represented + +lib/readline/vi_mode.c + - in rl_vi_done_inserting, don't try to save the text entered while + in insert mode unless rl_undo_list is non-null (indicating that + there was actually some text to be saved) + + 11/19 + ----- +lib/readline/tcap.h + - new file, for termcap library definitions. Uses if + it is available + +lib/readline/rldefs.h + - remove inclusion of termcap.h; now included in tcap.h + +lib/readline/{terminal,display,readline}.c + - include tcap.h + +lib/readline/Makefile.in + - update dependencies to include tcap.h + + 11/21 + ----- +lib/readline/complete.c + - broke the code that computes the lcd of the list of completion + matches out into a separate function, compute_lcd_of_matches() + +lib/readline/complete.c + - call compute_lcd_of_matches after calling the application-specific + completion ignore function, since it may have eliminated some + names from the match list + +builtins/cd.def + - replaced instances of MAXNAMLEN in the spelling correction code + with PATH_MAX + +lib/readline/terminal.c + - new termcap capabilities: kh (sent by Home key) and kH (sent by + End key) automatically bound to beginning-of-line and end-of-line + respectively in emacs_standard and vi_movement maps + +mailcheck.c + - fix to remember_mail_dates so any message following the + filename is saved correctly + + 11/22 + ----- +lib/readline/bind.c + - fixed extern declaration of _rl_parsing_coditionalized_out + to match declaration in readline.c + + 11/25 + ----- +doc/{bash.{1,html},bashref.texi} + - fixed a gross documentation error in the description of + ${parameter:offset:length} (offset and length were transposed) + - slight changes to the description of output redirection + +subst.c + - new function, quoted_substring, to return substrings of variables + when the expression is within double quotes and the value has + CTLESC characters embedded within it. Called by + parameter_brace_substring + - get_var_and_type should return VT_POSPARMS if `*' is passed as + the variable name + - added a new first parameter for pos_params -- the variable name + - changed pos_params to obey the rules for "$*" wrt using the + first character of IFS as the separator in the result + - if an unquoted $* or $@ is expanded, call quote_escapes on the + result to protect any special characters from inadvertently + causing quoting + + 12/3 + ---- +builtins/ulimit.def + - corrected a misspelling of `unlimited' + - added support for linux RLIMIT_AS resource limit for -v option + and changed the block multiplier to 1024 if we have RLIMIT_VMEM + or RLIMIT_AS + + 12/5 + ---- +lib/readline/readline.c + - fix rl_insert to handle a count of exactly 1024 + +shell.c + - new function: unbind_args(), which removes all the positional + parameters. Just calls remember_args(NULL, 1) + +execute_cmd.c + - call unbind_args when executing a subshell, after setting up + subshell_argX + +bashintl.h + - include if HAVE_LIBINTL_H defined + +config.h.in + - add HAVE_LIBINTL_H define + +configure.in + - add call to AC_CHECK_HEADERS for libintl.h + +doc/Makefile.in + - added infodir and various mandir defines for completeness + +Makefile.in + - changed some of the *dir defines to use the autoconf values + (e.g., bindir = @bindir@) + - changed manroot to mandir, removed old mandir and manext variables + - added `manpfx' variable; should be either `man' or `cat' + + 12/6 + ---- +lib/readline/readline.c + - fixed rl_digit_loop so it once again displays the argument count + as it's being entered (added calls to _rl_save_prompt and + _rl_restore_prompt) + + 12/7 + ---- +support/config.guess + - recognize netbsd/vax + - recognize openbsd on all supported platforms + - recognize tenon's machten running on powerpc and macintosh + + 12/9 + ---- +support/config.guess + - added all sorts of systems from config.guess distributed with + autoconf-2.12 + + 12/10 + ----- subst.c - - made an efficiency improvement to dequote_string -- don't - do anything when we see CTLESC, just `continue' the loop + - new function quoted_strchr(); does the same thing as strchr but + honors shell backslash and CTLESC quoting conventions + - parameter_brace_patsub now calls quoted_strchr + + 12/11 + ----- +shell.c + - if the shell is named `-su', run the normal login shell startup + files, even if the shell is not interactive. This handles the + case of `su - username -c command' compatibly + +lib/readline/readline.c + - minor change to rl_digit_loop so that M-- and M--1 are equivalent, + as the prompt for digit arguments has always implied + +lib/malloc/malloc.c + - added definitions of calloc() and cfree(), compiled in unless + NO_CALLOC is defined to cpp + + + 12/16 + ----- +parse.y + - protect uses of history_expansion_inhibited with #ifdef + BANG_HISTORY + +[bash-2.0-release candidate frozen] + +builtins/common.c + - changed backslash_quote to quote a tilde if it's the first + character in the string + + 12/17 + ----- +aclocal.m4 + - changed BASH_CC_WORKS to provide a cross-compiling default for + better error messages + +configure.in + - generated configure using autoconf-2.12 + - changed the default value of CFLAGS to `-g -O2' + + 12/18 + ----- +aclocal.m4 + - look for /var/spool/mail before /usr/spool/mail when checking + for the default mail directory + +jobs.c, builtins/shopt.def + - fixed a couple of `macro replacement within a string literal' + problems + +Makefile.in + - removed `realclean' target + +shell.c + - changed the first line ouput by bash --version to conform to + the latest GNU coding standards (replace space between version + and machtype with a hyphen) + + 12/19 + ----- +execute_cmd.c + - when looking at the debug trap in execute_function and + execute_command_internal, make sure it's trapped and not + ignored before trying to save the value of the trap string + + 12/20 + ----- +trap.c + - changed set_signal and ignore_signal to handle EXIT_TRAP and + DEBUG_TRAP specially, so we don't try to fetch signal handlers + or do other unnecessary things + + 12/22 + ----- +builtins/ulimit.def + - if the current euid is not 0, and we're trying to set the hard + limit of a resource to RLIM_INFINITY, set it to the current hard + limit to avoid error messages + +builtins/read.def + - fix for bug that caused core dump if line read had leading white + space and IFS was set to '' + +[bash-2.0-release frozen] diff --git a/CWRU/mh-folder-comp b/CWRU/mh-folder-comp new file mode 100644 index 0000000..905000c --- /dev/null +++ b/CWRU/mh-folder-comp @@ -0,0 +1,449 @@ +From jwe@che.utexas.edu Wed Sep 21 17:23:40 1994 +Flags: 10 +Return-Path: jwe@che.utexas.edu +Received: from po.CWRU.Edu (root@po.CWRU.Edu [129.22.4.2]) by odin.INS.CWRU.Edu with ESMTP (8.6.8.1+cwru/CWRU-2.1-ins) + id RAA04010; Wed, 21 Sep 1994 17:23:39 -0400 (from jwe@che.utexas.edu for ) +Received: from life.ai.mit.edu (life.ai.mit.edu [128.52.32.80]) by po.CWRU.Edu with SMTP (8.6.8.1+cwru/CWRU-2.2) + id RAA02121; Wed, 21 Sep 1994 17:23:28 -0400 (from jwe@che.utexas.edu for ) +Received: from schoch.che.utexas.edu by life.ai.mit.edu (4.1/AI-4.10) for chet@po.cwru.edu id AA09989; Wed, 21 Sep 94 17:23:17 EDT +Received: from localhost (jwe@localhost) by schoch.che.utexas.edu (8.6.8.1/8.6) with SMTP id QAA05737; Wed, 21 Sep 1994 16:22:01 -0500 +Message-Id: <199409212122.QAA05737@schoch.che.utexas.edu> +To: march@tudor.com +Cc: bug-bash@prep.ai.mit.edu +Subject: Re: Completion feature possible? +In-Reply-To: Your message of 21 Sep 94 13:30:22 EDT +Date: Wed, 21 Sep 94 16:22:00 EDT +From: John Eaton + +Gregory F. March wrote: + +: I was having a discussion about MH with one of my friends the other +: day and I got to thinking that the +folder/subfolder scheme for naming +: mail folders is a real pain because completion doesn't work on +: them. Someone then mentioned that zsh (I think) has the ability to +: specify how to complete (I guess where to look for the files) for +: different prefixes. Bash right now knows about '@', '~', and '$' (any +: others?). It would be really helpful if one could define something +: like: +: +: completion '+' "$HOME/Mail" +: +: in a config file someplace. Would this be easy? Is there a list of +: TODO item that someone might want to add this to? + +It would be nice to have a general completion feature like this. + +Until that happens, maybe you will find the following patch useful. +It makes MH folder name completion work with bash. The diffs are +relative to version 1.14.2. + +I realize that changes to readline.c and and complete.c are not good +since they add some MH-specific stuff to the readline code and not to +bash, but when I first wrote this, I had no idea what else to do. + +Chet, would you consider adding this if it were cleaned up a bit? +Made optional with cpp conditionals? + +This feature has been very useful to me for the last several years +(since about 1.05 or 1.06, I think). + +Thanks, + +-- +John W. Eaton | 4.3BSD is not perfect. -- Leffler, et al. (1989). +jwe@che.utexas.edu | + + +-------------------------------cut here------------------------------- +diff -rc bash-1.14.2/bashline.c bash-1.14.2.local/bashline.c +*** bash-1.14.2/bashline.c Wed Aug 3 09:32:45 1994 +--- bash-1.14.2.local/bashline.c Wed Sep 21 15:39:04 1994 +*************** +*** 58,63 **** +--- 58,64 ---- + static char *hostname_completion_function (); + static char *command_word_completion_function (); + static char *command_subst_completion_function (); ++ static char *mh_folder_completion_function (); + + static void snarf_hosts_from_file (), add_host_name (); + static void sort_hostname_list (); +*************** +*** 90,95 **** +--- 91,98 ---- + bash_complete_username_internal (), + bash_complete_hostname (), bash_possible_hostname_completions (), + bash_complete_hostname_internal (), ++ bash_complete_mh_folder (), bash_possible_mh_folder_completions (), ++ bash_complete_mh_folder_internal (), + bash_complete_variable (), bash_possible_variable_completions (), + bash_complete_variable_internal (), + bash_complete_command (), bash_possible_command_completions (), +*************** +*** 134,140 **** + rl_terminal_name = get_string_value ("TERM"); + rl_instream = stdin; + rl_outstream = stderr; +! rl_special_prefixes = "$@"; + + /* Allow conditional parsing of the ~/.inputrc file. */ + rl_readline_name = "Bash"; +--- 137,143 ---- + rl_terminal_name = get_string_value ("TERM"); + rl_instream = stdin; + rl_outstream = stderr; +! rl_special_prefixes = "$@+"; + + /* Allow conditional parsing of the ~/.inputrc file. */ + rl_readline_name = "Bash"; +*************** +*** 193,198 **** +--- 196,207 ---- + rl_bind_key_in_map ('@', bash_possible_hostname_completions, + emacs_ctlx_keymap); + ++ rl_add_defun ("complete-mh-folder", bash_complete_mh_folder, META('+')); ++ rl_add_defun ("possible-mh-folder-completions", ++ bash_possible_mh_folder_completions, -1); ++ rl_bind_key_in_map ('+', bash_possible_mh_folder_completions, ++ emacs_ctlx_keymap); ++ + rl_add_defun ("complete-variable", bash_complete_variable, -1); + rl_bind_key_in_map ('$', bash_complete_variable, emacs_meta_keymap); + rl_add_defun ("possible-variable-completions", +*************** +*** 656,661 **** +--- 665,677 ---- + if (!matches && *text == '@') + matches = completion_matches (text, hostname_completion_function); + ++ /* Another one. Why not? If the word starts in '+', then look for ++ matching mh folders for completion first. */ ++ if (!matches && *text == '+') ++ { ++ matches = completion_matches (text, mh_folder_completion_function); ++ } ++ + /* And last, (but not least) if this word is in a command position, then + complete over possible command names, including aliases, functions, + and command names. */ +*************** +*** 1077,1082 **** +--- 1093,1185 ---- + return ((char *)NULL); + } + ++ /* How about a completion function for mh folders? */ ++ static char * ++ mh_folder_completion_function (text, state) ++ int state; ++ char *text; ++ { ++ extern int rl_filename_completion_desired; ++ ++ extern char *get_mh_path (); ++ ++ static char *mh_path = (char *)NULL; ++ static int len; ++ static int istate; ++ static char *val; ++ char *hint; ++ ++ static char *mh_folder_hint = (char *)NULL; ++ ++ /* If we don't have any state, make some. */ ++ if (!state) ++ { ++ val = (char *)NULL; ++ ++ if (mh_path) ++ free (mh_path); ++ ++ mh_path = get_mh_path (); ++ if (!mh_path && !(hint[1] == '/' || hint[1] == '.')) ++ return ((char *)NULL); ++ ++ len = strlen (mh_path); ++ } ++ ++ if (mh_folder_hint) ++ free (mh_folder_hint); ++ ++ hint = text; ++ if (*hint == '+') ++ hint++; ++ ++ mh_folder_hint = (char *)xmalloc (2 + len + strlen (hint)); ++ if (*hint == '/' || *hint == '.') { ++ len = -1; ++ sprintf (mh_folder_hint, "%s", hint); ++ } else ++ sprintf (mh_folder_hint, "%s/%s", mh_path, hint); ++ ++ istate = (val != (char *)NULL); ++ ++ again: ++ val = filename_completion_function (mh_folder_hint, istate); ++ istate = 1; ++ ++ if (!val) ++ { ++ return ((char *)NULL); ++ } ++ else ++ { ++ char *ptr = val + len + 1, *temp; ++ struct stat sb; ++ int status = stat (val, &sb); ++ ++ if (status != 0) ++ return ((char *)NULL); ++ ++ if ((sb.st_mode & S_IFDIR) == S_IFDIR) ++ { ++ temp = (char *)xmalloc (2 + strlen (ptr)); ++ *temp = '+'; ++ strcpy (temp + 1, ptr); ++ ++ free (val); ++ val = ""; ++ ++ rl_filename_completion_desired = 1; ++ ++ return (temp); ++ } ++ else ++ { ++ free (val); ++ } ++ goto again; ++ } ++ } ++ + /* History and alias expand the line. */ + static char * + history_expand_line_internal (line) +*************** +*** 1628,1633 **** +--- 1731,1773 ---- + { + bash_specific_completion + (what_to_do, (Function *)username_completion_function); ++ } ++ ++ static void ++ bash_complete_mh_folder (ignore, ignore2) ++ int ignore, ignore2; ++ { ++ bash_complete_mh_folder_internal (TAB); ++ } ++ ++ static void ++ bash_possible_mh_folder_completions (ignore, ignore2) ++ int ignore, ignore2; ++ { ++ bash_complete_mh_folder_internal ('?'); ++ } ++ ++ static void ++ bash_complete_mh_folder_internal (what_to_do) ++ int what_to_do; ++ { ++ Function *orig_func; ++ CPPFunction *orig_attempt_func; ++ char *orig_rl_completer_word_break_characters; ++ extern char *rl_completer_word_break_characters; ++ ++ orig_func = rl_completion_entry_function; ++ orig_attempt_func = rl_attempted_completion_function; ++ orig_rl_completer_word_break_characters = rl_completer_word_break_characters; ++ rl_completion_entry_function = (Function *)mh_folder_completion_function; ++ rl_attempted_completion_function = (CPPFunction *)NULL; ++ rl_completer_word_break_characters = " \t\n\"\'"; ++ ++ rl_complete_internal (what_to_do); ++ ++ rl_completion_entry_function = orig_func; ++ rl_attempted_completion_function = orig_attempt_func; ++ rl_completer_word_break_characters = orig_rl_completer_word_break_characters; + } + + static void +Only in bash-1.14.2.local: bashline.c.orig +diff -rc bash-1.14.2/lib/readline/complete.c bash-1.14.2.local/lib/readline/complete.c +*** bash-1.14.2/lib/readline/complete.c Tue Jul 26 12:59:57 1994 +--- bash-1.14.2.local/lib/readline/complete.c Wed Sep 21 15:41:19 1994 +*************** +*** 733,751 **** + if (rl_filename_completion_desired) + { + struct stat finfo; +! char *filename = tilde_expand (matches[0]); + +! if ((stat (filename, &finfo) == 0) && S_ISDIR (finfo.st_mode)) + { +! if (rl_line_buffer[rl_point] != '/') +! rl_insert_text ("/"); + } +! else + { +! if (rl_point == rl_end) +! rl_insert_text (temp_string); + } +- free (filename); + } + else + { +--- 733,768 ---- + if (rl_filename_completion_desired) + { + struct stat finfo; +! char *tilde_expand (); +! char *plus_expand (); +! char *filename = (char *) NULL; + +! switch (*matches[0]) + { +! case '+': +! filename = plus_expand (matches[0]); +! break; +! case '~': +! default: +! filename = tilde_expand (matches[0]); +! break; + } +! +! if (filename) + { +! if ((stat (filename, &finfo) == 0) +! && S_ISDIR (finfo.st_mode)) +! { +! if (rl_line_buffer[rl_point] != '/') +! rl_insert_text ("/"); +! } +! else +! { +! if (rl_point == rl_end) +! rl_insert_text (temp_string); +! } +! free (filename); + } + } + else + { +Only in bash-1.14.2.local/lib/readline: diffs +diff -rc bash-1.14.2/lib/readline/readline.c bash-1.14.2.local/lib/readline/readline.c +*** bash-1.14.2/lib/readline/readline.c Fri Aug 12 12:47:46 1994 +--- bash-1.14.2.local/lib/readline/readline.c Wed Sep 21 15:36:07 1994 +*************** +*** 23,28 **** +--- 23,29 ---- + #define READLINE_LIBRARY + + #include ++ #include + #include + #include + #if !defined (NO_SYS_FILE) +*************** +*** 3518,3523 **** +--- 3519,3616 ---- + } + + #endif /* TEST */ ++ ++ #define cr_whitespace(c) ((c) == '\r' || (c) == '\n' || whitespace(c)) ++ ++ char * ++ get_mh_path () ++ { ++ static FILE *fp = (FILE *)NULL; ++ char buf[512]; /* XXX */ ++ char profile[512]; /* XXX */ ++ char *bp; ++ char *temp_home; ++ char *temp_path; ++ ++ temp_home = (char *)getenv ("HOME"); ++ if (!temp_home) ++ return ((char *)NULL); ++ ++ strcpy (profile, temp_home); ++ strcat (profile, "/.mh_profile"); ++ ++ if (fp) ++ fclose (fp); ++ ++ fp = fopen (profile, "r"); ++ if (fp == (FILE *)NULL) ++ return ((char *)NULL); ++ ++ while (fgets (buf, 512, fp) != (char *)NULL) /* XXX */ ++ { ++ if ((bp = strstr (buf, "Path:")) != (char *)NULL) ++ { ++ bp += 5; ++ while (whitespace (*bp)) ++ bp++; ++ ++ if (*bp == '\0') ++ return ((char *)NULL); ++ ++ temp_path = (char *)xmalloc (3 + strlen (bp) + strlen (temp_home)); ++ ++ strcpy (temp_path, temp_home); ++ strcat (temp_path, "/"); ++ strcat (temp_path, bp); ++ ++ bp = temp_path; ++ ++ while (!(cr_whitespace (*bp))) ++ bp++; ++ ++ *bp = '\0'; ++ ++ return temp_path; ++ } ++ } ++ ++ return ((char *)NULL); ++ } ++ ++ /* Expand FILENAME if it begins with a plus. This always returns ++ a new string. */ ++ char * ++ plus_expand (filename) ++ char *filename; ++ { ++ static char *dirname = (char *)NULL; ++ ++ if (filename && *filename == '+') ++ { ++ char *mh_path = get_mh_path (); ++ ++ if (filename[1] == '/' || filename[1] == '.') ++ { ++ dirname = (char *)xmalloc (1 + strlen (filename)); ++ ++ strcpy(dirname, filename+1); ++ ++ return dirname; ++ } ++ ++ if (mh_path) ++ { ++ dirname = (char *)xmalloc (1 + strlen (filename) + strlen (mh_path)); ++ ++ strcpy (dirname, mh_path); ++ strcat (dirname, "/"); ++ strcat (dirname, filename+1); ++ ++ return dirname; ++ } ++ } ++ return (char *)NULL; ++ } + + + /* + diff --git a/CWRU/misc/aux-mach-desc b/CWRU/misc/aux-mach-desc deleted file mode 100644 index 71a8dab..0000000 --- a/CWRU/misc/aux-mach-desc +++ /dev/null @@ -1,20 +0,0 @@ -/* ************************ */ -/* */ -/* A/UX 3.0 System */ -/* */ -/* ************************ */ -#if defined (mc68k32) && !defined (M_MACHINE) -# define M_MACHINE "Macintosh" -# define M_OS "AUX" -# define SYSDEP_CFLAGS -ZP -DUSG -DHAVE_BCOPY -DHAVE_UID_T -DNSIG=32 \ - -DHAVE_GETDTABLESIZE -# define SYSDEP_LDFLAGS -ZP -# define HAVE_DIRENT -# define HAVE_POSIX_SIGNALS -# define HAVE_VFPRINTF -# define VOID_SIGHANDLER -# define HAVE_GETGROUPS -# undef HAVE_RESOURCE -# undef HAVE_ALLOCA -# define REQUIRED_LIBRARIES -lc_s -#endif /* A/UX */ diff --git a/INSTALL b/INSTALL index e366406..a4e702e 100644 --- a/INSTALL +++ b/INSTALL @@ -1,212 +1,288 @@ -File: bash.info, Node: Install, Next: Invoke, Prev: Built-in, Up: Top +Basic Installation +================== -Installing BASH -*************** - -To install BASH you simply type `make'. The BASH `Makefile' tries -to dynamically figure out what kind of machine and operating system -you are using. It makes an educated guess based on the information -it finds. - -During the `make' process, a message is displayed describing what -machine and operating system has been chosen for you. This -information is also saved in the file `.machine' so you can look at -it later. - -Therefore, for most machines, simply follow this simple checklist -to install BASH: - - 1. Type `make'. If you want to use GCC to compile bash, type - `make CC=gcc CPPNAME='$(CC) -E''. - - 2. Wait for the compilation to finish. - - 3. Type `./bash' to see if the compile worked. - - 4. Type `make install prefix=/usr/gnu/' (or the appropriate root - of your local GNU software installation tree) to copy bash to - your binaries directory, assumed to be ${prefix}/bin. This will - also attempt to install the manual pages under ${prefix}/man - and the info file under ${prefix}/info. - -* Menu: - -* Problems:: What to do if BASH doesn't install quite so easily. - -* Files:: Files used in the `make' process. - -* Porting:: Porting BASH to a new machine. - -* Bugs:: What to do if you Discover Bugs in BASH. - - -File: bash.info, Node: Problems, Next: Files, Prev: Install, Up: Install - -What if it Doesn't Install so Easily? -===================================== - -Sometimes BASH gets confused and will make the wrong assumptions -about your machine or operating system. If the displayed -information (also found in `.machine') is incorrect, you will have -to edit the file `machines.h' and provide the appropriate -information so that BASH can be installed correctly. The complete -instructions for doing this are located in the `machines.h' file. - -However, if BASH says that your machine type is an -"UNKNOWN_MACHINE", or BASH thought it knew something about your -machine but was wrong, then reading the next few sections could -be of use to you (*note Files::., and *note Porting::., for more -information). - -On the MIPSEB with the BSD universe, you must: - -1) Place /bsd43/bin in your PATH before /bin -2) Use $(CC) -E instead of /lib/cpp to build cpp-Makefile. - -On SCO Xenix 386, you must: - -1) Use $(CC) -E instead of /lib/cpp to build cpp-Makefile. - -On Interactive Unix version 3 or 4, you must: - -1) Edit cpp-Makefile to remove either -O or -g from DEBUG_FLAGS - -File: bash.info, Node: Files, Next: Porting, Prev: Problems, Up: Install - -Files Used in the `make' Process. -================================= - -The following files are used during the installation of BASH, in -the `make' process: - -`Makefile' - This is responsible for making the actual `Makefile' that is - used to create Bash. It runs the C preprocessor (usually - located in `/lib/cpp') on the file `cpp-Makefile', producing - the output file `bash-Makefile'. - -`cpp-Makefile' - This is a file of C comments and text. It contains a - reasonable number of `ifdefs' which control what files get - compiled and which flags are passed to the various C files - comprising BASH. It includes files named `machines.h', - `sysdefs.h', and `config.h'. - -`machines.h' - This file contains the basic compilation parameters for all of - the machines to which BASH has been ported. This file - consists of a series of conditional blocks, one per machine - type. - - These conditional blocks are depend upon the unique identifier - that `cpp' has predefined for this machine. In some cases, - additional information can be passed from `Makefile'. It is - possible to pass information such as whether or not a - particular file is available on this system, and so on. - -`sysdefs.h' - This file is dynamically made at build time by running the shell - script `support/mksydefs'. If there appears to be something wrong - in this file, then edit the `mksysdefs' script, and mail the - changes that you make to bash-maintainers@prep.ai.mit.edu. - -`bash-Makefile' - This is the output from the initial stage of `make'. It is a - stripped down version of `cpp-Makefile' which is tailor-made - for your machine and operating system. All subsequent `makes' - use this file. - - -File: bash.info, Node: Porting, Next: Bugs, Prev: Files, Up: Install - -What if You Have to Port to a New Machine? -========================================== - -Sometimes you may want to port BASH to a new, previously -unsupported machine. To do so you need to create a block in -`machines.h' which is conditional based on a unique identifier -present in your version of the C preprocessor. - -If you don't know what that symbol is, you might try the following -simple test: - - echo "main () { }" > foo.c - cc -v foo.c - -You are looking for `-DMACHINE', where `MACHINE' is an identifier -for your machine. If you are very unlucky and your machine's C -preprocessor doesn't have a unique identifier, you will have to -define the identifier in Makefile manually. - -Let's say you have a machine from Yoyodyne Industries, called the -YoYo. It runs a version of BSD, so it is reasonably compatible. -However, the `cpp' on this YoYo machine doesn't define any unique -identifiers. You should change the `Makefile' line for `CPPFLAGS' -to: - - CPPFLAGS = -P -DYoYo - -Then, in `machines.h', you copy the block for `UNKNOWN_MACHINE', -and change the conditional to; - - #if defined (YoYo) - -Inside of the YoYo block you define `M_MACHINE="YoYo"', and -`M_OS=Bsd'. You also modify the existing defines to match your -machine's software. - -If BASH still won't compile, perhaps because of missing code that -is required for your YoYo machine, you will have to write that code -and place it within a conditional block based on YoYo. - -Most machines aren't that difficult; simply redefining a few of the -default values is sufficient. If you do run across a difficult -machine, please send all fixes and changes to -bash-maintainers@prep.ai.mit.edu in the form of context diffs: - - diff -c orig-machines.h machines.h >machines.diffs - -Please include information about which version of the shell you have. - -For those machines which prove more difficult, or if you are not -sure about where to start, the scripts in the `portbash' directory -may prove helpful. - -File: bash.info, Node: Bugs, Prev: Porting, Up: Install - -Reporting Bugs -============== - -If you find a bug in bash, you should report it. But first you -should make sure that it really is a bug and that it appears in the -latest version of BASH that is available. - -Once you have ascertained that a bug really exists, you are welcome -to mail in a bug report. If you have a fix, please mail that too! -The program `bashbug' is used to submit bug reports. - -Suggestions and "philosophical" bug reports should be mailed to -bug-bash@ai.mit.edu. Genuine bug reports should be mailed to the -same place, or to bash-maintainers@prep.ai.mit.edu. The `bashbug' -script sends its messages to bug-bash@prep.ai.mit.edu. - -*All* bug reports should include: - - * The version number of BASH. - - * The hardware and operating system used. - - * The compiler used to compile BASH. - - * A description of the bug's behavior. - - * A short script or "recipe" which demonstrates the bug. - -The `bashbug' program includes much of this information -automatically. Without this information, it is generally not -possible to successfully debug BASH. Usually, without this -information, the bug won't manifest itself! - -Discussion and questions about BASH in general (including -questions about this documentation) can be sent to -bash-maintainers@prep.ai.mit.edu. +These are generic installation instructions for Bash. + +The `configure' shell script attempts to guess correct values for +various system-dependent variables used during compilation. It uses +those values to create a `Makefile' in each directory of the package +(the top directory, the `builtins' and `doc' directories, and the each +directory under `lib'). It also creates a `config.h' file containing +system-dependent definitions. Finally, it creates a shell script named +`config.status' that you can run in the future to recreate the current +configuration, a file `config.cache' that saves the results of its +tests to speed up reconfiguring, and a file `config.log' containing +compiler output (useful mainly for debugging `configure'). If at some +point `config.cache' contains results you don't want to keep, you may +remove or edit it. + +If you need to do unusual things to compile the package, please try to +figure out how `configure' could check whether or not to do them, and +mail diffs or instructions to `bash-maintainers@prep.ai.mit.edu' so +they can be considered for the next release. + +The file `configure.in' is used to create `configure' by a program +called Autoconf. You only need `configure.in' if you want to change it +or regenerate `configure' using a newer version of Autoconf. If you do +this, make sure you are using Autoconf version 2.9 or newer. + +The simplest way to compile Bash is: + + 1. `cd' to the directory containing the source code and type + `./configure' to configure Bash for your system. If you're using + `csh' on an old version of System V, you might need to type `sh + ./configure' instead to prevent `csh' from trying to execute + `configure' itself. + + Running `configure' takes awhile. While running, it prints some + messages telling which features it is checking for. + + 2. Type `make' to compile Bash and build the `bashbug' bug reporting + script. + + 3. Optionally, type `make tests' to run the Bash test suite. + + 4. Type `make install' to install `bash' and `bashbug'. This will + also install the manual pages and Info file. + +You can remove the program binaries and object files from the source +code directory by typing `make clean'. To also remove the files that +`configure' created (so you can compile Bash for a different kind of +computer), type `make distclean'. + +Compilers and Options +===================== + +Some systems require unusual options for compilation or linking that +the `configure' script does not know about. You can give `configure' +initial values for variables by setting them in the environment. Using +a Bourne-compatible shell, you can do that on the command line like +this: + + CC=c89 CFLAGS=-O2 LIBS=-lposix ./configure + +On systems that have the `env' program, you can do it like this: + + env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure + +The configuration process uses GCC to build Bash if it is available. + +Compiling For Multiple Architectures +==================================== + +You can compile Bash for more than one kind of computer at the same +time, by placing the object files for each architecture in their own +directory. To do this, you must use a version of `make' that supports +the `VPATH' variable, such as GNU `make'. `cd' to the directory where +you want the object files and executables to go and run the `configure' +script from the source directory. You may need to supply the +`--srcdir=PATH' argument to tell `configure' where the source files +are. `configure' automatically checks for the source code in the +directory that `configure' is in and in `..'. + +If you have to use a `make' that does not supports the `VPATH' +variable, you can compile Bash for one architecture at a time in the +source code directory. After you have installed Bash for one +architecture, use `make distclean' before reconfiguring for another +architecture. + +Alternatively, if your system supports symbolic links, you can use the +`support/mkclone' script to create a build tree which has symbolic +links back to each file in the source directory. Here's an example +that creates a build directory in the current directory from a source +directory `/usr/gnu/src/bash-2.0': + + bash /usr/gnu/src/bash-2.0/support/mkclone -s /usr/gnu/src/bash-2.0 . + +The `mkclone' script requires Bash, so you must have already built Bash +for at least one architecture before you can create build directories +for other architectures. + +Installation Names +================== + +By default, `make install' will install into `/usr/local/bin', +`/usr/local/man', etc. You can specify an installation prefix other +than `/usr/local' by giving `configure' the option `--prefix=PATH'. + +You can specify separate installation prefixes for +architecture-specific files and architecture-independent files. If you +give `configure' the option `--exec-prefix=PATH', the package will use +`PATH' as the prefix for installing programs and libraries. +Documentation and other data files will still use the regular prefix. + +Specifying the System Type +========================== + +There may be some features `configure' can not figure out +automatically, but needs to determine by the type of host the package +will run on. Usually `configure' can figure that out, but if it prints +a message saying it can not guess the host type, give it the +`--host=TYPE' option. `TYPE' can either be a short name for the system +type, such as `sun4', or a canonical name with three fields: +`CPU-COMPANY-SYSTEM' (e.g., `sparc-sun-sunos4.1.2'). + +See the file `support/config.sub' for the possible values of each field. + +Sharing Defaults +================ + +If you want to set default values for `configure' scripts to share, you +can create a site shell script called `config.site' that gives default +values for variables like `CC', `cache_file', and `prefix'. `configure' +looks for `PREFIX/share/config.site' if it exists, then +`PREFIX/etc/config.site' if it exists. Or, you can set the +`CONFIG_SITE' environment variable to the location of the site script. +A warning: the Bash `configure' looks for a site script, but not all +`configure' scripts do. + +Operation Controls +================== + +`configure' recognizes the following options to control how it operates. + +`--cache-file=FILE' + Use and save the results of the tests in FILE instead of + `./config.cache'. Set FILE to `/dev/null' to disable caching, for + debugging `configure'. + +`--help' + Print a summary of the options to `configure', and exit. + +`--quiet' +`--silent' +`-q' + Do not print messages saying which checks are being made. + +`--srcdir=DIR' + Look for the Bash source code in directory DIR. Usually + `configure' can determine that directory automatically. + +`--version' + Print the version of Autoconf used to generate the `configure' + script, and exit. + +`configure' also accepts some other, not widely used, boilerplate +options. + +Optional Features +================= + +The Bash `configure' has a number of `--enable-FEATURE' options, where +FEATURE indicates an optional part of the package. There are also +several `--with-PACKAGE' options, where PACKAGE is something like +`gnu-malloc' or `purify' (for the Purify memory allocation checker). To +turn off the default use of a package, use `--without-PACKAGE'. To +configure Bash without a feature that is enabled by default, use +`--disable-FEATURE'. + +Here is a complete list of the `--enable-' and `--with-' options that +the Bash `configure' recognizes. + +`--with-gnu-malloc' + Use the GNU version of `malloc' in `lib/malloc/malloc.c'. This is + not the same `malloc' that appears in GNU libc, but an older + version derived from the 4.2 BSD `malloc'. This `malloc' is very + fast, but wastes a lot of space. This option is enabled by + default. The `NOTES' file contains a list of systems for which + this should be turned off. + +`--with-glibc-malloc' + Use the GNU libc version of `malloc' in `lib/malloc/gmalloc.c'. + This is somewhat slower than the default `malloc', but wastes + considerably less space. + +`--with-afs' + Define if you are using the Andrew File System from Transarc. + +`--with-purify' + Define this to use the Purify memory allocation checker from Pure + Software. + +`--enable-minimal-config' + This produces a shell with minimal features, close to the + historical Bourne shell. + +The `minimal-config' option can be used to disable all of the following +options, but it is processed first, so individual options may be +enabled using `enable-FEATURE'. + +All of the following options except for `disabled-builtins' and +`usg-echo-default' are enabled by default, unless the operating system +does not provide the necessary support. + +`--enable-job-control' + This enables job control features, if the OS supports them. + +`--enable-alias' + Allow alias expansion and include the `alias' and `unalias' + builtins. + +`--enable-readline' + Include support for command-line editing and history with the Bash + version of the Readline library. + +`--enable-history' + Include command history and the `fc' and `history' builtin + commands. + +`--enable-bang-history' + Include support for `csh'-like history substitution. + +`--enable-directory-stack' + Include support for a `csh'-like directory stack and the `pushd', + `popd', and `dirs' builtins. + +`--enable-restricted' + Include support for a "restricted shell". If this is enabled, + Bash, when called as `rbash', enters a restricted mode. See *Note + The Restricted Shell::, for a description of restricted mode. + +`--enable-process-substitution' + This enables process substitution (*note Process Substitution::.) + if the OS provides the necessary support. + +`--enable-prompt-string-decoding' + Turn on the interpretation of a number of backslash-escaped + characters in the `$PS1', `$PS2', `$PS3', and `$PS4' prompt + strings. + +`--enable-select' + Include the `ksh' `select' builtin, which allows the generation of + simple menus. + +`--enable-help-builtin' + Include the `help' builtin, which displays help on shell builtins + and variables. + +`--enable-array-variables' + Include support for one-dimensional array shell variables. + +`--enable-dparen-arithmetic' + Include support for the `ksh' `((...))' command. + +`--enable-brace-expansion' + Include `csh'-like brace expansion ( `b{a,b}c' ==> `bac bbc' ). + +`--enable-disabled-builtins' + Allow builtin commands to be invoked via `builtin xxx' even after + `xxx' has been disabled using `enable -n xxx'. See *Note Bash + Builtins::, for details of the `builtin' and `enable' builtin + commands. + +`--enable-command-timing' + Include support for recognizing `time' as a reserved word and for + displaying timing statistics for the pipeline following `time'. + This allows pipelines as well as shell builtins and functions to + be timed. + +`--enable-usg-echo-default' + Make the `echo' builtin expand backslash-escaped characters by + default, without requiring the `-e' option. This makes the Bash + `echo' behave more like the System V version. + +The file `config.h.top' contains C Preprocessor `#define' statements +for options which are not settable from `configure'. Some of these are +not meant to be changed; beware of the consequences if you do. Read +the comments associated with each definition for more information about +its effect. diff --git a/MANIFEST b/MANIFEST index 4307b2f..7110038 100644 --- a/MANIFEST +++ b/MANIFEST @@ -7,17 +7,20 @@ CWRU d CWRU/misc d builtins d -documentation d +doc d examples d +examples/bashdb d examples/functions d examples/scripts d +examples/scripts.v2 d +examples/scripts.noah d examples/startup-files d +examples/misc d +examples/loadables d lib d -lib/doc-support d lib/glob d lib/glob/doc d lib/malloc d -lib/malloclib d lib/posixheaders d lib/readline d lib/readline/doc d @@ -26,20 +29,32 @@ lib/termcap d lib/termcap/grot d lib/tilde d lib/tilde/doc d -portbash d support d tests d tests/misc d -README f -RELEASE f -INSTALL f +CHANGES f +COMPAT f COPYING f +INSTALL f MANIFEST f +NEWS f +NOTES f +README f +configure.in f configure f -Makefile f -cpp-Makefile f +Makefile.in f +config.h.top f +config.h.bot f +config.h.in f +aclocal.m4 f +array.c f +eval.c f print_cmd.c f general.c f +list.c f +locale.c f +stringlib.c f +oslib.c f variables.c f make_cmd.c f copy_cmd.c f @@ -47,16 +62,17 @@ unwind_prot.c f dispose_cmd.c f getcwd.c f bashhist.c f -hash.c f +hashlib.c f parse.y f +pathexp.c f subst.c f shell.c f trap.c f +sig.c f siglist.c f version.c f flags.c f jobs.c f -newversion.c f input.c f mailcheck.c f test.c f @@ -69,22 +85,23 @@ bracecomp.c f nojobs.c f vprint.c f error.c f -signames.c f -endian.c f +xmalloc.c f alias.h f -config.h f -config.h.mini f builtins.h f -parser.h f +bashhist.h f +bashline.h f variables.h f -machines.h f +array.h f jobs.h f maxpath.h f filecntl.h f -hash.h f +hashlib.h f quit.h f flags.h f shell.h f +pathexp.h f +parser.h f +sig.h f trap.h f general.h f unwind_prot.h f @@ -93,22 +110,28 @@ error.h f command.h f externs.h f siglist.h f -subst.h f +subst.h f dispose_cmd.h f bashansi.h f +bashtty.h f +bashjmp.h f +bashwait.h f +bashintl.h f make_cmd.h f -bashhist.h f execute_cmd.h f bashtypes.h f +mailcheck.h f +pathnames.h f y.tab.c f y.tab.h f +posixdir.h f posixstat.h f stdc.h f ansi_stdlib.h f memalloc.h f parser-built f builtins/ChangeLog f -builtins/Makefile f +builtins/Makefile.in f builtins/alias.def f builtins/bind.def f builtins/break.def f @@ -121,6 +144,8 @@ builtins/declare.def f builtins/echo.def f builtins/enable.def f builtins/eval.def f +builtins/evalfile.c f +builtins/evalstring.c f builtins/exec.def f builtins/exit.def f builtins/fc.def f @@ -136,12 +161,14 @@ builtins/history.def f builtins/jobs.def f builtins/kill.def f builtins/mkbuiltins.c f +builtins/pushd.def f builtins/read.def f builtins/reserved.def f builtins/return.def f builtins/set.def f builtins/setattr.def f builtins/shift.def f +builtins/shopt.def f builtins/source.def f builtins/suspend.def f builtins/test.def f @@ -157,94 +184,90 @@ builtins/inlib.def f builtins/bashgetopt.c f builtins/common.h f builtins/bashgetopt.h f -lib/doc-support/texindex.c f -lib/doc-support/getopt.h f -lib/doc-support/Makefile f lib/glob/ChangeLog f -lib/glob/Makefile f +lib/glob/Makefile.in f lib/glob/fnmatch.c f lib/glob/fnmatch.h f lib/glob/glob.c f +lib/glob/glob.h f lib/glob/doc/Makefile f lib/glob/doc/glob.texi f lib/glob/ndir.h f -lib/malloc/Makefile f -lib/malloc/alloca.c f +lib/malloc/Makefile.in f lib/malloc/getpagesize.h f -lib/malloc/i386-alloca.s f +lib/malloc/alloca.c f lib/malloc/malloc.c f -lib/malloc/x386-alloca.s f +lib/malloc/gmalloc.c f lib/malloc/xmalloc.c f -lib/malloclib/Makefile f -lib/malloclib/alloca.c f -lib/malloclib/i386-alloca.s f -lib/malloclib/calloc.c f -lib/malloclib/cfree.c f -lib/malloclib/x386-alloca.s f -lib/malloclib/morecore.c f -lib/malloclib/free.c f -lib/malloclib/getpagesize.h f -lib/malloclib/malloc.c f -lib/malloclib/malloc.h f -lib/malloclib/xmalloc.c f -lib/malloclib/mcheck.c f -lib/malloclib/memalign.c f -lib/malloclib/mstats.c f -lib/malloclib/mtrace.awk f -lib/malloclib/mtrace.c f -lib/malloclib/realloc.c f -lib/malloclib/valloc.c f +lib/malloc/stub.c f +lib/malloc/i386-alloca.s f +lib/malloc/x386-alloca.s f +lib/posixheaders/posixdir.h f lib/posixheaders/posixstat.h f lib/posixheaders/ansi_stdlib.h f lib/posixheaders/stdc.h f lib/posixheaders/memalloc.h f lib/posixheaders/filecntl.h f lib/readline/COPYING f -lib/readline/readline.c f -lib/readline/readline.h f +lib/readline/Makefile.in f lib/readline/ChangeLog f +lib/readline/README f +lib/readline/STANDALONE f +lib/readline/readline.c f lib/readline/vi_mode.c f -lib/readline/history.h f -lib/readline/Makefile f -lib/readline/chardefs.h f lib/readline/emacs_keymap.c f -lib/readline/keymaps.h f lib/readline/vi_keymap.c f lib/readline/history.c f +lib/readline/histexpand.c f +lib/readline/histsearch.c f +lib/readline/histfile.c f lib/readline/funmap.c f lib/readline/keymaps.c f +lib/readline/util.c f +lib/readline/terminal.c f lib/readline/xmalloc.c f -lib/readline/doc/Makefile f -lib/readline/doc/rlman.texinfo f -lib/readline/doc/rltech.texinfo f -lib/readline/doc/rluser.texinfo f -lib/readline/doc/hist.texinfo f -lib/readline/doc/hstech.texinfo f -lib/readline/doc/hsuser.texinfo f -lib/readline/examples/Makefile f -lib/readline/examples/fileman.c f -lib/readline/examples/manexamp.c f -lib/readline/examples/histexamp.c f -lib/readline/examples/Inputrc f -lib/readline/README f -lib/readline/STANDALONE f lib/readline/search.c f lib/readline/isearch.c f -lib/readline/rldefs.h f -lib/readline/rlconf.h f lib/readline/parens.c f lib/readline/rltty.c f lib/readline/complete.c f lib/readline/bind.c f lib/readline/display.c f lib/readline/signals.c f -lib/readline/doc/texindex.c f +lib/readline/kill.c f +lib/readline/undo.c f +lib/readline/macro.c f +lib/readline/input.c f +lib/readline/callback.c f +lib/readline/nls.c f lib/readline/tilde.c f lib/readline/tilde.h f +lib/readline/rldefs.h f +lib/readline/rlconf.h f +lib/readline/rltty.h f +lib/readline/readline.h f +lib/readline/tcap.h f +lib/readline/keymaps.h f +lib/readline/history.h f +lib/readline/histlib.h f +lib/readline/chardefs.h f +lib/readline/posixdir.h f lib/readline/posixstat.h f lib/readline/ansi_stdlib.h f -lib/readline/memalloc.h f -lib/termcap/Makefile f +lib/readline/doc/Makefile f +lib/readline/doc/rlman.texinfo f +lib/readline/doc/rltech.texinfo f +lib/readline/doc/rluser.texinfo f +lib/readline/doc/hist.texinfo f +lib/readline/doc/hstech.texinfo f +lib/readline/doc/hsuser.texinfo f +lib/readline/examples/Makefile f +lib/readline/examples/fileman.c f +lib/readline/examples/manexamp.c f +lib/readline/examples/histexamp.c f +lib/readline/examples/rltest.c f +lib/readline/examples/Inputrc f +lib/termcap/Makefile.in f lib/termcap/termcap.c f lib/termcap/termcap.h f lib/termcap/tparam.c f @@ -265,62 +288,80 @@ lib/termcap/grot/configure.in f lib/termcap/grot/COPYING f lib/termcap/grot/README f lib/tilde/ChangeLog f -lib/tilde/Makefile f +lib/tilde/Makefile.in f lib/tilde/doc/tilde.texi f lib/tilde/doc/Makefile f lib/tilde/tilde.c f lib/tilde/tilde.h f -lib/tilde/memalloc.h f CWRU/misc/open-files.c f CWRU/misc/sigs.c f CWRU/misc/pid.c f CWRU/misc/sigstat.c f CWRU/misc/bison f -CWRU/misc/aux-mach-desc f CWRU/PLATFORMS f CWRU/README f CWRU/POSIX.NOTES f CWRU/changelog f -CWRU/sh-redirection-hack f -documentation/Makefile f -documentation/bash.1 f -documentation/bash.ps f -documentation/bash.txt f -documentation/README f -documentation/readline.3 f -documentation/readline.ps f -documentation/readline.txt f -documentation/texinfo.tex f -documentation/features.texi f -documentation/features.info f -documentation/features.dvi f -documentation/features.ps f -documentation/builtins.1 f -documentation/builtins.ps f -documentation/builtins.txt f -documentation/article.ms f -documentation/article.ps f -documentation/article.txt f -support/cat-s f -support/mksysdefs f -support/printenv f -support/getcppsyms.c f -support/cppmagic f +CWRU/sh-redir-hack f +CWRU/mh-folder-comp f +doc/FAQ f +doc/Makefile.in f +doc/bash.1 f +doc/bashbug.1 f +doc/README f +doc/INTRO f +doc/readline.3 f +doc/texinfo.tex f +doc/bashref.texi f +doc/bashref.info f +doc/builtins.1 f +doc/article.ms f +support/config.guess f +support/config.sub f +support/printenv f 755 support/bash.xbm f -support/FAQ f -support/PORTING f -support/mklinks f -support/mkdirs f -support/clone-bash f +support/mkclone f 755 +support/mkdirs f 755 +support/mkversion.c f +support/mksignames.c f support/bashbug.sh f -support/mkmachtype f support/recho.c f -support/srcdir f +support/zecho.c f support/SYMLINKS f -support/fixlinks f +support/fixlinks f 755 +support/install.sh f 755 +support/texi2dvi f +support/texi2html f +examples/bashdb/PERMISSION f +examples/bashdb/README f +examples/bashdb/bashdb f +examples/bashdb/bashdb.fns f +examples/bashdb/bashdb.pre f +examples/loadables/README f +examples/loadables/Makefile f +examples/loadables/necho.c f +examples/loadables/hello.c f +examples/loadables/printf.c f +examples/loadables/print.c f +examples/loadables/sprintf.c f +examples/loadables/sleep.c f +examples/loadables/truefalse.c f +examples/loadables/getconf.c f +examples/loadables/pushd.c f +examples/loadables/finfo.c f +examples/loadables/cat.c f +examples/loadables/logname.c f +examples/loadables/basename.c f +examples/loadables/dirname.c f +examples/loadables/tty.c f +examples/loadables/pathchk.c f +examples/loadables/tee.c f +examples/loadables/rmdir.c f +examples/loadables/head.c f examples/functions/substr f examples/functions/kshenv f examples/functions/autoload f +examples/functions/autoload.v2 f examples/functions/csh-compat f examples/functions/shcat f examples/functions/substr2 f @@ -338,18 +379,39 @@ examples/functions/manpage f examples/functions/fstty f examples/functions/jj.bash f examples/functions/notify.bash f +examples/functions/inpath f +examples/functions/login f +examples/functions/keep f +examples/functions/seq f +examples/functions/mhfold f +examples/functions/repeat2 f +examples/functions/lowercase f examples/scripts/shprompt f examples/scripts/adventure.sh f examples/scripts/precedence f examples/scripts/bcsh.sh f +examples/scripts/inpath f +examples/scripts/nohup.bash f +examples/scripts/vtree2 f +examples/scripts/scrollbar f +examples/scripts/zprintf f +examples/startup-files/README f examples/startup-files/Bashrc f examples/startup-files/Bash_aliases f examples/startup-files/Bash_profile f examples/startup-files/bash-profile f examples/startup-files/bashrc f -examples/suncmd.termcap f -examples/alias-conv.sh f +examples/misc/suncmd.termcap f +examples/misc/alias-conv.sh f +examples/misc/alias-conv.bash f +examples/misc/cshtobash f tests/README f +tests/arith.tests f +tests/arith.right f +tests/array.tests f +tests/array.right f +tests/braces-tests f +tests/braces.right f tests/dollar-at.sh f tests/dollar-star.sh f tests/dollar.right f @@ -357,6 +419,8 @@ tests/exp-tests f tests/exp.right f tests/glob-test f tests/glob.right f +tests/heredoc.tests f +tests/heredoc.right f tests/ifs-test-1.sh f tests/ifs-test-2.sh f tests/ifs-test-3.sh f @@ -368,26 +432,52 @@ tests/input-line.sub f tests/input.right f tests/minus-e f tests/minus-e.right f +tests/more-exp.tests f +tests/more-exp.right f tests/new-exp.tests f tests/new-exp.right f +tests/nquote.tests f +tests/nquote.right f +tests/posix2.tests f +tests/posix2.right f tests/prec.right f tests/precedence f +tests/quote.tests f +tests/quote.right f +tests/read.tests f +tests/read.right f +tests/rhs-exp.tests f +tests/rhs-exp.right f tests/run-all f +tests/run-arith f +tests/run-array f +tests/run-braces f tests/run-dollars f tests/run-exp-tests f tests/run-glob-test f +tests/run-heredoc f tests/run-ifs-tests f tests/run-input-test f tests/run-minus-e f +tests/run-more-exp f tests/run-new-exp f +tests/run-nquote f +tests/run-posix2 f tests/run-precedence f +tests/run-quote f +tests/run-read f +tests/run-rhs-exp f tests/run-set-e-test f tests/run-strip f +tests/run-test f +tests/run-tilde f tests/run-varenv f tests/set-e-test f tests/set-e.right f tests/strip.tests f tests/strip.right f +tests/test-tests f +tests/test.right f tests/tilde-tests f tests/tilde.right f tests/varenv.right f @@ -411,11 +501,43 @@ tests/misc/sigint.t3.sh f tests/misc/sigint.t4.sh f tests/misc/test-minus-e.1 f tests/misc/test-minus-e.2 f -portbash/signals.sh f -portbash/stdio.sh f -portbash/libc.sh f -portbash/mkdesc.sh f -portbash/README f -portbash/strings.sh f -portbash/syscalls.sh f -portbash/pgrp.c f +examples/scripts.v2/PERMISSION f +examples/scripts.v2/README f +examples/scripts.v2/arc2tarz f +examples/scripts.v2/bashrand f +examples/scripts.v2/cdhist.bash f +examples/scripts.v2/corename f +examples/scripts.v2/fman f +examples/scripts.v2/frcp f +examples/scripts.v2/lowercase f +examples/scripts.v2/ncp f +examples/scripts.v2/newext f +examples/scripts.v2/nmv f +examples/scripts.v2/pages f +examples/scripts.v2/pf f +examples/scripts.v2/rename f +examples/scripts.v2/repeat f +examples/scripts.v2/untar f +examples/scripts.v2/uudec f +examples/scripts.v2/uuenc f +examples/scripts.v2/vtree f +examples/scripts.v2/where f +examples/scripts.v2/pmtop f +examples/scripts.v2/shprof f +examples/scripts.noah/PERMISSION f +examples/scripts.noah/README f +examples/scripts.noah/aref.bash f +examples/scripts.noah/bash.sub.bash f +examples/scripts.noah/bash_version.bash f +examples/scripts.noah/meta.bash f +examples/scripts.noah/mktmp.bash f +examples/scripts.noah/number.bash f +examples/scripts.noah/prompt.bash f +examples/scripts.noah/remap_keys.bash f +examples/scripts.noah/require.bash f +examples/scripts.noah/send_mail.bash f +examples/scripts.noah/shcat.bash f +examples/scripts.noah/source.bash f +examples/scripts.noah/string.bash f +examples/scripts.noah/stty.bash f +examples/scripts.noah/y_or_n_p.bash f diff --git a/Makefile b/Makefile deleted file mode 100644 index da50f7a..0000000 --- a/Makefile +++ /dev/null @@ -1,115 +0,0 @@ -# Hey Emacs, this Makefile is in -*- makefile -*- mode! -# -# Makefile for Bash. -# If your cpp doesn't like -P, just get rid of it (the -P, not cpp). -# If you wish to use Gcc, then type `make CC=gcc CPPNAME='$(CC) -E''. -# If you wish to use GNU's Make, then change `MAKE'. -# If you don't like the destination, then change `bindir'. -# The file that you most likely want to look at is cpp-Makefile. -# -# If you haven't read README, now might be a good time. - -# Include some boilerplate Gnu makefile definitions. -prefix = /usr/local -exec_prefix = $(prefix) -bindir = $(exec_prefix)/bin -srcdir = . -VPATH = $(srcdir) - -# MAKE = make -RM = rm -f -SHELL = /bin/sh -GAWK = awk -# GAWK = gawk - -# Force CPPNAME to be the name of your C preprocesor if Bash can't -# find it. For instance, `CPPNAME=/usr/libexec/cpp' on 4.4 BSD. -# If all else fails, set CPPNAME=$(CC) -E -CPPNAME = -CPP = `$(SHELL) $(CPPMAGIC) $(GETCPPSYMS) "$(CPPNAME)"` -P - -CPP_MAKEFILE = $(srcdir)/cpp-Makefile -ANSI_MAKEFILE = ansi-Makefile - -# CPPFLAGS = $(SYSTEM) $(CPP_DEFINES) -CPPFLAGS = $(CPP_DEFINES) -I. -I$(srcdir) -CPP_ARGS = -DCPP_CC="$(CC)" - -SUPPORTDIR = ./support/ -SUPPORTSRC = $(srcdir)/support/ - -MKSYSDEFS = $(SUPPORTSRC)mksysdefs -CPPMAGIC = $(SUPPORTSRC)cppmagic -CAT_S = $(SUPPORTSRC)cat-s -GETCPPSYMS = $(SUPPORTDIR)getcppsyms -GETCPPSYMS_SRC = $(SUPPORTSRC)getcppsyms.c - -# Here is a command which compresses runs of multiple blank lines to a -# single blank line. "cat -s" works for BSD systems, but not for USG -# systems. You can use an awk script if you like. If you have too -# much trouble with this, just forget it. It is for making -# bash-Makefile pretty and readable; something that isn't strictly -# necessary. -# SQUASH_BLANKS = cat -s -# -SQUASH_BLANKS = $(GAWK) -f $(CAT_S) - -all: .notified bash-Makefile - $(MAKE) -f bash-Makefile $(MFLAGS) $(MAKEARGS) srcdir=$(srcdir) - -bash-Makefile: $(CPP_MAKEFILE) Makefile machines.h sysdefs.h config.h - @-if [ -f ansi-Makefile ]; then \ - echo "cp ansi-Makefile tmp-Makefile.c"; \ - cp ansi-Makefile tmp-Makefile.c; else \ - echo "cp $(CPP_MAKEFILE) tmp-Makefile.c"; \ - cp $(CPP_MAKEFILE) tmp-Makefile.c; \ - fi - $(RM) $(GETCPPSYMS) - $(SHELL) $(SUPPORTSRC)mkdirs support - $(CC) -o $(GETCPPSYMS) $(GETCPPSYMS_SRC) - rm -f bash-Makefile - @$(SHELL) -c 'echo $(CPP) $(CPPFLAGS) $(CPP_ARGS) tmp-Makefile.c \| $(SQUASH_BLANKS) \> bash-Makefile' - @$(SHELL) -c '$(CPP) $(CPPFLAGS) $(CPP_ARGS) tmp-Makefile.c | $(SQUASH_BLANKS) >bash-Makefile' - rm -f tmp-Makefile.c - @test -s bash-Makefile || { rm -f bash-Makefile ; exit 1; } - -sysdefs.h: $(MKSYSDEFS) - $(SHELL) $(MKSYSDEFS) -s $(srcdir) - -# This is also performed by support/mksysdefs, but there's no way to change -# it if cpp-Makefile is changed without changing anything else, since there -# are no dependencies. This lets you run `make ansi-Makefile'. -ansi-Makefile: $(CPP_MAKEFILE) - grep -v '/\*\*/' $(CPP_MAKEFILE) > $@ - -# Subsequent lines contain targets that are correctly handled by an -# existing bash-Makefile. - -install uninstall newversion architecture: bash-Makefile - $(MAKE) -f bash-Makefile $(MFLAGS) $(MAKEARGS) bindir=$(bindir) \ - prefix=$(prefix) $@ - -tests DEFINES tags documentation: bash-Makefile directory-frob - $(MAKE) -f bash-Makefile $(MFLAGS) $(MAKEARGS) $@ - -clean distclean realclean mostlyclean maintainer-clean: bash-Makefile directory-frob - rm -f .notified - $(MAKE) -f bash-Makefile $(MFLAGS) $(MAKEARGS) $@ - -directory-frob: - -.NOEXPORT: - -.notified: - @echo "" - @echo " You are about to make this version of GNU Bash for" - @echo " this architecture for the first time. If you haven't" - @echo " yet read the README file, you may want to do so. If" - @echo " you wish to report a bug in Bash, or in the installation" - @echo " procedure, please run the bashbug script and include:" - @echo "" - @echo " * a description of the bug," - @echo " * a recipe for recreating the bug reliably," - @echo " * a fix for the bug if you have one!" - @echo "" - @touch .notified diff --git a/Makefile.in b/Makefile.in new file mode 100644 index 0000000..3f15866 --- /dev/null +++ b/Makefile.in @@ -0,0 +1,941 @@ +# Make sure the first target in the makefile is the right one +all: .made + +# Include some boilerplate Gnu makefile definitions. +prefix = @prefix@ + +exec_prefix = @exec_prefix@ +bindir = @bindir@ +libdir = @libdir@ +infodir = @infodir@ +includedir = @includedir@ + +mandir = @mandir@ +manpfx = man + +man1ext = 1 +man1dir = $(mandir)/$(manpfx)$(man1ext) +man3ext = 3 +man3dir = $(mandir)/$(manpfx)$(man3ext) + +topdir = @top_srcdir@ +BUILD_DIR = @BUILD_DIR@ +srcdir = @srcdir@ +VPATH = .:@srcdir@ + +@SET_MAKE@ +CC = @CC@ +YACC = @YACC@ +SHELL=/bin/sh +CP = cp +RM = rm -f +AR = @AR@ +RANLIB = @RANLIB@ + +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_DATA = @INSTALL_DATA@ + +COMPRESS = gzip +COMPRESS_EXT = .gz + +#If you have purify, and want to use it, uncomment this definition or +# run the make as `make PURIFY=purify' +# or run configure with the --with-purify argument. +PURIFY = @PURIFY@ + +# Here is a rule for making .o files from .c files that does not +# force the type of the machine (like -M_MACHINE) into the flags. +.c.o: + $(RM) $@ + $(CC) $(CCFLAGS) -c $< + +# The name of this program. +Program = bash +Machine = @host_cpu@ +OS = @host_os@ +MACHTYPE = @host@ + +RELSTATUS = release + +THIS_SH = $(BUILD_DIR)/$(Program) + +# PROFILE_FLAGS is either -pg, to generate profiling info for use +# with gprof, or nothing (the default). +PROFILE_FLAGS= + +# set to alloca.o if we are using the C alloca in lib/malloc +ALLOCA = @ALLOCA@ +ALLOCA_SOURCE = @ALLOCA_SOURCE@ +ALLOCA_OBJECT = @ALLOCA_OBJECT@ + +# The GNU coding standards don't recognize the possibility that +# other information besides optimization and debugging might be +# passed to cc. A different name should have been used. +CFLAGS = @CFLAGS@ +LOCAL_CFLAGS = @LOCAL_CFLAGS@ +DEFS = @DEFS@ +LOCAL_LIBS = @LOCAL_LIBS@ +LIBS = $(BUILTINS_LIB) $(LIBRARIES) $(LOCAL_LIBS) @LIBS@ +LDFLAGS = @LDFLAGS@ $(LOCAL_LDFLAGS) $(PROFILE_FLAGS) $(CFLAGS) +LOCAL_LDFLAGS = @LOCAL_LDFLAGS@ + +SYSTEM_FLAGS = -DPROGRAM='"$(Program)"' -DHOSTTYPE='"$(Machine)"' -DOSTYPE='"$(OS)"' -DMACHTYPE='"$(MACHTYPE)"' + +CCFLAGS = $(PROFILE_FLAGS) $(SYSTEM_FLAGS) -DSHELL \ + $(DEFS) $(LOCAL_CFLAGS) $(CPPFLAGS) $(INCLUDES) $(CFLAGS) + +INCLUDES = -I. -I$(srcdir) -I$(LIBSRC) + +GCC_LINT_FLAGS = -ansi -Wall -Wshadow -Wpointer-arith -Wcast-qual \ + -Wwrite-strings -Werror -Wstrict-prototypes \ + -Wmissing-prototypes +GCC_LINT_CFLAGS = $(CCFLAGS) $(GCC_LINT_FLAGS) + +# +# Support libraries +# + +dot = . + +LIBSUBDIR = lib +LIBSRC = $(srcdir)/$(LIBSUBDIR) + +SUBDIR_INCLUDES = -I. -I$(topdir) -I$(topdir)/$(LIBSUBDIR) -I$(includedir) + +# we assume for now that readline source is being shipped with bash +RL_LIBSRC = $(LIBSRC)/readline +RL_LIBDOC = $(RL_LIBSRC)/doc +RL_LIBDIR = $(dot)/$(LIBSUBDIR)/readline +RL_ABSSRC = ${topdir}/$(RL_LIBDIR) + +READLINE_LIB = @READLINE_LIB@ +READLINE_LIBRARY = $(RL_LIBDIR)/libreadline.a +READLINE_LDFLAGS = -L${RL_LIBDIR} +READLINE_DEP = @READLINE_DEP@ + +# The source, object and documentation of the GNU Readline library. +READLINE_SOURCE = $(RL_LIBSRC)/rldefs.h $(RL_LIBSRC)/rlconf.h \ + $(RL_LIBSRC)/readline.h $(RL_LIBSRC)/tcap.h \ + $(RL_LIBSRC)/chardefs.h $(RL_LIBSRC)/keymaps.h \ + $(RL_LIBSRC)/history.h $(RL_LIBSRC)/histlib.h \ + $(RL_LIBSRC)/posixstat.h $(RL_LIBSRC)/tilde.h \ + $(RL_LIBSRC)/funmap.c $(RL_LIBSRC)/emacs_keymap.c \ + $(RL_LIBSRC)/search.c $(RL_LIBSRC)/vi_keymap.c \ + $(RL_LIBSRC)/keymaps.c $(RL_LIBSRC)/parens.c \ + $(RL_LIBSRC)/vi_mode.c $(RL_LIBSRC)/callback.c \ + $(RL_LIBSRC)/readline.c $(RL_LIBSRC)/tilde.c \ + $(RL_LIBSRC)/rltty.c $(RL_LIBSRC)/complete.c \ + $(RL_LIBSRC)/bind.c $(RL_LIBSRC)/isearch.c \ + $(RL_LIBSRC)/display.c $(RL_LIBSRC)/signals.c \ + $(RL_LIBSRC)/util.c $(RL_LIBSRC)/kill.c \ + $(RL_LIBSRC)/undo.c $(RL_LIBSRC)/macro.c \ + $(RL_LIBSRC)/terminal.c $(RL_LIBSRC)/nls.c \ + $(RL_LIBSRC)/input.c $(RL_LIBSRC)/xmalloc.c \ + $(RL_LIBSRC)/histexpand.c $(RL_LIBSRC)/history.c \ + $(RL_LIBSRC)/histsearch.c $(RL_LIBSRC)/histfile.c + +READLINE_OBJ = $(RL_LIBDIR)/readline.o $(RL_LIBDIR)/funmap.o \ + $(RL_LIBDIR)/parens.o $(RL_LIBDIR)/search.o \ + $(RL_LIBDIR)/keymaps.o $(RL_LIBDIR)/xmalloc.o \ + $(RL_LIBDIR)/rltty.o $(RL_LIBDIR)/complete.o \ + $(RL_LIBDIR)/bind.o $(RL_LIBDIR)/isearch.o \ + $(RL_LIBDIR)/display.o $(RL_LIBDIR)/signals.o \ + $(RL_LIBDIR)/tilde.o $(RL_LIBDIR)/util.o \ + $(RL_LIBDIR)/kill.o $(RL_LIBDIR)/undo.o $(RL_LIBDIR)/nls.o \ + $(RL_LIBDIR)/macro.o $(RL_LIBDIR)/input.o \ + $(RL_LIBDIR)/terminal.o $(RL_LIBDIR)/callback.o \ + $(RL_LIBDIR)/history.o $(RL_LIBDIR)/histexpand.o \ + $(RL_LIBDIR)/histsearch.o $(RL_LIBDIR)/histfile.o + +HIST_LIBSRC = $(LIBSRC)/readline +HIST_LIBDIR = $(dot)/$(LIBSUBDIR)/readline +HIST_ABSSRC = ${topdir}/$(HIST_LIBDIR) + +HISTORY_LIB = @HISTORY_LIB@ +HISTORY_LIBRARY = $(HIST_LIBDIR)/libhistory.a +HISTORY_LDFLAGS = -L$(HIST_LIBDIR) +HISTORY_DEP = @HISTORY_DEP@ + +# The source, object and documentation of the history library. +HISTORY_SOURCE = $(HIST_LIBSRC)/history.c $(HIST_LIBSRC)/histexpand.c \ + $(HIST_LIBSRC)/histsearch.c $(HIST_LIBSRC)/histfile.c \ + $(HIST_LIBSRC)/history.h $(HIST_LIBSRC)/histlib.h +HISTORY_OBJ = $(HIST_LIBDIR)/history.o $(HIST_LIBDIR)/histexpand.o \ + $(HIST_LIBDIR)/histsearch.o $(HIST_LIBDIR)/histfile.o + +# You only need termcap (or curses) if you are linking with GNU Readline. +TERM_LIBSRC = $(LIBSRC)/termcap +TERM_LIBDIR = $(dot)/$(LIBSUBDIR)/termcap +TERM_ABSSRC = ${topdir}/$(TERM_LIBDIR) + +TERMCAP_LIB = @TERMCAP_LIB@ +TERMCAP_LIBRARY = $(TERM_LIBDIR)/libtermcap.a +TERMCAP_LDFLAGS = -L$(TERM_LIBDIR) +TERMCAP_DEP = @TERMCAP_DEP@ + +TERMCAP_SOURCE = $(TERM_LIBSRC)/termcap.c $(TERM_LIBSRC)/tparam.c +TERMCAP_OBJ = $(TERM_LIBDIR)/termcap.o $(TERM_LIBDIR)/tparam.o + +GLOB_LIBSRC = $(LIBSRC)/glob +GLOB_LIBDIR = $(dot)/$(LIBSUBDIR)/glob +GLOB_ABSSRC = ${topdir}/$(GLOB_LIBDIR) + +GLOB_LIB = -lglob +GLOB_LIBRARY = $(GLOB_LIBDIR)/libglob.a +GLOB_LDFLAGS = -L$(GLOB_LIBDIR) +GLOB_DEP = $(GLOB_LIBRARY) + +GLOB_SOURCE = $(GLOB_LIBSRC)/glob.c $(GLOB_LIBSRC)/fnmatch.c \ + $(GLOB_LIBSRC)/glob.h $(GLOB_LIBSRC)/fnmatch.h +GLOB_OBJ = $(GLOB_LIBDIR)/glob.o $(GLOB_LIBDIR)/fnmatch.o + +# The source, object and documentation for the GNU Tilde library. +TILDE_LIBSRC = $(LIBSRC)/tilde +TILDE_LIBDIR = $(dot)/$(LIBSUBDIR)/tilde +TILDE_ABSSRC = ${topdir}/$(TILDE_LIBDIR) + +TILDE_LIB = -ltilde +TILDE_LIBRARY = $(TILDE_LIBDIR)/libtilde.a +TILDE_LDFLAGS = -L$(TILDE_LIBDIR) +TILDE_DEP = $(TILDE_LIBRARY) + +TILDE_SOURCE = $(TILDE_LIBSRC)/tilde.c $(TILDE_LIBSRC)/tilde.h +TILDE_OBJ = $(TILDE_LIBDIR)/tilde.o + +# Our malloc. +ALLOC_LIBSRC = $(LIBSRC)/malloc +ALLOC_LIBDIR = $(dot)/$(LIBSUBDIR)/malloc +ALLOC_ABSSRC = ${topdir}/$(ALLOC_LIBDIR) + +ALLOCA_DEP = $(ALLOC_LIBDIR)/@ALLOCA@ + +MALLOC_OBJ = $(ALLOC_LIBDIR)/@MALLOC@ +MALLOC_SRC = @MALLOC_SRC@ +MALLOC_CFLAGS = -Drcheck -Dbotch=programming_error + +MALLOC_LIB = -lmalloc +MALLOC_LIBRARY = $(ALLOC_LIBDIR)/libmalloc.a +MALLOC_LDFLAGS = -L$(ALLOC_LIBDIR) +MALLOC_DEP = $(MALLOC_LIBRARY) + +ALLOC_HEADERS = $(ALLOC_LIBSRC)/getpagesize.h + +$(MALLOC_LIBRARY): $(MALLOC_SRC) + @$(RM) $@ + @(cd $(ALLOC_LIBDIR) && \ + $(MAKE) $(MFLAGS) \ + MALLOC_CFLAGS="$(MALLOC_CFLAGS)" libmalloc.a ) || exit 1 + +BASHPOSIX_LIB = $(LIBSRC)/posixheaders +BASHPOSIX_SUPPORT = $(BASHPOSIX_LIB)/posixstat.h $(BASHPOSIX_LIB)/ansi_stdlib.h \ + $(BASHPOSIX_LIB)/memalloc.h $(BASHPOSIX_LIB)/stdc.h + +LIBRARIES = $(READLINE_LIB) $(HISTORY_LIB) $(TERMCAP_LIB) $(GLOB_LIB) \ + $(TILDE_LIB) $(MALLOC_LIB) $(LOCAL_LIBS) + +LIBDEP = $(READLINE_DEP) $(TERMCAP_DEP) $(GLOB_DEP) $(HISTORY_DEP) \ + $(TILDE_DEP) $(MALLOC_DEP) + +LIBRARY_LDFLAGS = $(READLINE_LDFLAGS) $(HISTORY_LDFLAGS) $(TILDE_LDFLAGS) \ + $(GLOB_LDFLAGS) $(MALLOC_LDFLAGS) + +# +# The shell itself +# + +# The main source code for the Bourne Again SHell. +CSOURCES = shell.c eval.c parse.y general.c make_cmd.c print_cmd.c y.tab.c \ + dispose_cmd.c execute_cmd.c variables.c $(GLOBC) version.c \ + expr.c copy_cmd.c flags.c subst.c hashlib.c mailcheck.c \ + test.c trap.c jobs.c nojobs.c $(ALLOC_FILES) braces.c \ + vprint.c input.c bashhist.c array.c sig.c pathexp.c oslib.c \ + unwind_prot.c siglist.c getcwd.c $(RL_SUPPORT_SRC) error.c \ + list.c stringlib.c locale.c xmalloc.c + +HSOURCES = shell.h flags.h trap.h hashlib.h jobs.h builtins.h alias.c y.tab.h \ + general.h variables.h config.h $(ALLOC_HEADERS) alias.h maxpath.h \ + quit.h posixstat.h filecntl.h unwind_prot.h \ + command.h input.h error.h bashansi.h dispose_cmd.h make_cmd.h \ + subst.h externs.h siglist.h bashhist.h bashline.h bashtypes.h \ + array.h sig.h mailcheck.h bashtty.h + +SOURCES = $(CSOURCES) $(HSOURCES) $(BUILTIN_DEFS) + +# object files chosen based on running of configure +JOBS_O = @JOBS_O@ + +# Matching object files. +OBJECTS = shell.o eval.o y.tab.o general.o make_cmd.o print_cmd.o $(GLOBO) \ + dispose_cmd.o execute_cmd.o variables.o copy_cmd.o error.o \ + expr.o flags.o $(JOBS_O) subst.o hashlib.o mailcheck.o test.o \ + trap.o input.o unwind_prot.o pathexp.o sig.o version.o \ + alias.o array.o braces.o bracecomp.o bashhist.o bashline.o \ + getcwd.o siglist.o vprint.o oslib.o list.o stringlib.o \ + locale.o xmalloc.o + +# Where the source code of the shell builtins resides. +BUILTIN_SRCDIR=$(srcdir)/builtins +DEFSRC=$(BUILTIN_SRCDIR) +BUILTIN_ABSSRC=${topdir}/builtins +DEFDIR = $(dot)/builtins + +BUILTIN_DEFS = $(DEFSRC)/alias.def $(DEFSRC)/bind.def $(DEFSRC)/break.def \ + $(DEFSRC)/builtin.def $(DEFSRC)/cd.def $(DEFSRC)/colon.def \ + $(DEFSRC)/command.def $(DEFSRC)/declare.def \ + $(DEFSRC)/echo.def $(DEFSRC)/enable.def $(DEFSRC)/eval.def \ + $(DEFSRC)/exec.def $(DEFSRC)/exit.def $(DEFSRC)/fc.def \ + $(DEFSRC)/fg_bg.def $(DEFSRC)/hash.def $(DEFSRC)/help.def \ + $(DEFSRC)/history.def $(DEFSRC)/jobs.def $(DEFSRC)/kill.def \ + $(DEFSRC)/let.def $(DEFSRC)/read.def $(DEFSRC)/return.def \ + $(DEFSRC)/set.def $(DEFSRC)/setattr.def $(DEFSRC)/shift.def \ + $(DEFSRC)/source.def $(DEFSRC)/suspend.def $(DEFSRC)/test.def \ + $(DEFSRC)/times.def $(DEFSRC)/trap.def $(DEFSRC)/type.def \ + $(DEFSRC)/ulimit.def $(DEFSRC)/umask.def $(DEFSRC)/wait.def \ + $(DEFSRC)/getopts.def $(DEFSRC)/reserved.def \ + $(DEFSRC)/pushd.def $(DEFSRC)/shopt.def +BUILTIN_C_SRC = $(DEFSRC)/mkbuiltins.c $(DEFSRC)/common.c \ + $(DEFSRC)/evalstring.c $(DEFSRC)/evalfile.c \ + $(DEFSRC)/bashgetopt.c $(GETOPT_SOURCE) \ + $(DEFSRC)/hashcom.h +BUILTIN_C_OBJ = $(DEFDIR)/common.o $(DEFDIR)/evalstring.o \ + $(DEFDIR)/evalfile.o $(DEFDIR)/bashgetopt.o +BUILTIN_OBJS = $(DEFDIR)/alias.o $(DEFDIR)/bind.o $(DEFDIR)/break.o \ + $(DEFDIR)/builtin.o $(DEFDIR)/cd.o $(DEFDIR)/colon.o \ + $(DEFDIR)/command.o $(DEFDIR)/declare.o \ + $(DEFDIR)/echo.o $(DEFDIR)/enable.o $(DEFDIR)/eval.o \ + $(DEFDIR)/exec.o $(DEFDIR)/exit.o $(DEFDIR)/fc.o \ + $(DEFDIR)/fg_bg.o $(DEFDIR)/hash.o $(DEFDIR)/help.o \ + $(DEFDIR)/history.o $(DEFDIR)/jobs.o $(DEFDIR)/kill.o \ + $(DEFDIR)/let.o $(DEFDIR)/pushd.o $(DEFDIR)/read.o \ + $(DEFDIR)/return.o $(DEFDIR)/shopt.o \ + $(DEFDIR)/set.o $(DEFDIR)/setattr.o $(DEFDIR)/shift.o \ + $(DEFDIR)/source.o $(DEFDIR)/suspend.o $(DEFDIR)/test.o \ + $(DEFDIR)/times.o $(DEFDIR)/trap.o $(DEFDIR)/type.o \ + $(DEFDIR)/ulimit.o $(DEFDIR)/umask.o $(DEFDIR)/wait.o \ + $(DEFDIR)/getopts.o $(BUILTIN_C_OBJ) +GETOPT_SOURCE = $(DEFSRC)/getopt.c $(DEFSRC)/getopt.h +PSIZE_SOURCE = $(DEFSRC)/psize.sh $(DEFSRC)/psize.c + +BUILTINS_LIBRARY = builtins/libbuiltins.a +BUILTINS_LIB = -lbuiltins +BUILTINS_LDFLAGS = -L$(DEFDIR) +BUILTINS_DEP = $(BUILTINS_LIBRARY) + +# Documentation for the shell. +DOCSRC = $(srcdir)/doc +DOCDIR = ./doc + +SIGNAMES_SUPPORT = $(SUPPORT_SRC)mksignames.c + +SUPPORT_SRC = $(srcdir)/support/ +SDIR = ./support/ + +CREATED_SUPPORT = signames.h recho zecho tests/recho tests/zecho \ + tests/printenv mksignames mkversion +CREATED_CONFIGURE = config.h config.cache config.status config.log \ + stamp-h +CREATED_MAKEFILES = Makefile builtins/Makefile doc/Makefile \ + lib/readline/Makefile lib/glob/Makefile \ + lib/tilde/Makefile lib/malloc/Makefile \ + lib/termcap/Makefile + +# Keep GNU Make from exporting the entire environment for small machines. +.NOEXPORT: + +.made: $(Program) bashbug + cp .machine .made + +$(Program): .build $(OBJECTS) $(BUILTINS_DEP) $(LIBDEP) $(srcdir)/.distribution + $(RM) $@ + $(PURIFY) $(CC) $(LDFLAGS) $(BUILTINS_LDFLAGS) $(LIBRARY_LDFLAGS) -o $(Program) $(OBJECTS) $(LIBS) + ls -l $(Program) + size $(Program) + +.build: $(SOURCES) config.h Makefile mkversion version.h .machine + @echo + @echo " ***********************************************************" + @echo " * *" + @echo " * Making Bash-`cat $(srcdir)/.distribution`.`cat $(srcdir)/.patchlevel`-$(RELSTATUS) for a $(Machine) running $(OS)" + @echo " * *" + @echo " ***********************************************************" + @echo + +.machine: $(SOURCES) config.h Makefile mkversion version.h + @echo "$(Program) last made for a $(Machine) running $(OS)" >.machine + +bashbug: $(SUPPORT_SRC)bashbug.sh mkversion config.h Makefile + @sed -e "s:!MACHINE!:$(Machine):" -e "s:!OS!:$(OS):" \ + -e "s:!CFLAGS!:$(CCFLAGS):" -e "s:!CC!:$(CC):" \ + -e "s:!RELEASE!:`cat $(srcdir)/.distribution`:" \ + -e "s:!PATCHLEVEL!:`cat $(srcdir)/.patchlevel`:" \ + -e "s:!MACHTYPE!:$(MACHTYPE):" -e "s:!RELSTATUS!:$(RELSTATUS):" \ + $(SUPPORT_SRC)bashbug.sh > $@ + @chmod a+rx bashbug + +strip: $(Program) .made + strip $(Program) + ls -l $(Program) + size $(Program) + +version.h: $(SOURCES) config.h Makefile mkversion .patchlevel .distribution + if ./mkversion -dir $(srcdir) -build -status $(RELSTATUS); then mv -f newversion.h version.h; fi + +# old rules +y.tab.o: y.tab.c parser-built +y.tab.c: parser-built +y.tab.h: parser-built +parser-built: parse.y command.h stdc.h input.h + $(RM) $@ + -if test -f y.tab.h; then mv -f y.tab.h old-y.tab.h; fi + $(YACC) -d $(srcdir)/parse.y + -if cmp -s old-y.tab.h y.tab.h; then mv old-y.tab.h y.tab.h; fi + touch $@ + +# experimental new rules - work with GNU make but not BSD (or OSF) make +#y.tab.o: y.tab.c y.tab.h +#y.tab.c y.tab.h: parse.y command.h stdc.h input.h +# -if test -f y.tab.h; then mv -f y.tab.h old-y.tab.h; fi +# $(YACC) -d $(srcdir)/parse.y +# -if cmp -s old-y.tab.h y.tab.h; then mv old-y.tab.h y.tab.h; fi + +$(READLINE_LIBRARY): config.h $(READLINE_SOURCE) + @echo making $@ in ${RL_LIBDIR} + @(cd ${RL_LIBDIR} && \ + $(MAKE) $(MFLAGS) APP_CFLAGS=-DSHELL libreadline.a) || exit 1 + +$(HISTORY_LIBRARY): config.h $(HISTORY_SOURCE) + @echo making $@ in ${HIST_LIBDIR} + @(cd ${HIST_LIBDIR} && \ + $(MAKE) $(MFLAGS) libhistory.a) || exit 1 + +$(GLOB_LIBRARY): config.h $(GLOB_SOURCE) + @echo making $@ in ${GLOB_LIBDIR} + @(cd ${GLOB_LIBDIR} && \ + $(MAKE) $(MFLAGS) libglob.a) || exit 1 + +$(TILDE_LIBRARY): config.h $(TILDE_SOURCE) + @echo making $@ in ${TILDE_LIBDIR} + @(cd ${TILDE_LIBDIR} && \ + $(MAKE) $(MFLAGS) libtilde.a) || exit 1 + +$(TERMCAP_LIBRARY): config.h ${TERMCAP_SOURCE} + @echo making $@ in ${TERMCAP_LIBDIR} + @(cd ${TERMCAP_LIBDIR} && \ + $(MAKE) $(MFLAGS) libtermcap.a) || exit 1 + +mksignames: $(SUPPORT_SRC)mksignames.c + $(CC) $(CCFLAGS) $(CPPFLAGS) -o $@ $(SUPPORT_SRC)mksignames.c + +signames.h: mksignames + $(RM) $@ + ./mksignames $@ + +$(BUILTINS_LIBRARY): $(BUILTIN_DEFS) $(BUILTIN_C_SRC) config.h memalloc.h + @(cd $(DEFDIR) && $(MAKE) $(MFLAGS) libbuiltins.a ) || exit 1 + +# these require special rules to circumvent make builtin rules +builtins/common.o: $(BUILTIN_SRCDIR)/common.c + @(cd $(DEFDIR) && $(MAKE) $(MFLAGS) common.o) || exit 1 + +builtins/bashgetopt.o: $(BUILTIN_SRCDIR)/bashgetopt.c + @(cd $(DEFDIR) && $(MAKE) $(MFLAGS) bashgetopt.o) || exit 1 + +builtins/builtext.h: $(BUILTIN_DEFS) + @(cd $(DEFDIR) && $(MAKE) $(MFLAGS) builtext.h ) || exit 1 + +# For the justification of the following Makefile rules, see node +# `Automatic Remaking' in GNU Autoconf documentation. + +Makefile: config.status $(srcdir)/Makefile.in + CONFIG_FILES=$@ CONFIG_HEADERS= $(SHELL) ./config.status + +Makefiles makefiles: config.status $(srcdir)/Makefile.in + @for mf in $(CREATED_MAKEFILES); do \ + CONFIG_FILES=$$mf CONFIG_HEADERS= $(SHELL) ./config.status ; \ + done + +config.h: stamp-h + +stamp-h: config.status $(srcdir)/config.h.in $(srcdir)/config.h.top $(srcdir)/config.h.bot + CONFIG_FILES= CONFIG_HEADERS=config.h $(SHELL) ./config.status + +config.status: $(srcdir)/configure + $(SHELL) ./config.status --recheck + +# comment out for distribution +#$(srcdir)/configure: $(srcdir)/configure.in $(srcdir)/aclocal.m4 +# cd $(srcdir) && autoconf + +mkversion: $(SUPPORT_SRC)mkversion.c + $(CC) $(CCFLAGS) -I.. -o $@ $(SUPPORT_SRC)mkversion.c + +newversion: mkversion + $(RM) .build + ./mkversion -dir $(srcdir) -dist + mv -f newversion.h version.h + $(MAKE) -f $(srcdir)/Makefile $(MFLAGS) srcdir=$(srcdir) + +doc documentation: force + @(cd $(DOCDIR) ; $(MAKE) $(MFLAGS) ) + +info dvi ps: force + @(cd $(DOCDIR) ; $(MAKE) $(MFLAGS) CFLAGS='$(CCFLAGS)' $@ ) + +force: + +tags: $(SOURCES) $(BUILTIN_C_SRC) $(LIBRARY_SOURCE) + etags $(SOURCES) $(BUILTIN_C_SRC) $(LIBRARY_SOURCE) + +TAGS: $(SOURCES) $(BUILTIN_C_SRC) $(LIBRARY_SOURCE) + ctags -x $(SOURCES) $(BUILTIN_C_SRC) $(LIBRARY_SOURCE) > $@ + +# Targets that actually do things not part of the build + +installdirs: + @${SHELL} $(SUPPORT_SRC)mkdirs $(bindir) + @${SHELL} $(SUPPORT_SRC)mkdirs $(man1dir) $(man3dir) + @${SHELL} $(SUPPORT_SRC)mkdirs $(infodir) + +install: .made installdirs + $(INSTALL_PROGRAM) $(Program) $(bindir)/$(Program) + $(INSTALL_PROGRAM) bashbug $(bindir)/bashbug + -( cd $(DOCDIR) ; $(MAKE) $(MFLAGS) \ + man1dir=$(man1dir) man1ext=$(man1ext) \ + man3dir=$(man3dir) man3ext=$(man3ext) \ + infodir=$(infodir) $@ ) + +install-strip: + $(MAKE) $(MFLAGS) INSTALL_PROGRAM='$(INSTALL_PROGRAM) -s' \ + prefix=${prefix} exec_prefix=${exec_prefix} install + +uninstall: .made + $(RM) $(bindir)/$(Program) $(bindir)/bashbug + -( cd $(DOCDIR) ; $(MAKE) $(MFLAGS) \ + man1dir=$(man1dir) man1ext=$(man1ext) \ + man3dir=$(man3dir) man3ext=$(man3ext) \ + infodir=$(infodir) $@ ) + +.PHONY: basic-clean clean realclean maintainer-clean distclean mostlyclean +basic-clean: + $(RM) $(OBJECTS) $(Program) bashbug + $(RM) .build .made .machine version.h + +clean: basic-clean + ( cd $(DOCDIR) && $(MAKE) $(MFLAGS) $@ ) + ( cd builtins && $(MAKE) $(MFLAGS) $@ ) + -(cd $(RL_LIBDIR) && $(MAKE) $(MFLAGS) $@) + -(cd $(HIST_LIBDIR) && test -f Makefile && $(MAKE) $(MFLAGS) $@) + -(cd $(TERM_LIBDIR) && $(MAKE) $(MFLAGS) $@) + -(cd $(GLOB_LIBDIR) && $(MAKE) $(MFLAGS) $@) + -(cd $(TILDE_LIBDIR) && $(MAKE) $(MFLAGS) $@) + -(cd $(ALLOC_LIBDIR) && $(MAKE) $(MFLAGS) $@) + $(RM) $(CREATED_SUPPORT) + +mostlyclean: basic-clean + ( cd $(DOCDIR) && $(MAKE) $(MFLAGS) $@ ) + ( cd builtins && $(MAKE) $(MFLAGS) $@ ) + -(cd $(RL_LIBDIR) && $(MAKE) $(MFLAGS) $@) + -(cd $(HIST_LIBDIR) && test -f Makefile && $(MAKE) $(MFLAGS) $@) + -(cd $(TERM_LIBDIR) && $(MAKE) $(MFLAGS) $@) + -(cd $(GLOB_LIBDIR) && $(MAKE) $(MFLAGS) $@) + -(cd $(TILDE_LIBDIR) && $(MAKE) $(MFLAGS) $@) + -(cd $(ALLOC_LIBDIR) && $(MAKE) $(MFLAGS) $@) + +distclean: basic-clean + ( cd $(DOCDIR) && $(MAKE) $(MFLAGS) $@ ) + ( cd builtins && $(MAKE) $(MFLAGS) $@ ) + -(cd $(RL_LIBDIR) && $(MAKE) $(MFLAGS) $@) + -(cd $(HIST_LIBDIR) && test -f Makefile && $(MAKE) $(MFLAGS) $@) + -(cd $(TERM_LIBDIR) && $(MAKE) $(MFLAGS) $@) + -(cd $(GLOB_LIBDIR) && $(MAKE) $(MFLAGS) $@) + -(cd $(TILDE_LIBDIR) && $(MAKE) $(MFLAGS) $@) + -(cd $(ALLOC_LIBDIR) && $(MAKE) $(MFLAGS) $@) + $(RM) $(CREATED_CONFIGURE) tags TAGS + $(RM) $(CREATED_SUPPORT) Makefile $(CREATED_MAKEFILES) + +maintainer-clean: basic-clean + @echo This command is intended for maintainers to use. + @echo It deletes files that may require special tools to rebuild. + $(RM) y.tab.c y.tab.h parser-built tags TAGS + ( cd $(DOCDIR) && $(MAKE) $(MFLAGS) $@ ) + ( cd builtins && $(MAKE) $(MFLAGS) $@ ) + -(cd $(RL_LIBDIR) && $(MAKE) $(MFLAGS) $@) + -(cd $(HIST_LIBDIR) && test -f Makefile && $(MAKE) $(MFLAGS) $@) + -(cd $(TERM_LIBDIR) && $(MAKE) $(MFLAGS) $@) + -(cd $(GLOB_LIBDIR) && $(MAKE) $(MFLAGS) $@) + -(cd $(TILDE_LIBDIR) && $(MAKE) $(MFLAGS) $@) + -(cd $(ALLOC_LIBDIR) && $(MAKE) $(MFLAGS) $@) + $(RM) $(CREATED_CONFIGURE) $(CREATED_MAKEFILES) + $(RM) $(CREATED_SUPPORT) Makefile + +recho: $(SUPPORT_SRC)recho.c + @$(CC) -o $@ $(SUPPORT_SRC)recho.c + +zecho: $(SUPPORT_SRC)zecho.c + @$(CC) -o $@ $(SUPPORT_SRC)zecho.c + +tests check: force $(Program) recho zecho + @-test -d tests || mkdir tests + @cp recho zecho $(SUPPORT_SRC)printenv tests + @( cd $(srcdir)/tests && \ + PATH=$$PATH:$(BUILD_DIR)/tests THIS_SH=$(THIS_SH) sh run-all ) + +symlinks: + $(SHELL) $(SUPPORT_SRC)fixlinks -s $(srcdir) + +dist: force + @echo Bash distributions are created using $(srcdir)/support/mkdist. + @echo Here is a sample of the necessary commands: + @echo $(Program) $(srcdir)/support/mkdist -m $(srcdir)/MANIFEST -s $(srcdir) -r ${Program} `cat $(srcdir)/.distribution` + @echo tar cf $(Program)-`cat $(srcdir)/.distribution`.tar ${Program}-`cat $(srcdir)/.distribution` + @echo gzip $(Program)-`cat $(srcdir)/.distribution`.tar + +############################ DEPENDENCIES ############################### + +# Files that depend on the definitions in config.h.top, which are not meant +# to be changed +shell.o: config.h.top +input.o: config.h.top +y.tab.o: config.h.top +jobs.o: config.h.top +nojobs.o: config.h.top +execute_cmd.o: config.h.top +builtins/break.o: config.h.top +builtins/common.o: config.h.top +builtins/echo.o: config.h.top +variables.o: config.h.top +builtins/command.o: config.h.top + +copy_cmd.o: shell.h bashjmp.h sig.h command.h stdc.h hashlib.h +copy_cmd.o: general.h variables.h config.h memalloc.h quit.h +copy_cmd.o: dispose_cmd.h make_cmd.h subst.h externs.h +dispose_cmd.o: shell.h bashjmp.h sig.h command.h stdc.h +dispose_cmd.o: general.h variables.h config.h memalloc.h quit.h +dispose_cmd.o: dispose_cmd.h make_cmd.h subst.h externs.h +error.o: error.h +execute_cmd.o: shell.h bashjmp.h sig.h command.h stdc.h y.tab.h posixstat.h +execute_cmd.o: general.h variables.h config.h memalloc.h quit.h hashlib.h jobs.h +execute_cmd.o: unwind_prot.h siglist.h builtins/builtext.h config.h flags.h +execute_cmd.o: dispose_cmd.h make_cmd.h subst.h externs.h bashtypes.h +execute_cmd.o: pathexp.h +expr.o: shell.h bashjmp.h sig.h command.h stdc.h hashlib.h +expr.o: general.h variables.h config.h memalloc.h quit.h +expr.o: dispose_cmd.h make_cmd.h subst.h externs.h +flags.o: flags.h stdc.h config.h memalloc.h general.h quit.h +general.o: shell.h bashjmp.h sig.h command.h stdc.h maxpath.h +general.o: general.h variables.h config.h memalloc.h quit.h unwind_prot.h +general.o: dispose_cmd.h make_cmd.h subst.h externs.h stdc.h +getcwd.o: config.h config.h.bot bashtypes.h maxpath.h posixstat.h +hashlib.o: shell.h bashjmp.h sig.h command.h stdc.h hashlib.h +hashlib.o: general.h variables.h config.h memalloc.h quit.h +hashlib.o: dispose_cmd.h make_cmd.h subst.h externs.h stdc.h +jobs.o: shell.h bashjmp.h sig.h command.h stdc.h hashlib.h trap.h jobs.h +jobs.o: general.h variables.h config.h memalloc.h quit.h bashtty.h siglist.h +jobs.o: dispose_cmd.h make_cmd.h subst.h externs.h builtins/builtext.h +jobs.o: unwind_prot.h +mailcheck.o: posixstat.h maxpath.h variables.h +mailcheck.o: hashlib.h quit.h mailcheck.h +make_cmd.o: shell.h bashjmp.h sig.h command.h stdc.h flags.h input.h +make_cmd.o: general.h variables.h config.h memalloc.h quit.h bashtypes.h +make_cmd.o: dispose_cmd.h make_cmd.h subst.h externs.h +y.tab.o: shell.h bashjmp.h sig.h command.h stdc.h flags.h maxpath.h alias.h +y.tab.o: general.h variables.h config.h memalloc.h quit.h mailcheck.h parser.h +y.tab.o: dispose_cmd.h make_cmd.h subst.h externs.h bashtypes.h bashline.h +y.tab.o: builtins/builtext.h +print_cmd.o: shell.h bashjmp.h sig.h command.h stdc.h y.tab.h +print_cmd.o: general.h variables.h config.h memalloc.h quit.h +print_cmd.o: dispose_cmd.h make_cmd.h subst.h externs.h unwind_prot.h +shell.o: shell.h bashjmp.h sig.h command.h stdc.h flags.h stdc.h +shell.o: general.h variables.h config.h memalloc.h quit.h +shell.o: dispose_cmd.h make_cmd.h subst.h externs.h mailcheck.h +shell.o: posixstat.h filecntl.h jobs.h input.h +subst.o: shell.h bashjmp.h sig.h command.h stdc.h flags.h jobs.h siglist.h +subst.o: general.h variables.h config.h memalloc.h quit.h bashtypes.h +subst.o: dispose_cmd.h make_cmd.h subst.h externs.h execute_cmd.h +subst.o: ${DEFSRC}/getopt.h pathexp.h bashline.h +pathexp.o: config.h shell.h bashjmp.h command.h stdc.h general.h +pathexp.o: error.h variables.h quit.h maxpath.h unwind_prot.h dispose_cmd.h +pathexp.o: make_cmd.h subst.h sig.h pathnames.h externs.h +pathexp.o: $(GLOB_LIBSRC)/glob.h $(GLOB_LIBSRC)/fnmatch.h +test.o: posixstat.h +trap.o: trap.h shell.h bashjmp.h sig.h command.h stdc.h hashlib.h unwind_prot.h +trap.o: general.h variables.h config.h memalloc.h quit.h signames.h +trap.o: dispose_cmd.h make_cmd.h subst.h externs.h +unwind_prot.o: config.h memalloc.h general.h unwind_prot.h sig.h +variables.o: shell.h bashjmp.h sig.h command.h stdc.h hashlib.h flags.h +variables.o: config.h memalloc.h general.h variables.h quit.h mailcheck.h +variables.o: execute_cmd.h dispose_cmd.h make_cmd.h subst.h externs.h +sig.o: shell.h bashjmp.h sig.h command.h stdc.h hashlib.h flags.h +sig.o: config.h memalloc.h general.h variables.h quit.h +sig.o: bashtypes.h jobs.h bashline.h unwind_prot.h +version.o: version.h .build +oslib.o: config.h bashtypes.h posixstat.h filecntl.h bashansi.h maxpath.h +oslib.o: shell.h bashjmp.h sig.h command.h stdc.h mailcheck.h +oslib.o: general.h error.h variables.h quit.h unwind_prot.h dispose_cmd.h +oslib.o: make_cmd.h subst.h pathnames.h externs.h +xmalloc.o: config.h ansi_stdlib.h general.h error.h + +eval.o: config.h bashansi.h shell.h trap.h flags.h builtins/common.h +eval.o: input.h execute_cmd.h +eval.o: bashjmp.h command.h general.h error.h variables.h quit.h +eval.o: maxpath.h unwind_prot.h dispose_cmd.h make_cmd.h subst.h +eval.o: sig.h pathnames.h externs.h + +locale.o: bashintl.h bashansi.h config.h bashtypes.h shell.h +locale.o: bashjmp.h command.h general.h error.h variables.h quit.h +locale.o: maxpath.h unwind_prot.h dispose_cmd.h make_cmd.h subst.h +locale.o: sig.h pathnames.h externs.h + + +alias.o: ansi_stdlib.h +bashline.o: ansi_stdlib.h +variables.o: ansi_stdlib.h +shell.o: ansi_stdlib.h +error.o: ansi_stdlib.h +hash.o: ansi_stdlib.h +signames.o: ansi_stdlib.h +expr.o: ansi_stdlib.h +general.o: ansi_stdlib.h +input.o: ansi_stdlib.h + +jobs.o: jobs.c +nojobs.o: nojobs.c + +array.o: general.h shell.h bashjmp.h sig.h variables.h quit.h config.h +array.o: command.h error.h maxpath.h unwind_prot.h dispose_cmd.h memalloc.h +array.o: make_cmd.h subst.h externs.h +array.o: array.h stdc.h $(DEFSRC)/common.h + +braces.o: general.h shell.h bashjmp.h sig.h variables.h quit.h config.h +braces.o: dispose_cmd.h make_cmd.h subst.h externs.h memalloc.h +braces.o: maxpath.h unwind_prot.h command.h stdc.h + +bracecomp.o: bracecomp.c +bracecomp.o: shell.h bashjmp.h sig.h command.h hashlib.h builtins.h general.h +bracecomp.o: quit.h alias.h config.h variables.h +bracecomp.o: dispose_cmd.h make_cmd.h subst.h externs.h stdc.h +bracecomp.o: $(RL_LIBSRC)/readline.h + +bashline.o: shell.h bashjmp.h sig.h command.h stdc.h hashlib.h builtins.h +bashline.o: general.h variables.h config.h memalloc.h quit.h alias.h +bashline.o: dispose_cmd.h make_cmd.h subst.h externs.h config.h bashline.h +bashline.o: $(GLOB_LIBSRC)/glob.h pathexp.h execute_cmd.h + +bashhist.o: config.h bashansi.h posixstat.h filecntl.h parser.h +bashhist.o: shell.h bashjmp.h sig.h command.h stdc.h hashlib.h builtins.h +bashhist.o: general.h variables.h memalloc.h quit.h alias.h execute_cmd.h +bashhist.o: dispose_cmd.h make_cmd.h subst.h externs.h flags.h + +bashline.o: $(RL_LIBSRC)/chardefs.h $(RL_LIBSRC)/readline.h +bashline.o: $(RL_LIBSRC)/keymaps.h +y.tab.o: $(RL_LIBSRC)/keymaps.h $(RL_LIBSRC)/chardefs.h +y.tab.o: $(RL_LIBSRC)/readline.h + +subst.o: $(HIST_LIBSRC)/history.h +bashline.o: $(HIST_LIBSRC)/history.h +bashhist.o: $(HIST_LIBSRC)/history.h +y.tab.o: $(HIST_LIBSRC)/history.h + +subst.o: $(GLOB_LIBSRC)/fnmatch.h +execute_cmd.o: $(GLOB_LIBSRC)/fnmatch.h +bashhist.o: $(GLOB_LIBSRC)/fnmatch.h + +execute_cmd.o: $(TILDE_LIBSRC)/tilde.h +general.o: $(TILDE_LIBSRC)/tilde.h +mailcheck.o: $(TILDE_LIBSRC)/tilde.h +shell.o: $(TILDE_LIBSRC)/tilde.h +subst.o: $(TILDE_LIBSRC)/tilde.h +variables.o: $(TILDE_LIBSRC)/tilde.h + +builtins/common.o: shell.h bashjmp.h sig.h command.h config.h memalloc.h +builtins/common.o: variables.h input.h $(DEFSRC)/hashcom.h siglist.h +builtins/common.o: quit.h unwind_prot.h maxpath.h jobs.h builtins.h +builtins/common.o: dispose_cmd.h make_cmd.h subst.h externs.h bashhist.h +builtins/common.o: execute_cmd.h stdc.h general.h error.h unwind_prot.h +builtins/alias.o: command.h config.h memalloc.h error.h general.h maxpath.h +builtins/alias.o: quit.h $(DEFSRC)/common.h +builtins/alias.o: shell.h bashjmp.h sig.h command.h stdc.h unwind_prot.h +builtins/alias.o: dispose_cmd.h make_cmd.h subst.h externs.h variables.h +builtins/bind.o: command.h config.h memalloc.h error.h general.h maxpath.h +builtins/bind.o: dispose_cmd.h make_cmd.h subst.h externs.h stdc.h +builtins/bind.o: shell.h bashjmp.h sig.h unwind_prot.h variables.h quit.h +builtins/bind.o: $(DEFSRC)/bashgetopt.h +builtins/break.o: command.h config.h memalloc.h error.h general.h maxpath.h +builtins/break.o: shell.h bashjmp.h sig.h unwind_prot.h variables.h quit.h +builtins/break.o: dispose_cmd.h make_cmd.h subst.h externs.h stdc.h +builtins/builtin.o: command.h config.h memalloc.h error.h general.h maxpath.h +builtins/builtin.o: quit.h $(DEFSRC)/common.h +builtins/builtin.o: shell.h bashjmp.h sig.h unwind_prot.h variables.h +builtins/builtin.o: dispose_cmd.h make_cmd.h subst.h externs.h stdc.h +builtins/cd.o: command.h config.h memalloc.h error.h general.h maxpath.h +builtins/cd.o: shell.h bashjmp.h sig.h unwind_prot.h variables.h +builtins/cd.o: dispose_cmd.h make_cmd.h subst.h externs.h stdc.h +builtins/cd.o: $(DEFSRC)/common.h quit.h +builtins/command.o: command.h config.h memalloc.h error.h general.h maxpath.h +builtins/command.o: quit.h $(DEFSRC)/bashgetopt.h +builtins/command.o: shell.h bashjmp.h sig.h unwind_prot.h variables.h +builtins/command.o: dispose_cmd.h make_cmd.h subst.h externs.h stdc.h +builtins/declare.o: command.h config.h memalloc.h error.h general.h maxpath.h +builtins/declare.o: shell.h bashjmp.h sig.h unwind_prot.h variables.h quit.h +builtins/declare.o: dispose_cmd.h make_cmd.h subst.h externs.h stdc.h +builtins/echo.o: command.h config.h memalloc.h error.h general.h maxpath.h +builtins/echo.o: shell.h bashjmp.h sig.h unwind_prot.h variables.h quit.h +builtins/echo.o: dispose_cmd.h make_cmd.h subst.h externs.h stdc.h +builtins/enable.o: command.h config.h memalloc.h error.h general.h maxpath.h +builtins/enable.o: shell.h bashjmp.h sig.h unwind_prot.h variables.h quit.h +builtins/enable.o: dispose_cmd.h make_cmd.h subst.h externs.h stdc.h +builtins/eval.o: command.h config.h memalloc.h error.h general.h maxpath.h +builtins/eval.o: shell.h bashjmp.h sig.h unwind_prot.h variables.h quit.h +builtins/eval.o: dispose_cmd.h make_cmd.h subst.h externs.h stdc.h +builtins/exec.o: command.h config.h memalloc.h error.h general.h maxpath.h +builtins/exec.o: shell.h bashjmp.h sig.h unwind_prot.h variables.h +builtins/exec.o: dispose_cmd.h make_cmd.h subst.h externs.h execute_cmd.h +builtins/exec.o: flags.h quit.h $(DEFSRC)/common.h stdc.h +builtins/exit.o: command.h config.h memalloc.h error.h general.h maxpath.h +builtins/exit.o: shell.h bashjmp.h sig.h unwind_prot.h variables.h quit.h +builtins/exit.o: dispose_cmd.h make_cmd.h subst.h externs.h stdc.h +builtins/fc.o: builtins.h command.h stdc.h +builtins/fc.o: command.h config.h memalloc.h error.h general.h maxpath.h +builtins/fc.o: flags.h unwind_prot.h variables.h shell.h bashjmp.h sig.h +builtins/fc.o: dispose_cmd.h make_cmd.h subst.h externs.h stdc.h quit.h +builtins/fc.o: $(DEFSRC)/bashgetopt.h bashhist.h +builtins/fg_bg.o: command.h config.h memalloc.h error.h general.h maxpath.h +builtins/fg_bg.o: shell.h bashjmp.h sig.h unwind_prot.h variables.h quit.h +builtins/fg_bg.o: dispose_cmd.h make_cmd.h subst.h externs.h stdc.h +builtins/getopts.o: command.h config.h memalloc.h error.h general.h maxpath.h +builtins/getopts.o: shell.h bashjmp.h sig.h unwind_prot.h variables.h quit.h +builtins/getopts.o: dispose_cmd.h make_cmd.h subst.h externs.h stdc.h +builtins/hash.o: builtins.h command.h execute_cmd.h stdc.h $(DEFSRC)/common.h +builtins/hash.o: command.h config.h memalloc.h error.h general.h maxpath.h +builtins/hash.o: shell.h bashjmp.h sig.h unwind_prot.h variables.h quit.h +builtins/help.o: command.h config.h memalloc.h error.h general.h maxpath.h +builtins/help.o: dispose_cmd.h make_cmd.h subst.h externs.h stdc.h +builtins/help.o: shell.h bashjmp.h sig.h unwind_prot.h variables.h quit.h +builtins/help.o: $(GLOB_LIBSRC)/glob.h +builtins/history.o: command.h config.h memalloc.h error.h general.h maxpath.h +builtins/history.o: quit.h dispose_cmd.h make_cmd.h subst.h externs.h stdc.h +builtins/history.o: filecntl.h shell.h bashjmp.h sig.h unwind_prot.h +builtins/history.o: bashhist.h variables.h +builtins/inlib.o: command.h config.h memalloc.h error.h general.h maxpath.h +builtins/inlib.o: shell.h bashjmp.h sig.h unwind_prot.h variables.h quit.h +builtins/inlib.o: dispose_cmd.h make_cmd.h subst.h externs.h stdc.h +builtins/jobs.o: command.h config.h memalloc.h error.h general.h maxpath.h +builtins/jobs.o: quit.h $(DEFSRC)/bashgetopt.h +builtins/jobs.o: shell.h bashjmp.h sig.h unwind_prot.h variables.h +builtins/jobs.o: dispose_cmd.h make_cmd.h subst.h externs.h stdc.h +builtins/kill.o: command.h config.h memalloc.h error.h general.h maxpath.h +builtins/kill.o: quit.h dispose_cmd.h make_cmd.h subst.h externs.h stdc.h +builtins/kill.o: shell.h bashjmp.h sig.h trap.h unwind_prot.h variables.h +builtins/let.o: command.h config.h memalloc.h error.h general.h maxpath.h +builtins/let.o: quit.h dispose_cmd.h make_cmd.h subst.h externs.h stdc.h +builtins/let.o: shell.h bashjmp.h sig.h unwind_prot.h variables.h +builtins/pushd.o: command.h config.h memalloc.h error.h general.h maxpath.h +builtins/pushd.o: quit.h dispose_cmd.h make_cmd.h subst.h externs.h stdc.h +builtins/pushd.o: shell.h bashjmp.h sig.h unwind_prot.h variables.h +builtins/pushd.o: $(DEFSRC)/common.h +builtins/read.o: command.h config.h memalloc.h error.h general.h maxpath.h +builtins/read.o: quit.h dispose_cmd.h make_cmd.h subst.h externs.h stdc.h +builtins/read.o: shell.h bashjmp.h sig.h unwind_prot.h variables.h +builtins/return.o: command.h config.h memalloc.h error.h general.h maxpath.h +builtins/return.o: quit.h dispose_cmd.h make_cmd.h subst.h externs.h stdc.h +builtins/return.o: shell.h bashjmp.h sig.h unwind_prot.h variables.h +builtins/set.o: command.h config.h memalloc.h error.h general.h maxpath.h +builtins/set.o: quit.h dispose_cmd.h make_cmd.h subst.h externs.h stdc.h +builtins/set.o: shell.h bashjmp.h sig.h unwind_prot.h variables.h flags.h +builtins/setattr.o: command.h config.h memalloc.h error.h general.h maxpath.h +builtins/setattr.o: quit.h $(DEFSRC)/common.h $(DEFSRC)/bashgetopt.h +builtins/setattr.o: shell.h bashjmp.h sig.h unwind_prot.h variables.h +builtins/setattr.o: dispose_cmd.h make_cmd.h subst.h externs.h stdc.h +builtins/shift.o: command.h config.h memalloc.h error.h general.h maxpath.h +builtins/shift.o: quit.h dispose_cmd.h make_cmd.h subst.h externs.h stdc.h +builtins/shift.o: shell.h bashjmp.h sig.h unwind_prot.h variables.h +builtins/shift.o: dispose_cmd.h make_cmd.h subst.h externs.h stdc.h +builtins/source.o: command.h config.h memalloc.h error.h general.h maxpath.h +builtins/source.o: quit.h dispose_cmd.h make_cmd.h subst.h externs.h stdc.h +builtins/source.o: shell.h bashjmp.h sig.h unwind_prot.h variables.h +builtins/suspend.o: command.h config.h memalloc.h error.h general.h maxpath.h +builtins/suspend.o: quit.h dispose_cmd.h make_cmd.h subst.h externs.h stdc.h +builtins/suspend.o: shell.h bashjmp.h sig.h unwind_prot.h variables.h +builtins/test.o: command.h config.h memalloc.h error.h general.h maxpath.h +builtins/test.o: quit.h dispose_cmd.h make_cmd.h subst.h externs.h stdc.h +builtins/test.o: shell.h bashjmp.h sig.h unwind_prot.h variables.h +builtins/times.o: command.h config.h memalloc.h error.h general.h maxpath.h +builtins/times.o: quit.h dispose_cmd.h make_cmd.h subst.h externs.h stdc.h +builtins/times.o: shell.h bashjmp.h sig.h unwind_prot.h variables.h +builtins/trap.o: command.h config.h memalloc.h error.h general.h maxpath.h +builtins/trap.o: quit.h $(DEFSRC)/common.h +builtins/trap.o: shell.h bashjmp.h sig.h unwind_prot.h variables.h +builtins/trap.o: dispose_cmd.h make_cmd.h subst.h externs.h stdc.h +builtins/type.o: command.h config.h memalloc.h error.h general.h maxpath.h +builtins/type.o: quit.h $(DEFSRC)/common.h execute_cmd.h +builtins/type.o: shell.h bashjmp.h sig.h unwind_prot.h variables.h +builtins/type.o: dispose_cmd.h make_cmd.h subst.h externs.h stdc.h +builtins/ulimit.o: command.h config.h memalloc.h error.h general.h maxpath.h +builtins/ulimit.o: quit.h dispose_cmd.h make_cmd.h subst.h externs.h stdc.h +builtins/ulimit.o: shell.h bashjmp.h sig.h unwind_prot.h variables.h +builtins/umask.o: command.h config.h memalloc.h error.h general.h maxpath.h +builtins/umask.o: quit.h dispose_cmd.h make_cmd.h subst.h externs.h stdc.h +builtins/umask.o: shell.h bashjmp.h sig.h unwind_prot.h variables.h +builtins/wait.o: command.h config.h memalloc.h error.h general.h maxpath.h +builtins/wait.o: quit.h dispose_cmd.h make_cmd.h subst.h externs.h stdc.h +builtins/wait.o: shell.h bashjmp.h sig.h unwind_prot.h variables.h +builtins/shopt.o: command.h config.h memalloc.h error.h general.h +builtins/shopt.o: quit.h dispose_cmd.h make_cmd.h subst.h externs.h +builtins/shopt.o: shell.h bashjmp.h unwind_prot.h variables.h maxpath.h +builtins/shopt.o: $(DEFSRC)/common.h $(DEFSRC)/bashgetopt.h + +builtins/bashgetopt.o: bashansi.h ansi_stdlib.h +builtins/mkbuiltins.o: bashansi.h ansi_stdlib.h +builtins/fc.o: bashansi.h ansi_stdlib.h + +builtins/bind.o: $(RL_LIBSRC)/chardefs.h $(RL_LIBSRC)/readline.h +builtins/bind.o: $(RL_LIBSRC)/keymaps.h + +builtins/bind.o: $(HIST_LIBSRC)/history.h +builtins/fc.o: $(HIST_LIBSRC)/history.h +builtins/history.o: $(HIST_LIBSRC)/history.h + +builtins/common.o: $(TILDE_LIBSRC)/tilde.h +builtins/cd.o: $(TILDE_LIBSRC)/tilde.h + +builtins/alias.o: $(DEFSRC)/alias.def +builtins/bind.o: $(DEFSRC)/bind.def +builtins/break.o: $(DEFSRC)/break.def +builtins/builtin.o: $(DEFSRC)/builtin.def +builtins/cd.o: $(DEFSRC)/cd.def +builtins/colon.o: $(DEFSRC)/colon.def +builtins/command.o: $(DEFSRC)/command.def +builtins/declare.o: $(DEFSRC)/declare.def +builtins/echo.o: $(DEFSRC)/echo.def +builtins/enable.o: $(DEFSRC)/enable.def +builtins/eval.o: $(DEFSRC)/eval.def +builtins/exec.o: $(DEFSRC)/exec.def +builtins/exit.o: $(DEFSRC)/exit.def +builtins/fc.o: $(DEFSRC)/fc.def +builtins/fg_bg.o: $(DEFSRC)/fg_bg.def +builtins/getopts.o: $(DEFSRC)/getopts.def +builtins/hash.o: $(DEFSRC)/hash.def +builtins/help.o: $(DEFSRC)/help.def +builtins/history.o: $(DEFSRC)/history.def +builtins/inlib.o: $(DEFSRC)/inlib.def +builtins/jobs.o: $(DEFSRC)/jobs.def +builtins/kill.o: $(DEFSRC)/kill.def +builtins/let.o: $(DEFSRC)/let.def +builtins/pushd.o: $(DEFSRC)/pushd.def +builtins/read.o: $(DEFSRC)/read.def +builtins/reserved.o: $(DEFSRC)/reserved.def +builtins/return.o: $(DEFSRC)/return.def +builtins/set.o: $(DEFSRC)/set.def +builtins/setattr.o: $(DEFSRC)/setattr.def +builtins/shift.o: $(DEFSRC)/shift.def +builtins/shopt.o: $(DEFSRC)/shopt.def +builtins/source.o: $(DEFSRC)/source.def +builtins/suspend.o: $(DEFSRC)/suspend.def +builtins/test.o: $(DEFSRC)/test.def +builtins/times.o: $(DEFSRC)/times.def +builtins/trap.o: $(DEFSRC)/trap.def +builtins/type.o: $(DEFSRC)/type.def +builtins/ulimit.o: $(DEFSRC)/ulimit.def +builtins/umask.o: $(DEFSRC)/umask.def +builtins/wait.o: $(DEFSRC)/wait.def diff --git a/NEWS b/NEWS index 783d193..82e1bcc 100644 --- a/NEWS +++ b/NEWS @@ -1,10 +1,280 @@ -This file documents the bugs fixed between this release, bash-1.14.7, -and the last public bash release, 1.14.6. +This is a terse description of the new features added to bash-2.0 since +the release of bash-1.14.7. As always, the manual page (doc/bash.1) is +the place to look for complete descriptions. -1. Bugs fixed in Bash +1. New Features in Bash -a. A memory leak that caused long-running scripts to eventually consume - all available memory was fixed. +a. There is a new invocation option, -D, that dumps translatable strings + in a script. -b. A sign-extension bug that caused a security hole for non-interactive - shells was fixed. +b. The `long' invocation options must now be prefixed with `--'. + +c. New long invocation options: --dump-strings, --help, --verbose + +d. The `nolineediting' invocation option was renamed to `noediting'. + +e. The `nobraceexpansion' and `quiet' long invocation options were removed. + +f. The `--help' and `--version' long options now work as the GNU coding + standards specify. + +g. If invoked as `sh', bash now enters posix mode after reading the + startup files, and reads and executes commands from the file named + by $ENV if interactive (as POSIX.2 specifies). A login shell invoked + as `sh' reads $ENV after /etc/profile and ~/.profile. + +h. There is a new reserved word, `time', for timing pipelines, builtin + commands, and shell functions. It uses the value of the TIMEFORMAT + variable as a format string describing how to print the timing + statistics. + +i. The $'...' quoting syntax expands ANSI-C escapes in ... and leaves the + result single-quoted. + +j. The $"..." quoting syntax performs locale-specific translation of ... + and leaves the result double-quoted. + +k. LINENO now works correctly in functions. + +l. New variables: DIRSTACK, PIPESTATUS, BASH_VERSINFO, HOSTNAME, SHELLOPTS, + MACHTYPE. The first three are array variables. + +m. The BASH_VERSION and BASH_VERSINFO variables now include the shell's + `release status' (alpha[N], beta[N], release). + +n. Some variables have been removed: MAIL_WARNING, notify, history_control, + command_oriented_history, glob_dot_filenames, allow_null_glob_expansion, + nolinks, hostname_completion_file, noclobber, no_exit_on_failed_exec, and + cdable_vars. Most of them are now implemented with the new `shopt' + builtin; others were already implemented by `set'. + +o. Bash now uses some new variables: LC_ALL, LC_MESSAGES, LC_CTYPE, + LC_COLLATE, LANG, GLOBIGNORE, HISTIGNORE. + +p. The shell now supports integer-indexed arrays of unlimited length, + with a new compound assignment syntax and changes to the appropriate + builtin commands (declare/typeset, read, readonly, etc.). The array + index may be an arithmetic expression. + +q. ${!var}: indirect variable expansion, equivalent to eval \${$var}. + +r. ${paramter:offset[:length]}: variable substring extraction. + +s. ${parameter/pattern[/[/]string]}: variable pattern substitution. + +t. The $[...] arithmetic expansion syntax is no longer supported, in + favor of $((...)). + +u. Aliases can now be expanded in shell scripts with a shell option + (shopt expand_aliases). + +v. History and history expansion can now be used in scripts with + set -o history and set -H. + +w. All builtins now return an exit status of 2 for incorrect usage. + +x. Interactive shells resend SIGHUP to all running or stopped children + if (and only if) they exit due to a SIGHUP. + +y. New prompting expansions: \a, \e, \H, \T, \@, \v, \V. + +z. Variable expansion in prompt strings is now controllable via a shell + option (shopt promptvars). + +aa. Bash now defaults to using command-oriented history. + +bb. The history file ($HISTFILE) is now truncated to $HISTFILESIZE after + being written. + +cc. The POSIX.2 conditional arithmetic evaluation syntax (expr ? expr : expr) + has been implemented. + +dd. Each builtin now accepts `--' to signify the end of the options, except + as documented (echo, etc.). + +ee. All builtins use -p to display values in a re-readable format where + appropriate, except as documented (echo, type, etc.). + +ff. The `alias' builtin has a new -p option. + +gg. Changes to the `bind' builtin: + o has new options: -psPSVr. + o the `-d' option was renamed to `-p' + o the `-v' option now dumps variables; the old `-v' is now `-P' + +hh. The `bye' synonym for `exit' was removed. + +ii. The -L and -P options to `cd' and `pwd' have been documented. + +jj. The `cd' builtin now does spelling correction on the directory name + by default. This is settable with a shell option (shopt cdspell). + +kk. The `declare' builtin has new options: -a, -F, -p. + +ll. The `dirs' builtin has new options: -c, -p, -v. + +mm. The new `disown' builtin removes jobs from the shell's jobs table + or inhibits the resending of SIGHUP when the shell receives a + SIGHUP. + +nn. The `echo' builtin has a new escape character: \e. + +oo. The `enable' builtin can now load new builtins dynamically from shared + objects on systems with the dlopen/dlsym interface. There are a number + of examples in the examples/loadables directory. There are also + new options: -d, -f, -s, -p. + +pp. The `-all' option to `enable' was removed in favor of `-a'. + +qq. The `exec' builtin has new options: -l, -c, -a. + +rr. The `hash' builtin has a new option: -p. + +ss. The `history' builtin has new options: -c, -p, -s. + +tt. The `jobs' builtin has new options: -r, -s. + +uu. The `kill' builtin has new options: -n signum, -l signame. + +vv. The `pushd' and `popd' builtins have a new option: -n. + +ww. The `read' builtin has new options: -p prompt, -e, -a. + +xx. The `readonly' builtin has a new -a option, and the -n option was removed. + +yy. Changes to the `set' builtin: + o new options: -B, -o keyword, -o onecmd, -o history + o options removed: -l, -d, -o nohash + o options changed: +o, -h, -o hashall + o now displays variables in a format that can be re-read as input + +zz. The new `shopt' builtin controls shell optional behavior previously + done by setting and unsetting certain shell variables. + +aaa. The `test' builtin has new operators: -o option, s1 == s2, s1 < s2, + and s1 > s2, where s1 and s2 are strings. + +bbb. There is a new trap, DEBUG, executed after every simple command. + +ccc. The `trap' builtin has a new -p option. + +ddd. The `ulimit' builtin has a new -l option on 4.4BSD-based systems. + +eee. The PS1, PS2, PATH, and IFS variables may now be unset. + +fff. The restricted shell mode has been expanded and is now documented. + +ggg. Security improvements: + o functions are not imported from the environment if running setuid + or with -p + o no startup files are sourced if running setuid or with -p + +hhh. The documentation has been overhauled: the texinfo manual was + expanded, and HTML versions of the man page and texinfo manual + are included. + +iii. Changes to Posix mode: + o Command lookup now finds special builtins before shell functions. + o Failure of a special builtin causes a non-interactive shell to + exit. Failures are defined in the POSIX.2 specification. + o If the `cd' builtin finds a directory to change to using $CDPATH, + the value assigned to PWD when `cd' completes does not contain + any symbolic links. + o A non-interactive shell exits if a variable assignment error + occurs when no command name follows the assignment statements. + o A non-interactive shell exits if the interation variable in a + `for' statement or the selection variable in a `select' statement + is read-only or another variable assignment error occurs. + o The `<>' redirection operator now opens a file for both stdin and + stdout by default, not just when in posix mode. + o Assignment statements preceding special builtins now persist in + the shell's environment when the builtin completes. + + Posix mode is now completely POSIX.2-compliant (modulo bugs). When + invoked as sh, bash should be completely POSIX.2-compliant. + +jjj. The default value of PS1 is now "\s-\v\$ ". + +kkk. The ksh-like ((...)) arithmetic command syntax has been implemented. + This is exactly equivalent to `let "..."'. + +lll. Integer constants have been extended to base 64. + +mmm. The `ulimit' builtin now sets both hard and soft limits and reports the + soft limit by default. + +2. New Features in Readline + +a. New variables: enable-keypad, input-meta (new name for meta-flag), + mark-directories, visible-stats (now documented), disable-completion, + comment-begin. + +b. New bindable commands: kill-region, copy-region-as-kill, + copy-backward-word, copy-forward-word, set-mark, exchange-point-and-mark, + character-search, character-search-backward, insert-comment, + glob-expand-word, glob-list-expansions, dump-variables, dump-macros. + +c. New emacs keybindings: delete-horizontal-space (M-\), + insert-completions (M-*), possible-completions (M-=). + +d. The history-search-backward and history-search-forward commands were + modified to be the same as previous-line and next-line if point is at + the start of the line. + +e. More file types are available for the visible-stats mode. + +3. Changes of interest in the Bash implementation + +a. There is a new autoconf-based configuration mechanism. + +b. More things have been moved from Posix mode to standard shell behavior. + +c. The trace output (set -x) now inserts quotes where necessary so it can + be reused as input. + +d. There is a compile-time option for a system-wide interactive shell + startup file (disabled by default). + +e. The YACC grammar is smaller and tighter, and all 66 shift-reduce + conflicts are gone. Several parsing bugs have been fixed. + +f. Builtin option parsing has been regularized (using internal_getopt()), + with the exception of `echo', `type', and `set'. + +g. Builtins now return standard usage messages constructed from the + `short doc' used by the help builtin. + +h. Completion now quotes using backslashes by default, but honors + user-supplied quotes. + +i. The GNU libc malloc is available as a configure-time option. + +j. There are more internationalization features; bash uses gettext if + it is available. The $"..." translation syntax uses the current + locale and gettext. + +k. There is better reporting of job termination when the shell is not + interactive. + +l. The shell is somewhat more efficient: it uses a little less memory and + makes fewer system calls. + +4. Changes of interest in the Readline implementation + +a. There is now support for readline `callback' functions. + +b. There is now support for user-supplied input, redisplay, and terminal + preparation functions. + +c. Most of the shell-specific code in readline has been generalized or + removed. + +d. Most of the annoying redisplay bugs have been fixed, notably the problems + with incremental search and excessive redrawing when special characters + appear in the prompt string. + +e. There are new library functions and variables available to application + writers, most having to do with completion and quoting. + +f. The NEWLINE character (^J) is now treated as a search terminator by the + incremental search functions. diff --git a/NOTES b/NOTES new file mode 100644 index 0000000..0594d22 --- /dev/null +++ b/NOTES @@ -0,0 +1,42 @@ +Platform-Specific Configuration Notes +===================================== + +1. configure --without-gnu-malloc on: + + alpha running OSF/1 + alpha running Linux + + next running NeXT/OS + + all machines running SunOS YP code: SunOS4, SunOS5, HP/UX + + linux (optional) + + QNX 4.2 + other OSF/1 machines (KSR/1, HP, IBM AIX/ESA) + AIX + sparc SVR4, SVR4.2 (ICL reference port) + DG/UX + Cray + + NetBSD/sparc (malloc needs 8-byte alignment; GNU malloc has 4-byte) + + BSD/OS 2.1 if you want to use loadable builtins + + If you are using GNU libc, especially on a linux system + +(Configuring --without-gnu-malloc will still result in lib/malloc/libmalloc.a +being built and linked against, but there is only a stub file in the archive.) + +2. configure using shlicc on BSD/OS 2.1 to use loadable builtins + +3. Bash cannot be built in a directory separate from the source directory + using configure --srcdir=... unless the version of `make' you're using + does $VPATH handling right. The SunOS make, for one, does not seem to + do it right. The script support/mkclone can be used to create a + `build tree' using symlinks to get around this. + +4. I've had reports that username completion does not work on IRIX 5.3 + when linking with -lnsl. This is only a problem when you're running + NIS. Editing the Makefile after configure runs and removing the + `-lnsl' from the assignment to `LIBS' fixes the problem. diff --git a/README b/README index 6638c6e..89afad4 100644 --- a/README +++ b/README @@ -1,48 +1,77 @@ -This README file is in -*- text -*- mode, because Emacs likes it that way. +Introduction +============ -This is GNU Bash, version 1.14. Bash is the GNU Project's Bourne -Again SHell, an interactive shell with Bourne shell syntax (/bin/sh); +This is GNU Bash, version 2.0. Bash is the GNU Project's Bourne +Again SHell, a complete implementation of the POSIX.2 shell spec, but also with interactive command line editing, job control on -architectures that support it, Csh-like history features and brace -expansion, and a slew of other stuff. For more information on the -features of Bash that are new to this type of shell, see the file -`documentation/features.texi'. There is also a DVI file there, as -well as a large man page. +architectures that support it, csh-like features such as history +substitution and brace expansion, and a slew of other features. +For more information on the features of Bash that are new to this +type of shell, see the file `doc/features.texi'. There is also a +large man page. The manual page is the definitive description of +the shell's features. -To compile it, try typing `make'. Bash auto-configures the build -process, so no intervention should be necessary. If you want to -use gcc, type `make CC=gcc CPPNAME='$(CC) -E''. +See the file CWRU/POSIX.NOTES for a discussion of how Bash differs +from the POSIX.2 spec and a description of the Bash `posix mode'. -You may want to read the file INSTALL in this directory for more -information if the make fails. +There are some user-visible incompatibilities between this version +of Bash and the previous version, bash-1.14. For details, see the +file COMPAT. + +Bash is free software, distributed under the terms of the GNU Public +License, version 2. For more information, see the file COPYING. + +To compile Bash, try typing `./configure', then `make'. Bash +auto-configures the build process, so no further intervention +should be necessary. Bash builds with `gcc' by default if it is +available. If you want to use `cc' instead, type + + CC=cc ./configure + +if you are using a Bourne-style shell. If you are not, the following +may work: + + env CC=cc ./configure + +Read the file INSTALL in this directory for more information about how +to customize and control the build process. The file NOTES contains +platform-specific installation and configuration information. If you are a csh user and wish to convert your csh aliases to Bash -aliases, you may wish to use the script in examples/alias-conv.sh +aliases, you may wish to use the script `examples/misc/alias-conv.sh' as a starting point. -Bug reports for 1.14 should be sent to: +Reporting Bugs +============== + +Bug reports for 2.0 should be sent to: bug-bash@prep.ai.mit.edu using the `bashbug' program that is built and installed at the same time as bash. -The discussion list "bug-bash@prep.ai.mit.edu" often contains information -about new ports of Bash, or discussions of new features or behavior -changes that people would like. This mailing list is also available -as a usenet newsgroup: gnu.bash.bug. +The discussion list `bug-bash@prep.ai.mit.edu' often contains +information about new ports of Bash, or discussions of new +features or behavior changes that people would like. This +mailing list is also available as a usenet newsgroup: +gnu.bash.bug. -When you send a bug report to bash-maintainers@prep.ai.mit.edu, please -include: +When you send a bug report to bug-bash@prep.ai.mit.edu, please include: * the version number of Bash * the machine and OS that it is running on (see .machine or .made) + * a list of the compilation flags or the contents of `config.h', if + appropriate * a description of the bug * a recipe for recreating the bug reliably * a fix for the bug if you have one! The `bashbug' program includes much of this automatically. +If you would like to contact the Bash maintainers directly, send mail to +bash-maintainers@prep.ai.mit.edu. + While the Bash maintainers do not promise to fix all bugs, we would like this shell to be the best that we can make it. diff --git a/RELEASE b/RELEASE deleted file mode 100644 index 6a5167e..0000000 --- a/RELEASE +++ /dev/null @@ -1,269 +0,0 @@ -This file details the changes between the previous release of bash (1.13.5) -and this release (1.14.0). - -1. New Features in Bash - -a. The source has been reorganized: nearly all extern function - declarations have been moved to header files, function prototypes - have been added to most header files, function declarations have - been moved to file scope, dead code has been removed, the - bash history code has been isolated in bashhist.[ch], and several - new header files have been created - -b. `set -o posix' puts bash into Posix.2 mode - -c. If $POSIX_PEDANTIC exists in the initial environment or is assigned - a value, bash enters Posix.2 mode - -d. Bash sets $OSTYPE to a string describing the UNIX version - -e. The features.info file was completely rewritten and now reflects - the current state of things - -f. A manual page for readline is in documentation/readline.{3,ps} - -g. The test builtin emulates /dev/fd/x for systems without /dev/fd - -h. `dirs' has -n and +n options to access members of the directory stack - -i. Prompt string expansion handles invisible characters in the prompt; - \[ and \] are used (and required) to start and end sequences of - invisible chars - -j. NO_PROMPT_VARS has been removed - -k. New machine descriptions have been added: IBM AIX/ESA, NEC EWS, NetBSD, - FreeBSD, QNX 4.2, concurrent, MIPS SVR4.2, Lynx 2.1 - -l. RESTRICTED_SHELL is no longer defined by default in config.h - -m. The version string in $BASH_VERSION has changed to dist.patch(build) - -n. $history_control has been renamed to $HISTCONTROL and now takes the - value `ignoreboth' ($history_control is still accepted for backwards - compatibility) - -o. There is a new program `bashbug' for reporting bugs. Eventually I will - probably switch to gnats. - -p. auto_resume can take the values `exact' and `substring' - -q. `set -P' (`set -o physical') enables the same physical view of the - file system that `nolinks' enables (`nolinks' will remain for one - more release) - -r. There is a `mkmachtype' program to generate a GNU-style machine type - string (e.g., `sparc-sun-sunos4.1.2') suitable for assigning to - $MACHTYPE - -s. The variable $HISTCMD returns the current history number - -t. Variables in directory names are now expanded while doing completion - -u. The test suite has been expanded and is runnable as a regression test - with `make tests' - -v. `bye' is no longer a builtin synonym for `exit' - -w. The ksh `select' control construct has been implemented - -x. The `ignoreeof' attribute can be inherited if $IGNOREEOF is exported - -y. The `USG-style' echo is now a configuration option. Define - DEFAULT_ECHO_TO_USG for default \-interpretation without the -e flag - -z. There is a copy of an article I wrote about bash for the Linux - Journal in documentation/article.{ms,ps} - -aa. The `pwd' builtin now obeys the setting of `set -o physical' (`nolinks') - -bb. Process substitution is no longer performed when the shell is in - `posix mode' - -cc. Users may change the debugging and optimization flags to cc by specifying - CFLAGS to make - -2. New Features in Readline - -a. Readline now understands sequences of invisible characters in the prompt - string, as long as they are escaped (e.g., by the bash \[ and \] escapes) - -b. A `set keymap' variable assignment - -c. A `bell-style' variable that can be set to `visible', `audio', or `none' - -d. A `show-all-if-ambiguous' variable, which causes non-unique completion - to immediately list the possible completions - -e. An `output-meta' variable to make readline directly output chars - with the eighth bit set - -f. New bindable readline commands: kill-whole-line, tilde-expand, - vi-redo, vi-tilde-expand, emacs-editing-mode, - non-incremental-forward-search-history-again, - non-incremental-reverse-search-history-again - -g. New history-search-forward and history-search-backward to search for - the characters between the start of the current line and point - -h. Readline takes the name of the startup file from the INPUTRC variable - before defaulting to ~/.inputrc - -i. isearch no longer finds identical lines multiple times in succession - -j. M-C-H bound to backward-kill-word in emacs mode - -k. M-~ bound to tilde-expand in emacs mode - -l. History expansion is now fully csh-compatible: missing modifiers and - substitutions have been added, and bugs fixed - -m. When asking whether or not to display the possible completions, readline - now accepts space as equivalent to `y' and rubout for `n' - -n. Readline now attempts to find and bind the arrow keys into the vi mode - movement keymap - -3. Bugs fixed in Bash - -a. Portability fixes: `index' and `rindex' are gone completely, many - OS-specific defines have been replaced with feature-test macros, - the use of alloca has been reduced, and other platform-specific fixes - (e.g. cray) have been made - -b. The man page has been fixed up and brought up to date - -c. Speed improvements: here documents, variable expansion, history - expansion, command substitution - -d. If history is stifled, the history list replaces the history file at - exit - -e. Asynchronous jobs re-run with fc -s now print the job number - -f. Output redirections do not perform filename expansion in Posix.2 mode - when the shell is not interactive - -g. operate_and_get_next now works on the most recent line even if the - history is unstifled - -h. $PROMPT_COMMAND execution no longer causes recursive invocations - of yyparse() - -i. An error message is printed if job control initialization fails - -j. A command found in $PATH from the temporary environment is not hashed - -k. Errors display the name of the script if the shell is not interactive - -l. Fixed expression evaluation so blank expressions return 0 - -m. Fixed a bug that caused SIGINT and SIGQUIT not to be ignored in some - asynchronous children - -n. Pipes used for /dev/fd process substitution are now closed on errors - -o. Fixed /dev/null redirection so that ( list ) subshells inherit the - `stdin-has-been-redirected' flag as in sh - -p. Process substitution now works only when unquoted - -q. Fixed a bug where the async flag was added inappropriately in a command - like `a;b;c;d &' - -r. Fixed off-by-one bug which caused negative history offsets in `fc' to - be wrong - -s. Shell now remembers mail dates at startup on all systems - -t. Posix systems without job control no longer create so many zombies - -u. $ENV is now sourced by shells forked to execute scripts without a - leading `#!' line - -v. Non-root users can now use the `unlimited' argument to ulimit and have - the resource value set to the hard limit - -w. Made bash more sh-compatible by assigning the first argument after - `-c command' to $0 - -x. Fixed mail checking bug to note that *new* mail has arrived - -y. Fixed off-by-one error in mailcheck.c:free_mail_files() - -z. Fixed a bug where command strings passed to `bash -c' would be truncated - after executing the first disk command in the string - -aa. Fixed a bug which caused redirections passed to executable commands with - input or output pipes to be closed before the command was executed - -bb. Fixed a bug which caused bash to search for files supplied on the command - line in the $PATH if the initial open failed, even if the names contained - a slash - -cc. The initial argument parsing was fixed up so that other options can - be supplied with -c (that is, `sh -ec command' now works as make - intends), and so `bash -o' lists all the shell options at startup. - -dd. Error messages are consistently prefixed with the name of the shell - or shell script when non-interactive. - -ee. Fixed up a problem with the `read' builtin that occurred when more - variables than arguments were supplied. - -ff. Unset the variables passed to `read' as arguments when EOF is - read from stdin (sh, Posix.2 compatibility). - -gg. Fixes to the command printing code to make the output of `type' - available as legal shell input. - -ii. Fixes so that command completion is attempted after all of the shell - command separator characters. - -jj. Fixes to the shell completion code so that it handles quoted characters - and substrings better. - -kk. Bash no longer looks through $PATH for a shell script passed as an - argument if the name contains slashes. - -ll. Bash now checks that the `name' in a `name[=value]' argument to `declare' - (and thus `typeset', `export', and `readonly') is a legal shell variable - name. - -4. Bugs fixed in Readline - -a. The ^W and ^U bindings in non-incremental search mode have been changed - to be closer to what Posix specifies - -b. Tries to initialize the keypad to enable the arrow keys - -c. Multiple words are now killed and yanked in the right order - -d. rl_read_init_file now reads filenames in a more regular order: the last - one read, $INPUTRC, then ~/.inputrc - -e. yank_nth_arg inserts a space in the right place in vi mode - -f. Fixed a bug in the history library that tried to write to a file opened - O_RDONLY - -g. Binding of `0' in vi command mode is now right - -h. The VISIBLE_STATS completion listing code now follows symlinks - -i. Memory allocated with alloca() is no longer passed to other functions - -j. Error messages are now printed for unrecognized history modifiers - -k. Fixed a problem with history library and `!#'; now it is more csh-like. - -l. Fixed a csh incompatibility in the history library: now only an end of - line or `?' terminates a ?string history search string. - -m. Fixed a problem with readline completion that sometimes caused possible - matches to be listed one per line when `show-all-if-ambiguous' was set. - -n. Fixed a problem in the readline display code that caused divide-by-zero - errors. - -o. Fixed an off-by-one error in the kill ring reallocation code. diff --git a/aclocal.m4 b/aclocal.m4 new file mode 100644 index 0000000..8391f78 --- /dev/null +++ b/aclocal.m4 @@ -0,0 +1,993 @@ +dnl +dnl Bash specific tests +dnl +dnl Some derived from PDKSH 5.1.3 autoconf tests +dnl +dnl check whether cc can create executables +dnl +AC_DEFUN(BASH_CC_WORKS, +[AC_CACHE_CHECK(whether CC works at all, bash_cv_prog_cc_works, + [AC_TRY_RUN([main() { exit(0); }], + bash_cv_prog_cc_works=yes, bash_cv_prog_cc_works=no, + bash_cv_prog_cc_works=no) + ] +) +if test "$bash_cv_prog_cc_works" = "no"; then +AC_MSG_ERROR([Installation or configuration problem: C compiler cannot create executables]) +fi +]) + +dnl +dnl Check if dup2() does not clear the close on exec flag +dnl +AC_DEFUN(BASH_DUP2_CLOEXEC_CHECK, +[AC_MSG_CHECKING(if dup2 fails to clear the close-on-exec flag) +AC_CACHE_VAL(bash_cv_dup2_broken, +[AC_TRY_RUN([ +#include +#include +main() +{ + int fd1, fd2, fl; + fd1 = open("/dev/null", 2); + if (fcntl(fd1, 2, 1) < 0) + exit(1); + fd2 = dup2(fd1, 1); + if (fd2 < 0) + exit(2); + fl = fcntl(fd2, 1, 0); + /* fl will be 1 if dup2 did not reset the close-on-exec flag. */ + exit(fl != 1); +} +], bash_cv_dup2_broken=yes, bash_cv_dup2_broken=no, + AC_MSG_ERROR(cannot check dup2 if cross compiling)) +]) +AC_MSG_RESULT($bash_cv_dup2_broken) +if test $bash_cv_dup2_broken = yes; then +AC_DEFINE(DUP2_BROKEN) +fi +]) + +dnl Check type of signal routines (posix, 4.2bsd, 4.1bsd or v7) +AC_DEFUN(BASH_SIGNAL_CHECK, +[AC_REQUIRE([AC_TYPE_SIGNAL]) +AC_MSG_CHECKING(for type of signal functions) +AC_CACHE_VAL(bash_cv_signal_vintage, +[ + AC_TRY_LINK([#include ],[ + sigset_t ss; + struct sigaction sa; + sigemptyset(&ss); sigsuspend(&ss); + sigaction(SIGINT, &sa, (struct sigaction *) 0); + sigprocmask(SIG_BLOCK, &ss, (sigset_t *) 0); + ], bash_cv_signal_vintage=posix, + [ + AC_TRY_LINK([#include ], [ + int mask = sigmask(SIGINT); + sigsetmask(mask); sigblock(mask); sigpause(mask); + ], bash_cv_signal_vintage=4.2bsd, + [ + AC_TRY_LINK([ + #include + RETSIGTYPE foo() { }], [ + int mask = sigmask(SIGINT); + sigset(SIGINT, foo); sigrelse(SIGINT); + sighold(SIGINT); sigpause(SIGINT); + ], bash_cv_signal_vintage=svr3, bash_cv_signal_vintage=v7 + )] + )] +) +]) +AC_MSG_RESULT($bash_cv_signal_vintage) +if test "$bash_cv_signal_vintage" = posix; then +AC_DEFINE(HAVE_POSIX_SIGNALS) +elif test "$bash_cv_signal_vintage" = "4.2bsd"; then +AC_DEFINE(HAVE_BSD_SIGNALS) +elif test "$bash_cv_signal_vintage" = svr3; then +AC_DEFINE(HAVE_USG_SIGHOLD) +fi +]) + +dnl Check if the pgrp of setpgrp() can't be the pid of a zombie process. +AC_DEFUN(BASH_PGRP_SYNC, +[AC_REQUIRE([AC_FUNC_GETPGRP]) +AC_MSG_CHECKING(whether pgrps need synchronization) +AC_CACHE_VAL(bash_cv_pgrp_pipe, +[AC_TRY_RUN([ +#ifdef HAVE_UNISTD_H +# include +#endif +main() +{ +# ifdef GETPGRP_VOID +# define getpgID() getpgrp() +# else +# define getpgID() getpgrp(0) +# define setpgid(x,y) setpgrp(x,y) +# endif + int pid1, pid2, fds[2]; + int status; + char ok; + + switch (pid1 = fork()) { + case -1: + exit(1); + case 0: + setpgid(0, getpid()); + exit(0); + } + setpgid(pid1, pid1); + + sleep(2); /* let first child die */ + + if (pipe(fds) < 0) + exit(2); + + switch (pid2 = fork()) { + case -1: + exit(3); + case 0: + setpgid(0, pid1); + ok = getpgID() == pid1; + write(fds[1], &ok, 1); + exit(0); + } + setpgid(pid2, pid1); + + close(fds[1]); + if (read(fds[0], &ok, 1) != 1) + exit(4); + wait(&status); + wait(&status); + exit(ok ? 0 : 5); +} +], bash_cv_pgrp_pipe=no,bash_cv_pgrp_pipe=yes, + AC_MSG_ERROR(cannot check pgrp synchronization if cross compiling)) +]) +AC_MSG_RESULT($bash_cv_pgrp_pipe) +if test $bash_cv_pgrp_pipe = yes; then +AC_DEFINE(PGRP_PIPE) +fi +]) + +dnl +dnl check for typedef'd symbols in header files, but allow the caller to +dnl specify the include files to be checked in addition to the default +dnl +dnl BASH_CHECK_TYPE(TYPE, HEADERS, DEFAULT[, VALUE-IF-FOUND]) +AC_DEFUN(BASH_CHECK_TYPE, +[AC_REQUIRE([AC_HEADER_STDC])dnl +AC_MSG_CHECKING(for $1) +AC_CACHE_VAL(bash_cv_type_$1, +[AC_EGREP_CPP($1, [#include +#if STDC_HEADERS +#include +#endif +$2 +], bash_cv_type_$1=yes, bash_cv_type_$1=no)]) +AC_MSG_RESULT($bash_cv_type_$1) +ifelse($#, 4, [if test $bash_cv_type_$1 = yes; then + AC_DEFINE($4) + fi]) +if test $bash_cv_type_$1 = no; then + AC_DEFINE($1, $3) +fi +]) + +dnl +dnl Type of struct rlimit fields: some systems (OSF/1, NetBSD, RISC/os 5.0) +dnl have a rlim_t, others (4.4BSD based systems) use quad_t, others use +dnl long and still others use int (HP-UX 9.01, SunOS 4.1.3). To simplify +dnl matters, this just checks for rlim_t, quad_t, or long. +dnl +AC_DEFUN(BASH_RLIMIT_TYPE, +[AC_MSG_CHECKING(for size and type of struct rlimit fields) +AC_CACHE_VAL(bash_cv_type_rlimit, +[AC_TRY_COMPILE([#include ], +[rlim_t xxx;], bash_cv_type_rlimit=rlim_t,[ +AC_TRY_RUN([ +#include +#include +#include +main() +{ +#ifdef HAVE_QUAD_T + struct rlimit rl; + if (sizeof(rl.rlim_cur) == sizeof(quad_t)) + exit(0); +#endif + exit(1); +}], bash_cv_type_rlimit=quad_t, bash_cv_type_rlimit=long, + AC_MSG_ERROR(cannot check quad_t if cross compiling))]) +]) +AC_MSG_RESULT($bash_cv_type_rlimit) +if test $bash_cv_type_rlimit = quad_t; then +AC_DEFINE(RLIMTYPE, quad_t) +elif test $bash_cv_type_rlimit = rlim_t; then +AC_DEFINE(RLIMTYPE, rlim_t) +fi +]) + +dnl +dnl Check for sys_siglist[] or _sys_siglist[] +dnl +AC_DEFUN(BASH_UNDER_SYS_SIGLIST, +[AC_MSG_CHECKING([for _sys_siglist in system C library]) +AC_CACHE_VAL(bash_cv_under_sys_siglist, +[AC_TRY_RUN([ +#include +#include +#ifdef HAVE_UNISTD_H +#include +#endif +#ifndef _sys_siglist +extern char *_sys_siglist[]; +#endif +main() +{ +char *msg = _sys_siglist[2]; +exit(msg == 0); +}], +bash_cv_under_sys_siglist=yes, bash_cv_under_sys_siglist=no, +AC_MSG_ERROR(cannot check for _sys_siglist[] if cross compiling))])dnl +AC_MSG_RESULT($bash_cv_under_sys_siglist) +if test $bash_cv_under_sys_siglist = yes; then +AC_DEFINE(HAVE_UNDER_SYS_SIGLIST) +fi +]) + +AC_DEFUN(BASH_SYS_SIGLIST, +[AC_REQUIRE([AC_DECL_SYS_SIGLIST]) +AC_MSG_CHECKING([for sys_siglist in system C library]) +AC_CACHE_VAL(bash_cv_sys_siglist, +[AC_TRY_RUN([ +#include +#include +#ifdef HAVE_UNISTD_H +#include +#endif +#ifndef SYS_SIGLIST_DECLARED +extern char *sys_siglist[]; +#endif +main() +{ +char *msg = sys_siglist[2]; +exit(msg == 0); +}], +bash_cv_sys_siglist=yes, bash_cv_sys_siglist=no, +AC_MSG_ERROR(cannot check for sys_siglist if cross compiling))])dnl +AC_MSG_RESULT($bash_cv_sys_siglist) +if test $bash_cv_sys_siglist = yes; then +AC_DEFINE(HAVE_SYS_SIGLIST) +fi +]) + +dnl Check for sys_errlist[] and sys_nerr, check for declaration +AC_DEFUN(BASH_SYS_ERRLIST, +[AC_MSG_CHECKING([for sys_errlist and sys_nerr]) +AC_CACHE_VAL(bash_cv_sys_errlist, +[AC_TRY_LINK([#include ], +[extern char *sys_errlist[]; + extern int sys_nerr; + char *msg = sys_errlist[sys_nerr - 1];], + bash_cv_sys_errlist=yes, bash_cv_sys_errlist=no)])dnl +AC_MSG_RESULT($bash_cv_sys_errlist) +if test $bash_cv_sys_errlist = yes; then +AC_DEFINE(HAVE_SYS_ERRLIST) +fi +]) + +dnl Check to see if opendir will open non-directories (not a nice thing) +AC_DEFUN(BASH_FUNC_OPENDIR_CHECK, +[AC_REQUIRE([AC_HEADER_DIRENT])dnl +AC_MSG_CHECKING(if opendir() opens non-directories) +AC_CACHE_VAL(bash_cv_opendir_not_robust, +[AC_TRY_RUN([ +#include +#include +#include +#ifdef HAVE_UNISTD_H +# include +#endif /* HAVE_UNISTD_H */ +#if defined(HAVE_DIRENT_H) +# include +#else +# define dirent direct +# ifdef HAVE_SYS_NDIR_H +# include +# endif /* SYSNDIR */ +# ifdef HAVE_SYS_DIR_H +# include +# endif /* SYSDIR */ +# ifdef HAVE_NDIR_H +# include +# endif +#endif /* HAVE_DIRENT_H */ +main() +{ +DIR *dir; +int fd; +unlink("/tmp/not_a_directory"); +fd = open("/tmp/not_a_directory", O_WRONLY|O_CREAT, 0666); +write(fd, "\n", 1); +close(fd); +dir = opendir("/tmp/not_a_directory"); +unlink("/tmp/not_a_directory"); +exit (dir == 0); +}], bash_cv_opendir_not_robust=yes,bash_cv_opendir_not_robust=no, + AC_MSG_ERROR(cannot check opendir if cross compiling))]) +AC_MSG_RESULT($bash_cv_opendir_not_robust) +if test $bash_cv_opendir_not_robust = yes; then +AC_DEFINE(OPENDIR_NOT_ROBUST) +fi +]) + +dnl +AC_DEFUN(BASH_TYPE_SIGHANDLER, +[AC_MSG_CHECKING([whether signal handlers are of type void]) +AC_CACHE_VAL(bash_cv_void_sighandler, +[AC_TRY_COMPILE([#include +#include +#ifdef signal +#undef signal +#endif +#ifdef __cplusplus +extern "C" +#endif +void (*signal ()) ();], +[int i;], bash_cv_void_sighandler=yes, bash_cv_void_sighandler=no)])dnl +AC_MSG_RESULT($bash_cv_void_sighandler) +if test $bash_cv_void_sighandler = yes; then +AC_DEFINE(VOID_SIGHANDLER) +fi +]) + +AC_DEFUN(BASH_FUNC_STRSIGNAL, +[AC_MSG_CHECKING([for the existance of strsignal]) +AC_CACHE_VAL(bash_cv_have_strsignal, +[AC_TRY_LINK([#include +#include ], +[char *s = (char *)strsignal(2);], + bash_cv_have_strsignal=yes, bash_cv_have_strsignal=no)]) +AC_MSG_RESULT($bash_cv_have_strsignal) +if test $bash_cv_have_strsignal = yes; then +AC_DEFINE(HAVE_STRSIGNAL) +fi +]) + +AC_DEFUN(BASH_FUNC_LSTAT, +[dnl Cannot use AC_CHECK_FUNCS(lstat) because Linux defines lstat() as an +dnl inline function in . +AC_CACHE_CHECK([for lstat], bash_cv_func_lstat, +[AC_TRY_LINK([ +#include +#include +],[ lstat("",(struct stat *)0); ], +bash_cv_func_lstat=yes, bash_cv_func_lstat=no)]) +if test $bash_cv_func_lstat = yes; then + AC_DEFINE(HAVE_LSTAT) +fi +]) + +AC_DEFUN(BASH_STRUCT_TERMIOS_LDISC, +[AC_MSG_CHECKING([for a c_line member of struct termios]) +AC_CACHE_VAL(bash_cv_termios_ldisc, +[AC_TRY_COMPILE([#include +#include ],[struct termios t; int i; i = t.c_line;], + bash_cv_termios_ldisc=yes, bash_cv_termios_ldisc=no)])dnl +AC_MSG_RESULT($bash_cv_termios_ldisc) +if test $bash_cv_termios_ldisc = yes; then +AC_DEFINE(TERMIOS_LDISC) +fi +]) + +AC_DEFUN(BASH_STRUCT_TERMIO_LDISC, +[AC_MSG_CHECKING([for a c_line member of struct termio]) +AC_CACHE_VAL(bash_cv_termio_ldisc, +[AC_TRY_COMPILE([#include +#include ],[struct termio t; int i; i = t.c_line;], + bash_cv_termio_ldisc=yes, bash_cv_termio_ldisc=no)])dnl +AC_MSG_RESULT($bash_cv_termio_ldisc) +if test $bash_cv_termio_ldisc = yes; then +AC_DEFINE(TERMIO_LDISC) +fi +]) + +AC_DEFUN(BASH_FUNC_GETENV, +[AC_MSG_CHECKING(to see if getenv can be redefined) +AC_CACHE_VAL(bash_cv_getenv_redef, +[AC_TRY_RUN([ +#ifdef HAVE_UNISTD_H +# include +#endif +#ifndef __STDC__ +# ifndef const +# define const +# endif +#endif +char * +getenv (name) +#if defined (__linux__) || defined (__bsdi__) || defined (convex) + const char *name; +#else + char const *name; +#endif /* !__linux__ && !__bsdi__ && !convex */ +{ +return "42"; +} +main() +{ +char *s; +/* The next allows this program to run, but does not allow bash to link + when it redefines getenv. I'm not really interested in figuring out + why not. */ +#if defined (NeXT) +exit(1); +#endif +s = getenv("ABCDE"); +exit(s == 0); /* force optimizer to leave getenv in */ +} +], bash_cv_getenv_redef=yes, bash_cv_getenv_redef=no, +AC_MSG_ERROR(cannot check getenv redefinition if cross compiling))]) +AC_MSG_RESULT($bash_cv_getenv_redef) +if test $bash_cv_getenv_redef = yes; then +AC_DEFINE(CAN_REDEFINE_GETENV) +fi +]) + +AC_DEFUN(BASH_FUNC_PRINTF, +[AC_MSG_CHECKING(for declaration of printf in ) +AC_CACHE_VAL(bash_cv_printf_declared, +[AC_TRY_RUN([ +#include +#ifdef __STDC__ +typedef int (*_bashfunc)(const char *, ...); +#else +typedef int (*_bashfunc)(); +#endif +main() +{ +_bashfunc pf; +pf = printf; +exit(pf == 0); +} +],bash_cv_printf_declared=yes, bash_cv_printf_declared=no, +AC_MSG_ERROR(cannot check printf declaration if cross compiling))]) +AC_MSG_RESULT($bash_cv_printf_declared) +if test $bash_cv_printf_declared = yes; then +AC_DEFINE(PRINTF_DECLARED) +fi +]) + +AC_DEFUN(BASH_FUNC_ULIMIT_MAXFDS, +[AC_MSG_CHECKING(whether ulimit can substitute for getdtablesize) +AC_CACHE_VAL(bash_cv_ulimit_maxfds, +[AC_TRY_RUN([ +main() +{ +long maxfds = ulimit(4, 0L); +exit (maxfds == -1L); +} +],bash_cv_ulimit_maxfds=yes, bash_cv_ulimit_maxfds=no, +AC_MSG_ERROR(cannot check ulimit if cross compiling))]) +AC_MSG_RESULT($bash_cv_ulimit_maxfds) +if test $bash_cv_ulimit_maxfds = yes; then +AC_DEFINE(ULIMIT_MAXFDS) +fi +]) + +AC_DEFUN(BASH_CHECK_LIB_TERMCAP, +[ +if test "X$bash_cv_termcap_lib" = "X"; then +_bash_needmsg=yes +else +AC_MSG_CHECKING(which library has the termcap functions) +_bash_needmsg= +fi +AC_CACHE_VAL(bash_cv_termcap_lib, +[AC_CHECK_LIB(termcap, tgetent, bash_cv_termcap_lib=libtermcap, + [AC_CHECK_LIB(curses, tgetent, bash_cv_termcap_lib=libcurses, + [AC_CHECK_LIB(ncurses, tgetent, bash_cv_termcap_lib=libncurses, + bash_cv_termcap_lib=gnutermcap)])])]) +if test "X$_bash_needmsg" = "Xyes"; then +AC_MSG_CHECKING(which library has the termcap functions) +fi +AC_MSG_RESULT(using $bash_cv_termcap_lib) +if test $bash_cv_termcap_lib = gnutermcap; then +LDFLAGS="$LDFLAGS -L./lib/termcap" +TERMCAP_LIB="./lib/termcap/libtermcap.a" +TERMCAP_DEP="./lib/termcap/libtermcap.a" +elif test $bash_cv_termcap_lib = libtermcap; then +TERMCAP_LIB=-ltermcap +TERMCAP_DEP= +elif test $bash_cv_termcap_lib = libncurses; then +TERMCAP_LIB=-lncurses +TERMCAP_DEP= +else +TERMCAP_LIB=-lcurses +TERMCAP_DEP= +fi +]) + +AC_DEFUN(BASH_FUNC_GETCWD, +[AC_MSG_CHECKING([if getcwd() calls popen()]) +AC_CACHE_VAL(bash_cv_getcwd_calls_popen, +[AC_TRY_RUN([ +#include +#ifdef HAVE_UNISTD_H +#include +#endif + +#ifndef __STDC__ +#ifndef const +#define const +#endif +#endif + +int popen_called; + +FILE * +popen(command, type) + const char *command; + const char *type; +{ + popen_called = 1; + return (FILE *)NULL; +} + +FILE *_popen(command, type) + const char *command; + const char *type; +{ + return (popen (command, type)); +} + +int +pclose(stream) +FILE *stream; +{ + return 0; +} + +int +_pclose(stream) +FILE *stream; +{ + return 0; +} + +main() +{ + char lbuf[32]; + popen_called = 0; + getcwd(lbuf, 32); + exit (popen_called); +} +], bash_cv_getcwd_calls_popen=no, bash_cv_getcwd_calls_popen=yes, +AC_MSG_ERROR(cannot check whether getcwd calls popen if cross compiling))]) +AC_MSG_RESULT($bash_cv_getcwd_calls_popen) +if test $bash_cv_getcwd_calls_popen = yes; then +AC_DEFINE(GETCWD_BROKEN) +fi +]) + +AC_DEFUN(BASH_STRUCT_DIRENT_D_INO, +[AC_REQUIRE([AC_HEADER_DIRENT]) +AC_MSG_CHECKING(if struct dirent has a d_ino member) +AC_CACHE_VAL(bash_cv_dirent_has_dino, +[AC_TRY_COMPILE([ +#include +#include +#ifdef HAVE_UNISTD_H +# include +#endif /* HAVE_UNISTD_H */ +#if defined(HAVE_DIRENT_H) +# include +#else +# define dirent direct +# ifdef HAVE_SYS_NDIR_H +# include +# endif /* SYSNDIR */ +# ifdef HAVE_SYS_DIR_H +# include +# endif /* SYSDIR */ +# ifdef HAVE_NDIR_H +# include +# endif +#endif /* HAVE_DIRENT_H */ +],[ +struct dirent d; int z; z = d.d_ino; +], bash_cv_dirent_has_dino=yes, bash_cv_dirent_has_dino=no)]) +AC_MSG_RESULT($bash_cv_dirent_has_dino) +if test $bash_cv_dirent_has_dino = yes; then +AC_DEFINE(STRUCT_DIRENT_HAS_D_INO) +fi +]) + +AC_DEFUN(BASH_REINSTALL_SIGHANDLERS, +[AC_REQUIRE([AC_TYPE_SIGNAL]) +AC_REQUIRE([BASH_SIGNAL_CHECK]) +AC_MSG_CHECKING([if signal handlers must be reinstalled when invoked]) +AC_CACHE_VAL(bash_cv_must_reinstall_sighandlers, +[AC_TRY_RUN([ +#include +#ifdef HAVE_UNISTD_H +#include +#endif + +typedef RETSIGTYPE sigfunc(); + +int nsigint; + +#ifdef HAVE_POSIX_SIGNALS +sigfunc * +set_signal_handler(sig, handler) + int sig; + sigfunc *handler; +{ + struct sigaction act, oact; + act.sa_handler = handler; + act.sa_flags = 0; + sigemptyset (&act.sa_mask); + sigemptyset (&oact.sa_mask); + sigaction (sig, &act, &oact); + return (oact.sa_handler); +} +#else +#define set_signal_handler(s, h) signal(s, h) +#endif + +RETSIGTYPE +sigint(s) +int s; +{ + nsigint++; +} + +main() +{ + nsigint = 0; + set_signal_handler(SIGINT, sigint); + kill((int)getpid(), SIGINT); + kill((int)getpid(), SIGINT); + exit(nsigint != 2); +} +], bash_cv_must_reinstall_sighandlers=no, bash_cv_must_reinstall_sighandlers=yes, +AC_MSG_ERROR(cannot check signal handling if cross compiling))]) +AC_MSG_RESULT($bash_cv_must_reinstall_sighandlers) +if test $bash_cv_must_reinstall_sighandlers = yes; then +AC_DEFINE(MUST_REINSTALL_SIGHANDLERS) +fi +]) + +AC_DEFUN(BASH_FUNC_SBRK_DECLARED, +[AC_MSG_CHECKING(for declaration of sbrk in ) +AC_CACHE_VAL(bash_cv_sbrk_declared, +[AC_EGREP_HEADER(sbrk, unistd.h, + bash_cv_sbrk_declared=yes, bash_cv_sbrk_declared=no)]) +AC_MSG_RESULT($bash_cv_sbrk_declared) +if test $bash_cv_sbrk_declared = yes; then +AC_DEFINE(SBRK_DECLARED) +fi +]) + +dnl check that some necessary job control definitions are present +AC_DEFUN(BASH_JOB_CONTROL_MISSING, +[AC_REQUIRE([BASH_SIGNAL_CHECK]) +AC_MSG_CHECKING(for presence of necessary job control definitions) +AC_CACHE_VAL(bash_cv_job_control_missing, +[AC_TRY_RUN([ +#include +#ifdef HAVE_SYS_WAIT_H +#include +#endif +#ifdef HAVE_UNISTD_H +#include +#endif +#include + +/* Add more tests in here as appropriate. */ +main() +{ +/* signal type */ +#if !defined (HAVE_POSIX_SIGNALS) && !defined (HAVE_BSD_SIGNALS) +exit(1); +#endif + +/* signals and tty control. */ +#if !defined (SIGTSTP) || !defined (SIGSTOP) || !defined (SIGCONT) +exit (1); +#endif + +/* process control */ +#if !defined (WNOHANG) || !defined (WUNTRACED) +exit(1); +#endif + +/* Posix systems have tcgetpgrp and waitpid. */ +#if defined (_POSIX_VERSION) && !defined (HAVE_TCGETPGRP) +exit(1); +#endif + +#if defined (_POSIX_VERSION) && !defined (HAVE_WAITPID) +exit(1); +#endif + +/* Other systems have TIOCSPGRP/TIOCGPRGP and wait3. */ +#if !defined (_POSIX_VERSION) && !defined (HAVE_WAIT3) +exit(1); +#endif + +exit(0); +}],bash_cv_job_control_missing=present, bash_cv_job_control_missing=missing, + AC_MSG_ERROR(cannot check job control if cross-compiling)) +]) +AC_MSG_RESULT($bash_cv_job_control_missing) +if test $bash_cv_job_control_missing = missing; then +AC_DEFINE(JOB_CONTROL_MISSING) +fi +]) + +dnl check whether named pipes are present +dnl this requires a previous check for mkfifo, but that is awkward to specify +AC_DEFUN(BASH_SYS_NAMED_PIPES, +[AC_MSG_CHECKING(for presence of named pipes) +AC_CACHE_VAL(bash_cv_sys_named_pipes, +[AC_TRY_RUN([ +#include +#include +#ifdef HAVE_UNISTD_H +#include +#endif + +/* Add more tests in here as appropriate. */ +main() +{ +int fd; + +#if defined (HAVE_MKFIFO) +exit (0); +#endif + +#if !defined (S_IFIFO) && (defined (_POSIX_VERSION) && !defined (S_ISFIFO)) +exit (1); +#endif + +#if defined (NeXT) +exit (1); +#endif + +fd = mknod ("/tmp/sh-np-autoconf", 0666 | S_IFIFO, 0); +if (fd == -1) + exit (1); +close(fd); +unlink ("/tmp/sh-np-autoconf"); +exit(0); +}],bash_cv_sys_named_pipes=present, bash_cv_sys_named_pipes=missing, + AC_MSG_ERROR(cannot check for named pipes if cross-compiling)) +]) +AC_MSG_RESULT($bash_cv_sys_named_pipes) +if test $bash_cv_sys_named_pipes = missing; then +AC_DEFINE(NAMED_PIPES_MISSING) +fi +]) + +AC_DEFUN(BASH_FUNC_POSIX_SETJMP, +[AC_REQUIRE([BASH_SIGNAL_CHECK]) +AC_MSG_CHECKING(for presence of POSIX-style sigsetjmp/siglongjmp) +AC_CACHE_VAL(bash_cv_func_sigsetjmp, +[AC_TRY_RUN([ +#ifdef HAVE_UNISTD_H +#include +#endif +#include +#include +#include + +main() +{ +#if !defined (_POSIX_VERSION) || !defined (HAVE_POSIX_SIGNALS) +exit (1); +#else + +int code; +sigset_t set, oset; +sigjmp_buf xx; + +/* get the mask */ +sigemptyset(&set); +sigemptyset(&oset); +sigprocmask(SIG_BLOCK, (sigset_t *)NULL, &set); +sigprocmask(SIG_BLOCK, (sigset_t *)NULL, &oset); + +/* save it */ +code = sigsetjmp(xx, 1); +if (code) + exit(0); /* could get sigmask and compare to oset here. */ + +/* change it */ +sigaddset(&set, SIGINT); +sigprocmask(SIG_BLOCK, &set, (sigset_t *)NULL); + +/* and siglongjmp */ +siglongjmp(xx, 10); +exit(1); +#endif +}],bash_cv_func_sigsetjmp=present, bash_cv_func_sigsetjmp=missing, + AC_MSG_ERROR(cannot check for sigsetjmp/siglongjmp if cross-compiling)) +]) +AC_MSG_RESULT($bash_cv_func_sigsetjmp) +if test $bash_cv_func_sigsetjmp = present; then +AC_DEFINE(HAVE_POSIX_SIGSETJMP) +fi +]) + +AC_DEFUN(BASH_HAVE_TIOCGWINSZ, +[AC_MSG_CHECKING(for TIOCGWINSZ in sys/ioctl.h) +AC_CACHE_VAL(bash_cv_tiocgwinsz_in_ioctl, +[AC_TRY_COMPILE([#include +#include ], [int x = TIOCGWINSZ;], + bash_cv_tiocgwinsz_in_ioctl=yes,bash_cv_tiocgwinsz_in_ioctl=no)]) +AC_MSG_RESULT($bash_cv_tiocgwinsz_in_ioctl) +if test $bash_cv_tiocgwinsz_in_ioctl = yes; then +AC_DEFINE(GWINSZ_IN_SYS_IOCTL) +fi +]) + +AC_DEFUN(BASH_HAVE_TIOCSTAT, +[AC_MSG_CHECKING(for TIOCSTAT in sys/ioctl.h) +AC_CACHE_VAL(bash_cv_tiocstat_in_ioctl, +[AC_TRY_COMPILE([#include +#include ], [int x = TIOCSTAT;], + bash_cv_tiocstat_in_ioctl=yes,bash_cv_tiocstat_in_ioctl=no)]) +AC_MSG_RESULT($bash_cv_tiocstat_in_ioctl) +if test $bash_cv_tiocstat_in_ioctl = yes; then +AC_DEFINE(TIOCSTAT_IN_SYS_IOCTL) +fi +]) + +AC_DEFUN(BASH_HAVE_FIONREAD, +[AC_MSG_CHECKING(for FIONREAD in sys/ioctl.h) +AC_CACHE_VAL(bash_cv_fionread_in_ioctl, +[AC_TRY_COMPILE([#include +#include ], [int x = FIONREAD;], + bash_cv_fionread_in_ioctl=yes,bash_cv_fionread_in_ioctl=no)]) +AC_MSG_RESULT($bash_cv_fionread_in_ioctl) +if test $bash_cv_fionread_in_ioctl = yes; then +AC_DEFINE(FIONREAD_IN_SYS_IOCTL) +fi +]) + +AC_DEFUN(BASH_CHECK_GETPW_FUNCS, +[AC_MSG_CHECKING(whether programs are able to redeclare getpw functions) +AC_CACHE_VAL(bash_cv_can_redecl_getpw, +[AC_TRY_COMPILE([#include +#include +extern struct passwd *getpwent();], [struct passwd *z; z = getpwent();], + bash_cv_can_redecl_getpw=yes,bash_cv_can_redecl_getpw=no)]) +AC_MSG_RESULT($bash_cv_can_redecl_getpw) +if test $bash_cv_can_redecl_getpw = no; then +AC_DEFINE(HAVE_GETPW_DECLS) +fi +]) + +AC_DEFUN(BASH_CHECK_DEV_FD, +[AC_MSG_CHECKING(whether /dev/fd is available) +AC_CACHE_VAL(bash_cv_dev_fd, +[if test -d /dev/fd && test -r /dev/fd/0; then + bash_cv_dev_fd=standard + elif test -d /proc/self/fd && test -r /proc/self/fd/0; then + bash_cv_dev_fd=whacky + else + bash_cv_dev_fd=absent + fi +]) +AC_MSG_RESULT($bash_cv_dev_fd) +if test $bash_cv_dev_fd = "standard"; then + AC_DEFINE(HAVE_DEV_FD) + AC_DEFINE(DEV_FD_PREFIX, "/dev/fd/") +elif test $bash_cv_dev_fd = "whacky"; then + AC_DEFINE(HAVE_DEV_FD) + AC_DEFINE(DEV_FD_PREFIX, "/proc/self/fd/") +fi +]) + +AC_DEFUN(BASH_CHECK_SOCKLIB, +[ +if test "X$bash_cv_have_socklib" = "X"; then +_bash_needmsg= +else +AC_MSG_CHECKING(for socket library) +_bash_needmsg=yes +fi +AC_CACHE_VAL(bash_cv_have_socklib, +[AC_CHECK_LIB(socket, getpeername, + bash_cv_have_socklib=yes, bash_cv_have_socklib=no, -lnsl)]) +if test "X$_bash_needmsg" = Xyes; then + AC_MSG_RESULT($bash_cv_have_socklib) + _bash_needmsg= +fi +if test $bash_cv_have_socklib = yes; then + # check for libnsl, add it to LIBS if present + if test "X$bash_cv_have_libnsl" = "X"; then + _bash_needmsg= + else + AC_MSG_CHECKING(for libnsl) + _bash_needmsg=yes + fi + AC_CACHE_VAL(bash_cv_have_libnsl, + [AC_CHECK_LIB(nsl, t_open, + bash_cv_have_libnsl=yes, bash_cv_have_libnsl=no)]) + if test "X$_bash_needmsg" = Xyes; then + AC_MSG_RESULT($bash_cv_have_libnsl) + _bash_needmsg= + fi + if test $bash_cv_have_libnsl = yes; then + LIBS="-lsocket -lnsl $LIBS" + else + LIBS="-lsocket $LIBS" + fi + AC_DEFINE(HAVE_LIBSOCKET) + AC_DEFINE(HAVE_GETPEERNAME) +fi +]) + +AC_DEFUN(BASH_DEFAULT_MAIL_DIR, +[AC_MSG_CHECKING(for default mail directory) +AC_CACHE_VAL(bash_cv_mail_dir, +[if test -d /var/mail; then + bash_cv_mail_dir=/var/mail + elif test -d /usr/mail; then + bash_cv_mail_dir=/usr/mail + elif test -d /usr/spool/mail; then + bash_cv_mail_dir=/usr/spool/mail + elif test -d /var/spool/mail; then + bash_cv_mail_dir=/var/spool/mail + else + bash_cv_mail_dir=unknown + fi +]) +AC_MSG_RESULT($bash_cv_mail_dir) +if test $bash_cv_mail_dir = "/var/mail"; then + AC_DEFINE(DEFAULT_MAIL_DIRECTORY, "/var/mail") +elif test $bash_cv_mail_dir = "/usr/mail"; then + AC_DEFINE(DEFAULT_MAIL_DIRECTORY, "/usr/mail") +elif test $bash_cv_mail_dir = "/var/spool/mail"; then + AC_DEFINE(DEFAULT_MAIL_DIRECTORY, "/var/spool/mail") +elif test $bash_cv_mail_dir = "/usr/spool/mail"; then + AC_DEFINE(DEFAULT_MAIL_DIRECTORY, "/usr/spool/mail") +else + AC_DEFINE(DEFAULT_MAIL_DIRECTORY, "unknown") +fi +]) + +dnl +dnl Check if HPUX needs _KERNEL defined for RLIMIT_* definitions +dnl +AC_DEFUN(BASH_KERNEL_RLIMIT_CHECK, +[AC_MSG_CHECKING([whether $host_os needs _KERNEL for RLIMIT defines]) +AC_CACHE_VAL(bash_cv_kernel_rlimit, +[AC_TRY_COMPILE([ +#include +#include +], +[ + int f; + f = RLIMIT_DATA; +], bash_cv_kernel_rlimit=no, + [AC_TRY_COMPILE([ + #include + #define _KERNEL + #include + #undef _KERNEL + ], + [ + int f; + f = RLIMIT_DATA; + ], bash_cv_kernel_rlimit=yes, bash_cv_kernel_rlimit=no)] +)]) +AC_MSG_RESULT($bash_cv_kernel_rlimit) +if test $bash_cv_kernel_rlimit = yes; then +AC_DEFINE(RLIMIT_NEEDS_KERNEL) +fi +]) diff --git a/alias.c b/alias.c index f9be0b4..707e38b 100644 --- a/alias.c +++ b/alias.c @@ -19,12 +19,19 @@ along with Bash; see the file COPYING. If not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include "config.h" + +#if defined (ALIAS) + +#if defined (HAVE_UNISTD_H) +# include +#endif + #include #include "bashansi.h" -#include "config.h" #include "command.h" #include "general.h" -#include "hash.h" +#include "externs.h" #include "alias.h" static int qsort_alias_compare (); @@ -44,22 +51,18 @@ initialize_aliases () } /* Scan the list of aliases looking for one with NAME. Return NULL - if the alias doesn't exist, else a pointer to the assoc. */ -ASSOC * + if the alias doesn't exist, else a pointer to the alias_t. */ +alias_t * find_alias (name) char *name; { BUCKET_CONTENTS *al; - if (!aliases) - return ((ASSOC *)NULL); - else - al = find_hash_item (name, aliases); + if (aliases == 0) + return ((alias_t *)NULL); - if (al) - return ((ASSOC *)al->data); - else - return ((ASSOC *)NULL); + al = find_hash_item (name, aliases); + return (al ? (alias_t *)al->data : (alias_t *)NULL); } /* Return the value of the alias for NAME, or NULL if there is none. */ @@ -67,11 +70,13 @@ char * get_alias_value (name) char *name; { - ASSOC *alias = find_alias (name); - if (alias) - return (alias->value); - else + alias_t *alias; + + if (aliases == 0) return ((char *)NULL); + + alias = find_alias (name); + return (alias ? alias->value : (char *)NULL); } /* Make a new alias from NAME and VALUE. If NAME can be found, @@ -80,10 +85,15 @@ void add_alias (name, value) char *name, *value; { - ASSOC *temp = (ASSOC *)NULL; + BUCKET_CONTENTS *elt; + alias_t *temp; + int n; if (!aliases) - initialize_aliases (); + { + initialize_aliases (); + temp = (alias_t *)NULL; + } else temp = find_alias (name); @@ -91,20 +101,39 @@ add_alias (name, value) { free (temp->value); temp->value = savestring (value); + n = value[strlen (value) - 1]; + if (n == ' ' || n == '\t') + temp->flags |= AL_EXPANDNEXT; } else { - BUCKET_CONTENTS *elt; - - temp = (ASSOC *)xmalloc (sizeof (ASSOC)); + temp = (alias_t *)xmalloc (sizeof (alias_t)); temp->name = savestring (name); temp->value = savestring (value); + temp->flags = 0; + + n = value[strlen (value) - 1]; + if (n == ' ' || n == '\t') + temp->flags |= AL_EXPANDNEXT; elt = add_hash_item (savestring (name), aliases); elt->data = (char *)temp; } } +/* Delete a single alias structure. */ +static void +free_alias_data (data) + char *data; +{ + register alias_t *a; + + a = (alias_t *)data; + free (a->value); + free (a->name); + free (data); +} + /* Remove the alias with name NAME from the alias table. Returns the number of aliases left in the table, or -1 if the alias didn't exist. */ @@ -114,93 +143,59 @@ remove_alias (name) { BUCKET_CONTENTS *elt; - if (!aliases) + if (aliases == 0) return (-1); elt = remove_hash_item (name, aliases); if (elt) { - ASSOC *t; - - t = (ASSOC *)elt->data; - free (t->name); - free (t->value); + free_alias_data (elt->data); free (elt->key); /* alias name */ - free (t); - return (aliases->nentries); } return (-1); } -/* Delete a hash bucket chain of aliases. */ -static void -delete_alias_list (alias_list) - BUCKET_CONTENTS *alias_list; -{ - register BUCKET_CONTENTS *bp, *temp; - register ASSOC *a; - - for (bp = alias_list; bp; ) - { - temp = bp->next; - a = (ASSOC *)bp->data; - free (a->value); - free (a->name); - free (bp->data); - free (bp->key); - free (bp); - bp = temp; - } -} - /* Delete all aliases. */ void delete_all_aliases () { - register int i; - - if (!aliases) + if (aliases == 0) return; - for (i = 0; i < aliases->nbuckets; i++) - { - register BUCKET_CONTENTS *bp; - - bp = get_hash_bucket (i, aliases); - delete_alias_list (bp); - } + flush_hash_table (aliases, free_alias_data); free (aliases); aliases = (HASH_TABLE *)NULL; } /* Return an array of aliases that satisfy the conditions tested by FUNCTION. If FUNCTION is NULL, return all aliases. */ -static ASSOC ** +static alias_t ** map_over_aliases (function) Function *function; { register int i; register BUCKET_CONTENTS *tlist; - ASSOC *alias, **list = (ASSOC **)NULL; - int list_index = 0, list_size = 0; + alias_t *alias, **list; + int list_index, list_size; - for (i = 0; i < aliases->nbuckets; i++) + list = (alias_t **)NULL; + for (i = list_index = list_size = 0; i < aliases->nbuckets; i++) { tlist = get_hash_bucket (i, aliases); while (tlist) { - alias = (ASSOC *)tlist->data; + alias = (alias_t *)tlist->data; if (!function || (*function) (alias)) { if (list_index + 1 >= list_size) - list = (ASSOC **) - xrealloc ((char *)list, (list_size += 20) * sizeof (ASSOC *)); + list = (alias_t **) + xrealloc ((char *)list, (list_size += 20) * sizeof (alias_t *)); list[list_index++] = alias; - list[list_index] = (ASSOC *)NULL; + list[list_index] = (alias_t *)NULL; } tlist = tlist->next; } @@ -210,31 +205,31 @@ map_over_aliases (function) static void sort_aliases (array) - ASSOC **array; + alias_t **array; { - qsort (array, array_len ((char **)array), sizeof (ASSOC *), qsort_alias_compare); + qsort (array, array_len ((char **)array), sizeof (alias_t *), qsort_alias_compare); } static int qsort_alias_compare (as1, as2) - ASSOC **as1, **as2; + alias_t **as1, **as2; { int result; - + if ((result = (*as1)->name[0] - (*as2)->name[0]) == 0) result = strcmp ((*as1)->name, (*as2)->name); return (result); } - -/* Return a sorted list of all defined aliases */ -ASSOC ** + +/* Return a sorted list of all defined aliases */ +alias_t ** all_aliases () { - ASSOC **list; + alias_t **list; if (!aliases) - return ((ASSOC **)NULL); + return ((alias_t **)NULL); list = map_over_aliases ((Function *)NULL); if (list) @@ -246,12 +241,10 @@ char * alias_expand_word (s) char *s; { - ASSOC *r = find_alias (s); + alias_t *r; - if (r) - return (savestring (r->value)); - else - return ((char *)NULL); + r = find_alias (s); + return (r ? savestring (r->value) : (char *)NULL); } /* Return non-zero if CHARACTER is a member of the class of characters @@ -391,7 +384,7 @@ skipws (string, start) so all characters show up (e.g. foo'' and foo""bar) */ static int rd_token (string, start) - char *string; + char *string; int start; { register int i; @@ -408,7 +401,7 @@ rd_token (string, start) /* If this character is a quote character, we want to call skipquotes to get the whole quoted portion as part of this word. That word will not generally match an alias, even if te unquoted word would - have. The presence of the quotes in the token serves then to + have. The presence of the quotes in the token serves then to inhibit expansion. */ if (quote_char (string[i])) { @@ -431,7 +424,7 @@ alias_expand (string) register int i, j, start; char *token = xmalloc (line_len); int tl, real_start, expand_next, expand_this_token; - ASSOC *alias; + alias_t *alias; line[0] = i = 0; expand_next = 0; @@ -462,8 +455,7 @@ alias_expand (string) expanding it if there is not enough room. */ j = strlen (line); tl = i - start; /* number of characters just skipped */ - if (1 + j + tl >= line_len) - line = (char *)xrealloc (line, line_len += (50 + tl)); + RESIZE_MALLOCED_BUFFER (line, j, (tl + 1), line_len, (tl + 50)); strncpy (line + j, string + start, tl); line[j + tl] = '\0'; @@ -506,30 +498,35 @@ alias_expand (string) (expand_this_token || alias_expand_all) && (alias = find_alias (token))) { - char *v = alias->value; - int l = strlen (v); - + char *v; + int vlen, llen; + + v = alias->value; + vlen = strlen (v); + llen = strlen (line); + /* +3 because we possibly add one more character below. */ - if ((l + 3) > line_len - (int)strlen (line)) - line = (char *)xrealloc (line, line_len += (50 + l)); + RESIZE_MALLOCED_BUFFER (line, llen, (vlen + 3), line_len, (vlen + 50)); - strcat (line, v); + strcpy (line + llen, v); - if ((expand_this_token && l && whitespace (v[l - 1])) || + if ((expand_this_token && vlen && whitespace (v[vlen - 1])) || alias_expand_all) expand_next = 1; } else { - int ll = strlen (line); - int tlen = i - real_start; /* tlen == strlen(token) */ + int llen, tlen; + + llen = strlen (line); + tlen = i - real_start; /* tlen == strlen(token) */ - if (ll + tlen + 2 > line_len) - line = (char *)xrealloc (line, line_len += 50 + ll + tlen); + RESIZE_MALLOCED_BUFFER (line, llen, (tlen + 1), line_len, (llen + tlen + 50)); - strncpy (line + ll, string + real_start, tlen); - line[ll + tlen] = '\0'; + strncpy (line + llen, string + real_start, tlen); + line[llen + tlen] = '\0'; } command_word = 0; } } +#endif /* ALIAS */ diff --git a/alias.h b/alias.h index 2a2d184..7b7cac7 100644 --- a/alias.h +++ b/alias.h @@ -18,33 +18,22 @@ along with Bash; see the file COPYING. If not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ -#if !defined (_ALIAS_) -#define _ALIAS_ +#if !defined (_ALIAS_H_) +#define _ALIAS_H_ -#include "hash.h" +#include "hashlib.h" extern char *xmalloc (); -#if !defined (whitespace) -# define whitespace(c) (((c) == ' ') || ((c) == '\t')) -#endif /* !whitespace */ - -#if !defined (savestring) -# define savestring(x) (char *)strcpy (xmalloc (1 + strlen (x)), (x)) -#endif /* !savestring */ - -#if !defined (NULL) -# if defined (__STDC__) -# define NULL ((void *) 0) -# else -# define NULL 0x0 -# endif /* !__STDC__ */ -#endif /* !NULL */ - -typedef struct { +typedef struct alias { char *name; char *value; -} ASSOC; + char flags; +} alias_t; + +/* Values for `flags' member of struct alias. */ +#define AL_EXPANDNEXT 0x1 +#define AL_BEINGEXPANDED 0x2 /* The list of known aliases. */ extern HASH_TABLE *aliases; @@ -52,8 +41,8 @@ extern HASH_TABLE *aliases; extern void initialize_aliases (); /* Scan the list of aliases looking for one with NAME. Return NULL - if the alias doesn't exist, else a pointer to the assoc. */ -extern ASSOC *find_alias (); + if the alias doesn't exist, else a pointer to the alias. */ +extern alias_t *find_alias (); /* Return the value of the alias for NAME, or NULL if there is none. */ extern char *get_alias_value (); @@ -66,10 +55,16 @@ extern void add_alias (); the index of the removed alias, or -1 if the alias didn't exist. */ extern int remove_alias (); +/* Remove all aliases. */ +extern void delete_all_aliases (); + /* Return a new line, with any aliases expanded. */ extern char *alias_expand (); /* Return an array of all defined aliases. */ -extern ASSOC **all_aliases (); +extern alias_t **all_aliases (); + +/* Expand a single word for aliases. */ +extern char *alias_expand_word (); -#endif /* _ALIAS_ */ +#endif /* _ALIAS_H_ */ diff --git a/array.c b/array.c new file mode 100644 index 0000000..0de505c --- /dev/null +++ b/array.c @@ -0,0 +1,602 @@ +/* + * array.c - functions to create, destroy, access, and manipulate arrays + * of strings. + * + * Arrays are sparse doubly-linked lists. An element's index is stored + * with it. + * + * Chet Ramey + * chet@ins.cwru.edu + */ +#include "config.h" + +#if defined (ARRAY_VARS) + +#if defined (HAVE_UNISTD_H) +# include +#endif + +#include +#include "shell.h" +#include "array.h" +#include "builtins/common.h" + +extern char *quote_string (); /* XXX */ + +#define ADD_BEFORE(ae, new) \ + do { \ + ae->prev->next = new; \ + new->prev = ae->prev; \ + ae->prev = new; \ + new->next = ae; \ + } while(0) + +/* + * Allocate and return a new array element with index INDEX and value + * VALUE. + */ +ARRAY_ELEMENT * +new_array_element(indx, value) +arrayind_t indx; +char *value; +{ + ARRAY_ELEMENT *r; + + r = (ARRAY_ELEMENT *) xmalloc(sizeof(ARRAY_ELEMENT)); + r->ind = indx; + r->value = value ? savestring(value) : (char *)NULL; + r->next = r->prev = (ARRAY_ELEMENT *) NULL; + return(r); +} + +void +destroy_array_element(ae) +ARRAY_ELEMENT *ae; +{ + FREE(ae->value); + free(ae); +} + +ARRAY * +new_array() +{ + ARRAY *r; + ARRAY_ELEMENT *head; + + r =(ARRAY *) xmalloc(sizeof(ARRAY)); + r->type = array_indexed; + r->max_index = r->max_size = -1; + r->num_elements = 0; + head = new_array_element(-1, (char *)NULL); /* dummy head */ + head->prev = head->next = head; + r->head = head; + return(r); +} + +void +empty_array (a) +ARRAY *a; +{ + register ARRAY_ELEMENT *r, *r1; + + if (a == 0) + return; + for (r = element_forw(a->head); r != a->head; ) { + r1 = element_forw(r); + destroy_array_element(r); + r = r1; + } + a->head->next = a->head->prev = a->head; + a->max_index = a->max_size = -1; + a->num_elements = a->max_size = 0; +} + +void +dispose_array(a) +ARRAY *a; +{ + if (a == 0) + return; + empty_array (a); + destroy_array_element(a->head); + free(a); +} + +ARRAY * +dup_array(a) +ARRAY *a; +{ + ARRAY *a1; + ARRAY_ELEMENT *ae, *new; + + if (!a) + return((ARRAY *) NULL); + a1 = new_array(); + a1->type = a->type; + a1->max_index = a->max_index; + a1->num_elements = a->num_elements; + a1->max_size = a->max_size; + for (ae = element_forw(a->head); ae != a->head; ae = element_forw(ae)) { + new = new_array_element(element_index(ae), element_value(ae)); + ADD_BEFORE(a1->head, new); + } + return(a1); +} + +/* + * Make and return a new array composed of the elements in array A from + * S to E, inclusive. + */ +ARRAY * +dup_array_subrange(array, s, e) +ARRAY *array; +ARRAY_ELEMENT *s, *e; +{ + ARRAY *a; + ARRAY_ELEMENT *p, *n; + int i; + + a = new_array (); + a->type = array->type; + + for (p = s, i = 0; p != e; p = element_forw(p), i++) { + n = new_array_element (i, element_value(p)); + ADD_BEFORE(a->head, n); + } + a->num_elements = a->max_index = i; + return a; +} + +ARRAY_ELEMENT * +copy_array_element(ae) +ARRAY_ELEMENT *ae; +{ + return(ae ? new_array_element(element_index(ae), element_value(ae)) + : (ARRAY_ELEMENT *) NULL); +} + +/* + * Add a new element with index I and value V to array A (a[i] = v). + */ +int +array_add_element(a, i, v) +ARRAY *a; +arrayind_t i; +char *v; +{ + register ARRAY_ELEMENT *new, *ae; + + if (!a) + return(-1); + new = new_array_element(i, v); + if (i > array_max_index(a)) { + /* + * Hook onto the end. This also works for an empty array. + * Fast path for the common case of allocating arrays + * sequentially. + */ + ADD_BEFORE(a->head, new); + a->max_index = i; + a->num_elements++; + return(0); + } + /* + * Otherwise we search for the spot to insert it. + */ + for (ae = element_forw(a->head); ae != a->head; ae = element_forw(ae)) { + if (element_index(ae) == i) { + /* + * Replacing an existing element. + */ + destroy_array_element(new); + free(element_value(ae)); + ae->value = savestring(v); + return(0); + } else if (element_index(ae) > i) { + ADD_BEFORE(ae, new); + a->num_elements++; + return(0); + } + } + return (-1); /* problem */ +} + +/* + * Delete the element with index I from array A and return it so the + * caller can dispose of it. + */ +ARRAY_ELEMENT * +array_delete_element(a, i) +ARRAY *a; +arrayind_t i; +{ + register ARRAY_ELEMENT *ae; + + if (!a || array_empty(a)) + return((ARRAY_ELEMENT *) NULL); + for (ae = element_forw(a->head); ae != a->head; ae = element_forw(ae)) + if (element_index(ae) == i) { + ae->next->prev = ae->prev; + ae->prev->next = ae->next; + a->num_elements--; + if (i == array_max_index(a)) + a->max_index = element_index(ae->prev); + return(ae); + } + return((ARRAY_ELEMENT *) NULL); +} + +/* + * Return the value of a[i]. + */ +char * +array_reference(a, i) +ARRAY *a; +arrayind_t i; +{ + register ARRAY_ELEMENT *ae; + + if (a == 0 || array_empty(a)) + return((char *) NULL); + for (ae = element_forw(a->head); ae != a->head; ae = element_forw(ae)) + if (element_index(ae) == i) + return(element_value(ae)); + return((char *) NULL); +} + +/* + * Walk the array, calling FUNC once for each element, with the array + * element as the argument. + */ +void +array_walk(a, func) +ARRAY *a; +Function *func; +{ + register ARRAY_ELEMENT *ae; + + if (a == 0 || array_empty(a)) + return; + for (ae = element_forw(a->head); ae != a->head; ae = element_forw(ae)) + (*func)(ae); +} + +/* + * Return a string that is the concatenation of all the elements in A, + * separated by SEP. + */ +static char * +array_to_string_internal (start, end, sep, quoted) +ARRAY_ELEMENT *start, *end; +char *sep; +int quoted; +{ + char *result, *t; + ARRAY_ELEMENT *ae; + int slen, rsize, rlen, reg; + + if (start == end) /* XXX - should not happen */ + return ((char *)NULL); + + slen = strlen(sep); + for (rsize = rlen = 0, ae = start; ae != end; ae = element_forw(ae)) { + if (rsize == 0) + result = xmalloc (rsize = 64); + if (element_value(ae)) { + t = quoted ? quote_string(element_value(ae)) : element_value(ae); + reg = strlen(t); + RESIZE_MALLOCED_BUFFER (result, rlen, (reg + slen + 2), + rsize, rsize); + strcpy(result + rlen, t); + rlen += reg; + if (quoted && t) + free(t); + /* + * Add a separator only after non-null elements. + */ + if (element_forw(ae) != end) { + strcpy(result + rlen, sep); + rlen += slen; + } + } + } + result[rlen] = '\0'; /* XXX */ + return(result); +} + +char * +array_to_string (a, sep, quoted) +ARRAY *a; +char *sep; +int quoted; +{ + if (a == 0) + return((char *)NULL); + if (array_empty(a)) + return(savestring("")); + return (array_to_string_internal (element_forw(a->head), a->head, sep, quoted)); +} + +char * +array_to_assignment_string (a) +ARRAY *a; +{ + char *result, *indstr, *valstr; + ARRAY_ELEMENT *ae; + int rsize, rlen, elen; + + if (a == 0 || array_empty (a)) + return((char *)NULL); + + result = xmalloc (rsize = 128); + result[0] = '('; + rlen = 1; + + for (ae = element_forw(a->head); ae != a->head; ae = element_forw(ae)) { + indstr = itos (element_index(ae)); + valstr = element_value (ae) ? double_quote (element_value(ae)) + : (char *)NULL; + elen = STRLEN (indstr) + 8 + STRLEN (valstr); + RESIZE_MALLOCED_BUFFER (result, rlen, (elen + 1), rsize, rsize); + + result[rlen++] = '['; + strcpy (result + rlen, indstr); + rlen += STRLEN (indstr); + result[rlen++] = ']'; + result[rlen++] = '='; + if (valstr) { + strcpy (result + rlen, valstr); + rlen += STRLEN (valstr); + } + + if (element_forw(ae) != a->head) + result[rlen++] = ' '; + + FREE (indstr); + FREE (valstr); + } + RESIZE_MALLOCED_BUFFER (result, rlen, 1, rsize, 8); + result[rlen++] = ')'; + result[rlen] = '\0'; + return(result); +} + +char * +quoted_array_assignment_string (a) +ARRAY *a; +{ + char *vstr, *sv; + + sv = array_to_assignment_string (a); + if (sv == 0) + return ((char *)NULL); + + vstr = single_quote (sv); + free (sv); + return (vstr); +} + +#if 0 +/* Determine if s2 occurs in s1. If so, return a pointer to the + match in s1. The compare is case sensitive. */ +static char * +sindex (s1, s2) +register char *s1, *s2; +{ + register int i, l, len; + + for (i = 0, l = strlen(s2), len = strlen(s1); (len - i) >= l; i++) + if (strncmp (s1 + i, s2, l) == 0) + return (s1 + i); + return ((char *)NULL); +} +#endif + +/* + * Return an array consisting of elements in S, separated by SEP + */ +ARRAY * +string_to_array(s, sep) +char *s, *sep; +{ + ARRAY *a; + WORD_LIST *w; + + if (s == 0) + return((ARRAY *)NULL); + w = list_string (s, sep, 0); + if (w == 0) + return((ARRAY *)NULL); + a = word_list_to_array (w); + return (a); +} + +/* Convenience routines for the shell to translate to and from the form used + by the rest of the code. */ +WORD_LIST * +array_to_word_list(a) +ARRAY *a; +{ + WORD_LIST *list; + ARRAY_ELEMENT *ae; + + if (a == 0 || array_empty(a)) + return((WORD_LIST *)NULL); + list = (WORD_LIST *)NULL; + for (ae = element_forw(a->head); ae != a->head; ae = element_forw(ae)) + list = make_word_list (make_bare_word(element_value(ae)), list); + return (REVERSE_LIST(list, WORD_LIST *)); +} + +ARRAY * +assign_word_list (array, list) +ARRAY *array; +WORD_LIST *list; +{ + register WORD_LIST *l; + register arrayind_t i; + + for (l = list, i = 0; l; l = l->next, i++) + array_add_element(array, i, l->word->word); + return array; +} + +ARRAY * +word_list_to_array (list) +WORD_LIST *list; +{ + ARRAY *a; + + if (list == 0) + return((ARRAY *)NULL); + a = new_array(); + return (assign_word_list (a, list)); +} + +ARRAY * +array_quote(array) +ARRAY *array; +{ + ARRAY_ELEMENT *a; + char *t; + + if (array == 0 || array->head == 0 || array_empty (array)) + return (ARRAY *)NULL; + for (a = element_forw(array->head); a != array->head; a = element_forw(a)) { + t = quote_string (a->value); + FREE(a->value); + a->value = t; + } + return array; +} + +char * +array_subrange (a, start, end, quoted) +ARRAY *a; +int start, end, quoted; +{ + ARRAY_ELEMENT *h, *p; + int i; + + p = array_head (a); + if (p == 0 || array_empty (a) || start > array_num_elements (a)) + return ((char *)NULL); + + for (i = 0, p = element_forw(p); p != a->head && i < start; i++, p = element_forw(p)) + ; + if (p == a->head) + return ((char *)NULL); + for (h = p; p != a->head && i < end; i++, p = element_forw(p)) + ; + + return (array_to_string_internal (h, p, " ", quoted)); +} + +char * +array_pat_subst (a, pat, rep, mflags) +ARRAY *a; +char *pat, *rep; +int mflags; +{ + ARRAY *a2; + ARRAY_ELEMENT *e; + char *t; + + if (array_head (a) == 0 || array_empty (a)) + return ((char *)NULL); + + a2 = dup_array (a); + for (e = element_forw(a2->head); e != a2->head; e = element_forw(e)) { + t = pat_subst(element_value(e), pat, rep, mflags); + FREE(element_value(e)); + e->value = t; + } + + if (mflags & MATCH_QUOTED) + array_quote (a2); + t = array_to_string (a2, " ", 0); + dispose_array (a2); + + return t; +} + + +#if defined (TEST_ARRAY) +print_element(ae) +ARRAY_ELEMENT *ae; +{ + printf("array[%d] = %s\n",(int)element_index(ae), element_value(ae)); +} + +print_array(a) +ARRAY *a; +{ + printf("\n"); + array_walk(a, print_element); +} + +main() +{ + ARRAY *a, *new_a, *copy_of_a; + ARRAY_ELEMENT *ae; + char *s; + + a = new_array(); + array_add_element(a, 1, "one"); + array_add_element(a, 7, "seven"); + array_add_element(a, 4, "four"); + array_add_element(a, 1029, "one thousand twenty-nine"); + array_add_element(a, 12, "twelve"); + array_add_element(a, 42, "forty-two"); + print_array(a); + s = array_to_string (a, " "); + printf("s = %s\n", s); + copy_of_a = string_to_array(s, " "); + printf("copy_of_a:"); + print_array(copy_of_a); + dispose_array(copy_of_a); + printf("\n"); + free(s); + ae = array_delete_element(a, 4); + destroy_array_element(ae); + ae = array_delete_element(a, 1029); + destroy_array_element(ae); + array_add_element(a, 16, "sixteen"); + print_array(a); + s = array_to_string (a, " "); + printf("s = %s\n", s); + copy_of_a = string_to_array(s, " "); + printf("copy_of_a:"); + print_array(copy_of_a); + dispose_array(copy_of_a); + printf("\n"); + free(s); + array_add_element(a, 2, "two"); + array_add_element(a, 1029, "new one thousand twenty-nine"); + array_add_element(a, 0, "zero"); + array_add_element(a, 134, ""); + print_array(a); + s = array_to_string (a, ":"); + printf("s = %s\n", s); + copy_of_a = string_to_array(s, ":"); + printf("copy_of_a:"); + print_array(copy_of_a); + dispose_array(copy_of_a); + printf("\n"); + free(s); + new_a = copy_array(a); + print_array(new_a); + s = array_to_string (new_a, ":"); + printf("s = %s\n", s); + copy_of_a = string_to_array(s, ":"); + printf("copy_of_a:"); + print_array(copy_of_a); + dispose_array(copy_of_a); + printf("\n"); + free(s); + dispose_array(a); + dispose_array(new_a); +} + +#endif /* TEST_ARRAY */ +#endif /* ARRAY_VARS */ diff --git a/array.h b/array.h new file mode 100644 index 0000000..15e2a56 --- /dev/null +++ b/array.h @@ -0,0 +1,66 @@ +/* array.h -- definitions for the interface exported by array.c that allows + the rest of the shell to manipulate array variables. */ +#ifndef _ARRAY_H_ +#define _ARRAY_H_ + +#include "stdc.h" + +typedef int arrayind_t; + +enum atype {array_indexed, array_assoc}; + +typedef struct array { + enum atype type; + arrayind_t max_index, num_elements, max_size; + struct array_element *head; +} ARRAY; + +typedef struct array_element { + arrayind_t ind; + char *value; + struct array_element *next, *prev; +} ARRAY_ELEMENT; + +char *array_reference __P((ARRAY *, arrayind_t)); + +extern int array_add_element __P((ARRAY *, arrayind_t, char *)); +extern ARRAY_ELEMENT *array_delete_element __P((ARRAY *, arrayind_t)); + +extern ARRAY_ELEMENT *new_array_element __P((arrayind_t, char *)); +extern void destroy_array_element __P((ARRAY_ELEMENT *)); + +extern ARRAY *new_array __P((void)); +extern void empty_array __P((ARRAY *)); +extern void dispose_array __P((ARRAY *)); +extern ARRAY *dup_array __P((ARRAY *)); +extern ARRAY *dup_array_subrange __P((ARRAY *, ARRAY_ELEMENT *, ARRAY_ELEMENT *)); +extern ARRAY_ELEMENT *new_array_element __P((arrayind_t, char *)); +extern ARRAY_ELEMENT *copy_array_element __P((ARRAY_ELEMENT *)); + +extern WORD_LIST *array_to_word_list __P((ARRAY *)); +extern ARRAY *word_list_to_array __P((WORD_LIST *)); +extern ARRAY *assign_word_list __P((ARRAY *, WORD_LIST *)); + +extern char *array_to_assignment_string __P((ARRAY *)); +extern char *quoted_array_assignment_string __P((ARRAY *)); +extern char *array_to_string __P((ARRAY *, char *, int)); +extern ARRAY *string_to_array __P((char *, char *)); + +extern char *array_subrange __P((ARRAY *, int, int, int)); +extern char *array_pat_subst __P((ARRAY *, char *, char *, int)); + +extern ARRAY *array_quote __P((ARRAY *)); + +#define array_num_elements(a) ((a)->num_elements) +#define array_max_index(a) ((a)->max_index) +#define array_head(a) ((a)->head) +#define array_empty(a) ((a)->num_elements == 0) + +#define element_value(ae) ((ae)->value) +#define element_index(ae) ((ae)->ind) +#define element_forw(ae) ((ae)->next) +#define element_back(ae) ((ae)->prev) + +#define ALL_ELEMENT_SUB(c) ((c) == '@' || (c) == '*') + +#endif /* _ARRAY_H_ */ diff --git a/bashhist.c b/bashhist.c index cd7134b..102d4d8 100644 --- a/bashhist.c +++ b/bashhist.c @@ -18,7 +18,15 @@ with Bash; see the file COPYING. If not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include +#include "config.h" + +#if defined (HISTORY) + +#if defined (HAVE_UNISTD_H) +# include +#endif + +#include "bashtypes.h" #include #include #include "bashansi.h" @@ -26,7 +34,33 @@ #include "filecntl.h" #include "shell.h" #include "flags.h" +#include "input.h" +#include "parser.h" /* for the struct dstack stuff. */ +#include "pathexp.h" /* for the struct ignorevar stuff */ +#include "builtins/common.h" #include +#include + +#if defined (READLINE) +# include "bashline.h" +#endif + +#if !defined (errno) +extern int errno; +#endif + +static int histignore_item_func (); + +static struct ignorevar histignore = +{ + "HISTIGNORE", + (struct ign *)0, + 0, + (char *)0, + (Function *)histignore_item_func, +}; + +#define HIGN_EXPAND 0x01 /* Declarations of bash history variables. */ /* Non-zero means to remember lines typed to the shell on the history @@ -35,87 +69,145 @@ int remember_on_history = 1; /* The number of lines that Bash has added to this history session. */ -int history_lines_this_session = 0; +int history_lines_this_session; /* The number of lines that Bash has read from the history file. */ -int history_lines_in_file = 0; +int history_lines_in_file; +#if defined (BANG_HISTORY) /* Non-zero means do no history expansion on this line, regardless of what history_expansion says. */ -int history_expansion_inhibited = 0; +int history_expansion_inhibited; +#endif /* By default, every line is saved in the history individually. I.e., if the user enters: bash$ for i in a b c - > do - > echo $i - > done + > do + > echo $i + > done Each line will be individually saved in the history. bash$ history 10 for i in a b c - 11 do - 12 echo $i - 13 done - 14 history + 11 do + 12 echo $i + 13 done + 14 history If the variable command_oriented_history is set, multiple lines which form one command will be saved as one history entry. bash$ for i in a b c - > do - > echo $i - > done - bash$ history + > do + > echo $i + > done + bash$ history 10 for i in a b c do echo $i done - 11 history + 11 history The user can then recall the whole command all at once instead of just being able to recall one line at a time. */ -int command_oriented_history = 0; +int command_oriented_history = 1; + +/* Non-zero means to store newlines in the history list when using + command_oriented_history rather than trying to use semicolons. */ +int literal_history; + +/* Non-zero means to append the history to the history file at shell + exit, even if the history has been stifled. */ +int force_append_history; /* A nit for picking at history saving. Value of 0 means save all lines parsed by the shell on the history. Value of 1 means save all lines that do not start with a space. Value of 2 means save all lines that do not match the last line saved. */ -int history_control = 0; +int history_control; + +#if defined (READLINE) +/* If non-zero, and readline is being used, the user is offered the + chance to re-edit a failed history expansion. */ +int history_reediting; + +/* If non-zero, and readline is being used, don't directly execute a + line with history substitution. Reload it into the editing buffer + instead and let the user further edit and confirm with a newline. */ +int hist_verify; +#endif /* Variables declared in other files used here. */ extern int interactive; extern int current_command_line_count; -extern int delimiter_depth; +extern struct dstack dstack; + +extern char *extract_colon_unit (); extern char *history_delimiting_chars (); extern void maybe_add_history (); /* forward declaration */ static void bash_add_history (); +static int history_should_ignore (); + +void +bash_initialize_history () +{ + history_quotes_inhibit_expansion = 1; + history_search_delimiter_chars = ";&()|<>"; +} + +void +bash_history_reinit (interact) + int interact; +{ +#if defined (BANG_HISTORY) + history_expansion = interact != 0; + history_expansion_inhibited = 1; +#endif + remember_on_history = interact != 0; +} + +void +bash_history_disable () +{ + remember_on_history = 0; +#if defined (BANG_HISTORY) + history_expansion_inhibited = 1; +#endif +} + +void +bash_history_enable () +{ + remember_on_history = 1; +#if defined (BANG_HISTORY) + history_expansion_inhibited = 0; +#endif + sv_history_control ("HISTCONTROL"); + sv_histignore ("HISTIGNORE"); +} /* Load the history list from the history file. */ void load_history () { char *hf; + struct stat buf; /* Truncate history file for interactive shells which desire it. Note that the history file is automatically truncated to the size of HISTSIZE if the user does not explicitly set the size differently. */ set_if_not ("HISTFILESIZE", get_string_value ("HISTSIZE")); - stupidly_hack_special_variables ("HISTFILESIZE"); + sv_histsize ("HISTFILESIZE"); /* Read the history in HISTFILE into the history list. */ hf = get_string_value ("HISTFILE"); - if (hf && *hf) + if (hf && *hf && stat (hf, &buf) == 0) { - struct stat buf; - - if (stat (hf, &buf) == 0) - { - read_history (hf); - using_history (); - history_lines_in_file = where_history (); - } + read_history (hf); + using_history (); + history_lines_in_file = where_history (); } } @@ -123,24 +215,51 @@ load_history () void save_history () { - char *hf = get_string_value ("HISTFILE"); + char *hf; + struct stat buf; - if (hf && *hf) + hf = get_string_value ("HISTFILE"); + if (hf && *hf && stat (hf, &buf) == 0) { - struct stat buf; + /* Append only the lines that occurred this session to + the history file. */ + using_history (); - if (stat (hf, &buf) == 0) - { - /* Append only the lines that occurred this session to - the history file. */ - using_history (); + if (history_lines_this_session < where_history () || force_append_history) + append_history (history_lines_this_session, hf); + else + write_history (hf); - if (history_lines_this_session < where_history ()) - append_history (history_lines_this_session, hf); - else - write_history (hf); + sv_histsize ("HISTFILESIZE"); + } +} + +int +maybe_append_history (filename) + char *filename; +{ + int fd, result; + struct stat buf; + + result = EXECUTION_SUCCESS; + if (history_lines_this_session && (history_lines_this_session < where_history ())) + { + /* If the filename was supplied, then create it if necessary. */ + if (stat (filename, &buf) == -1 && errno == ENOENT) + { + fd = open (filename, O_WRONLY|O_CREAT, 0666); + if (fd < 0) + { + builtin_error ("%s: cannot create: %s", filename, strerror (errno)); + return (EXECUTION_FAILURE); + } + close (fd); } + result = append_history (history_lines_this_session, filename); + history_lines_in_file += history_lines_this_session; + history_lines_this_session = 0; } + return (result); } /* If this is an interactive shell, then append the lines executed @@ -148,20 +267,22 @@ save_history () int maybe_save_shell_history () { - int result = 0; + int result; + char *hf; + struct stat buf; + result = 0; if (history_lines_this_session) { - char *hf = get_string_value ("HISTFILE"); + hf = get_string_value ("HISTFILE"); if (hf && *hf) { - struct stat buf; - /* If the file doesn't exist, then create it. */ if (stat (hf, &buf) == -1) { - int file = open (hf, O_CREAT | O_TRUNC | O_WRONLY, 0666); + int file; + file = open (hf, O_CREAT | O_TRUNC | O_WRONLY, 0666); if (file != -1) close (file); } @@ -170,7 +291,7 @@ maybe_save_shell_history () stifled. If the history has been stifled, rewrite the history file. */ using_history (); - if (history_lines_this_session <= where_history ()) + if (history_lines_this_session <= where_history () || force_append_history) { result = append_history (history_lines_this_session, hf); history_lines_in_file += history_lines_this_session; @@ -181,23 +302,36 @@ maybe_save_shell_history () history_lines_in_file = history_lines_this_session; } history_lines_this_session = 0; + + sv_histsize ("HISTFILESIZE"); } } return (result); } -#if defined (HISTORY_REEDITING) +#if defined (READLINE) /* Tell readline () that we have some text for it to edit. */ static void re_edit (text) char *text; { -#if defined (READLINE) - if (strcmp (bash_input.name, "readline stdin") == 0) + if (bash_input.type == st_stdin) bash_re_edit (text); +} #endif /* READLINE */ + +/* Return 1 if this line needs history expansion. */ +static int +history_expansion_p (line) + char *line; +{ + register char *s; + + for (s = line; *s; s++) + if (*s == history_expansion_char || *s == history_subst_char) + return 1; + return 0; } -#endif /* HISTORY_REEDITING */ /* Do pre-processing on LINE. If PRINT_CHANGES is non-zero, then print the results of expanding the line if there were any changes. @@ -213,14 +347,15 @@ pre_process_line (line, print_changes, addit) { char *history_value; char *return_value; - int expanded = 0; + int expanded; return_value = line; + expanded = 0; # if defined (BANG_HISTORY) /* History expand the line. If this results in no errors, then add that line to the history if ADDIT is non-zero. */ - if (!history_expansion_inhibited && history_expansion) + if (!history_expansion_inhibited && history_expansion && history_expansion_p (line)) { expanded = history_expand (line, &history_value); @@ -230,7 +365,7 @@ pre_process_line (line, print_changes, addit) { if (expanded < 0) internal_error (history_value); - else + else if (hist_verify == 0) fprintf (stderr, "%s\n", history_value); } @@ -239,13 +374,22 @@ pre_process_line (line, print_changes, addit) { free (history_value); -# if defined (HISTORY_REEDITING) +# if defined (READLINE) /* New hack. We can allow the user to edit the failed history expansion. */ - re_edit (line); -# endif /* HISTORY_REEDITING */ + if (history_reediting && expanded < 0) + re_edit (line); +# endif /* READLINE */ + return ((char *)NULL); + } + +# if defined (READLINE) + if (hist_verify && expanded == 1) + { + re_edit (history_value); return ((char *)NULL); } +# endif } /* Let other expansions know that return_value can be free'ed, @@ -259,7 +403,7 @@ pre_process_line (line, print_changes, addit) if (addit && remember_on_history && *return_value) maybe_add_history (return_value); - if (!expanded) + if (expanded == 0) return_value = savestring (line); return (return_value); @@ -270,43 +414,46 @@ void maybe_add_history (line) char *line; { - int h; + int should_add; + HIST_ENTRY *temp; + + should_add = 0; /* Don't use the value of history_control to affect the second and subsequent lines of a multi-line command when command_oriented_history is enabled. */ if (command_oriented_history && current_command_line_count > 1) - h = 0; - else - h = history_control; + { + bash_add_history (line); + return; + } - switch (h) + switch (history_control) { case 0: - bash_add_history (line); + should_add = 1; break; case 1: if (*line != ' ') - bash_add_history (line); + should_add = 1; break; case 3: if (*line == ' ') - break; + break; /* FALLTHROUGH if case == 3 (`ignoreboth') */ case 2: - { - HIST_ENTRY *temp; - - using_history (); - temp = previous_history (); + using_history (); + temp = previous_history (); - if (!temp || (STREQ (temp->line, line) == 0)) - bash_add_history (line); + if (temp == 0 || STREQ (temp->line, line) == 0) + should_add = 1; - using_history (); - } + using_history (); break; } + + if (should_add && history_should_ignore (line) == 0) + bash_add_history (line); } /* Add a line to the history list. @@ -318,18 +465,16 @@ static void bash_add_history (line) char *line; { - int add_it = 1; + int add_it, offset, curlen; + HIST_ENTRY *current, *old; + char *chars_to_add, *new_line; + add_it = 1; if (command_oriented_history && current_command_line_count > 1) { - register int offset; - register HIST_ENTRY *current, *old; - char *chars_to_add, *new_line; - - chars_to_add = history_delimiting_chars (); + chars_to_add = literal_history ? "\n" : history_delimiting_chars (); using_history (); - current = previous_history (); if (current) @@ -337,11 +482,9 @@ bash_add_history (line) /* If the previous line ended with an escaped newline (escaped with backslash, but otherwise unquoted), then remove the quoted newline, since that is what happens when the line is parsed. */ - int curlen; - curlen = strlen (current->line); - if (!delimiter_depth && current->line[curlen - 1] == '\\' && + if (dstack.delimiter_depth == 0 && current->line[curlen - 1] == '\\' && current->line[curlen - 2] != '\\') { current->line[curlen - 1] = '\0'; @@ -349,22 +492,18 @@ bash_add_history (line) chars_to_add = ""; } - offset = where_history (); new_line = (char *) xmalloc (1 + curlen + strlen (line) + strlen (chars_to_add)); sprintf (new_line, "%s%s%s", current->line, chars_to_add, line); + offset = where_history (); old = replace_history_entry (offset, new_line, current->data); free (new_line); if (old) { - /* Note that the old data is not freed, since it was simply - copied to the new history entry. */ - if (old->line) - free (old->line); - + FREE (old->line); free (old); } add_it = 0; @@ -383,8 +522,144 @@ int history_number () { using_history (); - if (get_string_value ("HISTSIZE")) - return (history_base + where_history ()); - else - return (1); /* default to command number 1 */ + return (get_string_value ("HISTSIZE") ? history_base + where_history () : 1); +} + +static int +should_expand (s) + char *s; +{ + char *p; + + for (p = s; p && *p; p++) + { + if (*p == '\\') + p++; + else if (*p == '&') + return 1; + } + return 0; +} + +static int +histignore_item_func (ign) + struct ign *ign; +{ + if (should_expand (ign->val)) + ign->flags |= HIGN_EXPAND; + return (0); +} + +void +setup_history_ignore (varname) + char *varname; +{ + setup_ignore_patterns (&histignore); +} + +static HIST_ENTRY * +last_history_entry () +{ + HIST_ENTRY *he; + + using_history (); + he = previous_history (); + using_history (); + return he; +} + +char * +last_history_line () +{ + HIST_ENTRY *he; + + he = last_history_entry (); + if (he == 0) + return ((char *)NULL); + return he->line; +} + +static char * +expand_histignore_pattern (pat) + char *pat; +{ + HIST_ENTRY *phe; + char *ret, *p, *r, *t; + int len, rlen, ind, tlen; + + phe = last_history_entry (); + + if (phe == (HIST_ENTRY *)0) + return (savestring (pat)); + + len = strlen (phe->line); + rlen = len + strlen (pat) + 2; + ret = xmalloc (rlen); + + for (p = pat, r = ret; p && *p; ) + { + if (*p == '&') + { + ind = r - ret; + if (glob_pattern_p (phe->line) || strchr (phe->line, '\\')) + { + t = quote_globbing_chars (phe->line); + tlen = strlen (t); + RESIZE_MALLOCED_BUFFER (ret, ind, tlen, rlen, rlen); + r = ret + ind; /* in case reallocated */ + strcpy (r, t); + r += tlen; + free (t); + } + else + { + tlen = strlen (phe->line); + RESIZE_MALLOCED_BUFFER (ret, ind, tlen, rlen, rlen); + r = ret + ind; /* in case reallocated */ + strcpy (r, phe->line); + r += len; + } + p++; + continue; + } + + if (*p == '\\' && p[1] == '&') + p++; + + *r++ = *p++; + } + *r = '\0'; + return ret; +} + +/* Return 1 if we should not put LINE into the history according to the + patterns in HISTIGNORE. */ +static int +history_should_ignore (line) + char *line; +{ + register int i, match; + char *npat; + + if (histignore.num_ignores == 0) + return 0; + + for (i = match = 0; i < histignore.num_ignores; i++) + { + if (histignore.ignores[i].flags & HIGN_EXPAND) + npat = expand_histignore_pattern (histignore.ignores[i].val); + else + npat = histignore.ignores[i].val; + + match = fnmatch (npat, line, 0) != FNM_NOMATCH; + + if (histignore.ignores[i].flags & HIGN_EXPAND) + free (npat); + + if (match) + break; + } + + return match; } +#endif /* HISTORY */ diff --git a/bashhist.h b/bashhist.h index c1c24fc..409f531 100644 --- a/bashhist.h +++ b/bashhist.h @@ -18,8 +18,8 @@ with Bash; see the file COPYING. If not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ -#if !defined (__BASHHIST_H__) -#define __BASHHIST_H__ +#if !defined (_BASHHIST_H_) +#define _BASHHIST_H_ extern int remember_on_history; extern int history_lines_this_session; @@ -32,11 +32,20 @@ extern int command_oriented_history; extern int history_expansion_inhibited; # endif /* BANG_HISTORY */ +extern void bash_initialize_history (); +extern void bash_history_reinit (); +extern void bash_history_disable (); +extern void bash_history_enable (); extern void load_history (); extern void save_history (); +extern int maybe_append_history (); extern int maybe_save_shell_history (); extern char *pre_process_line (); extern int history_number (); extern void maybe_add_history (); -#endif /* __BASHHIST_H__ */ +extern void setup_history_ignore (); + +extern char *last_history_line (); + +#endif /* _BASHHIST_H_ */ diff --git a/bashintl.h b/bashintl.h new file mode 100644 index 0000000..50d0553 --- /dev/null +++ b/bashintl.h @@ -0,0 +1,49 @@ +/* bashintl.h -- Internationalization stuff + + Copyright (C) 1996 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, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#if !defined (_BASHINTL_H_) +#define _BASHINTL_H_ + +/* Include this *after* config.h */ +#if defined (HAVE_LIBINTL_H) +# include +#endif + +#if defined (HAVE_LOCALE_H) +# include +#endif + +#if defined (HAVE_SETLOCALE) && !defined (LC_ALL) +# undef HAVE_SETLOCALE +#endif + +#if !defined (HAVE_SETLOCALE) +# define setlocale(cat, loc) +#endif + +#if !defined (HAVE_TEXTDOMAIN) +# define textdomain(dom) +#endif + +#if !defined (HAVE_BINDTEXTDOMAIN) +# define bindtextdomain(dom, dir) +#endif + +#endif /* !_BASHINTL_H_ */ diff --git a/bashjmp.h b/bashjmp.h new file mode 100644 index 0000000..82dd41f --- /dev/null +++ b/bashjmp.h @@ -0,0 +1,35 @@ +/* bashjmp.h -- wrapper for setjmp.h with necessary bash definitions. */ + +#ifndef _BASHJMP_H_ +#define _BASHJMP_H_ + +#include + +/* This *must* be included *after* config.h */ + +#if defined (HAVE_POSIX_SIGSETJMP) +# define procenv_t sigjmp_buf +# undef setjmp +# define setjmp(x) sigsetjmp((x), 1) +# undef longjmp +# define longjmp(x, n) siglongjmp((x), (n)) +#else +# define procenv_t jmp_buf +#endif + +extern procenv_t top_level; +extern procenv_t subshell_top_level; +extern procenv_t return_catch; /* used by `return' builtin */ + +#define SHFUNC_RETURN() longjmp (return_catch, 1) + +#define COPY_PROCENV(old, save) \ + xbcopy ((char *)old, (char *)save, sizeof (procenv_t)); + +/* Values for the second argument to longjmp/siglongjmp. */ +#define NOT_JUMPED 0 /* Not returning from a longjmp. */ +#define FORCE_EOF 1 /* We want to stop parsing. */ +#define DISCARD 2 /* Discard current command. */ +#define EXITPROG 3 /* Unconditionally exit the program now. */ + +#endif /* _BASHJMP_H_ */ diff --git a/bashline.c b/bashline.c index a924b05..7d2e5d7 100644 --- a/bashline.c +++ b/bashline.c @@ -18,28 +18,36 @@ along with Bash; see the file COPYING. If not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include "config.h" + +#if defined (READLINE) + #include "bashtypes.h" #include "posixstat.h" +#if defined (HAVE_UNISTD_H) +# include +#endif + #include #include "bashansi.h" -#include -#include -#include #include "shell.h" #include "builtins.h" -#include "builtins/common.h" #include "bashhist.h" +#include "bashline.h" #include "execute_cmd.h" +#include "pathexp.h" +#include "builtins/common.h" +#include +#include +#include + +#include #if defined (ALIAS) # include "alias.h" #endif -#if defined (BRACE_EXPANSION) -# define BRACE_COMPLETION -#endif /* BRACE_EXPANSION */ - #if defined (BRACE_COMPLETION) extern void bash_brace_completion (); #endif /* BRACE_COMPLETION */ @@ -59,14 +67,20 @@ static char *variable_completion_function (); static char *hostname_completion_function (); static char *command_word_completion_function (); static char *command_subst_completion_function (); +static void dynamic_complete_history (); + +static char *glob_complete_word (); +static void bash_glob_expand_word (); +static void bash_glob_list_expansions (); static void snarf_hosts_from_file (), add_host_name (); -static void sort_hostname_list (); -#define DYNAMIC_HISTORY_COMPLETION -#if defined (DYNAMIC_HISTORY_COMPLETION) -static void dynamic_complete_history (); -#endif /* DYNAMIC_HISTORY_COMPLETION */ +static char *bash_dequote_filename (); +static char *bash_quote_filename (); + +#if defined (ALIAS) +static int posix_edit_macros (); +#endif /* Variables used here but defined in other files. */ extern int posixly_correct, no_symbolic_links; @@ -76,6 +90,10 @@ extern STRING_INT_ALIST word_token_alist[]; extern Function *rl_last_func; extern int rl_filename_completion_desired; +/* Helper functions from subst.c */ +extern int char_is_quoted (); +extern int unclosed_pair (); + /* SPECIFIC_COMPLETION_FUNCTIONS specifies that we have individual completion functions which indicate what type of completion should be done (at or before point) that can be bound to key sequences with @@ -83,48 +101,76 @@ extern int rl_filename_completion_desired; #define SPECIFIC_COMPLETION_FUNCTIONS #if defined (SPECIFIC_COMPLETION_FUNCTIONS) -static void - bash_specific_completion (), - bash_complete_filename (), bash_possible_filename_completions (), - bash_complete_filename_internal (), - bash_complete_username (), bash_possible_username_completions (), - bash_complete_username_internal (), - bash_complete_hostname (), bash_possible_hostname_completions (), - bash_complete_hostname_internal (), - bash_complete_variable (), bash_possible_variable_completions (), - bash_complete_variable_internal (), - bash_complete_command (), bash_possible_command_completions (), - bash_complete_command_internal (); +static void bash_specific_completion (); +static void bash_complete_filename (), bash_possible_filename_completions (); +static void bash_complete_filename_internal (); +static void bash_complete_username (), bash_possible_username_completions (); +static void bash_complete_username_internal (); +static void bash_complete_hostname (), bash_possible_hostname_completions (); +static void bash_complete_hostname_internal (); +static void bash_complete_variable (), bash_possible_variable_completions (); +static void bash_complete_variable_internal (); +static void bash_complete_command (), bash_possible_command_completions (); +static void bash_complete_command_internal (); #endif /* SPECIFIC_COMPLETION_FUNCTIONS */ -/* Non-zero once initalize_readline () has been called. */ -int bash_readline_initialized = 0; - #if defined (VI_MODE) static void vi_edit_and_execute_command (); -extern char *rl_vi_comment_begin; #endif +/* Non-zero once initalize_readline () has been called. */ +int bash_readline_initialized = 0; + +/* If non-zero, we do hostname completion, breaking words at `@' and + trying to complete the stuff after the `@' from our own internal + host list. */ +int perform_hostname_completion = 1; + +static char *bash_completer_word_break_characters = " \t\n\"'@><=;|&(:"; +static char *bash_nohostname_word_break_characters = " \t\n\"'><=;|&(:"; + static Function *old_rl_startup_hook = (Function *) NULL; +/* What kind of quoting is performed by bash_quote_filename: + COMPLETE_DQUOTE = double-quoting the filename + COMPLETE_SQUOTE = single_quoting the filename + COMPLETE_BSQUOTE = backslash-quoting special chars in the filename +*/ +#define COMPLETE_DQUOTE 1 +#define COMPLETE_SQUOTE 2 +#define COMPLETE_BSQUOTE 3 +static int completion_quoting_style = COMPLETE_BSQUOTE; + /* Change the readline VI-mode keymaps into or out of Posix.2 compliance. Called when the shell is put into or out of `posix' mode. */ void posix_readline_initialize (on_or_off) int on_or_off; { + if (on_or_off) + rl_variable_bind ("comment-begin", "#"); #if defined (VI_MODE) + rl_bind_key_in_map (CTRL('I'), on_or_off ? rl_insert : rl_complete, vi_insertion_keymap); +#endif +} + +void +enable_hostname_completion (on_or_off) + int on_or_off; +{ if (on_or_off) { - rl_bind_key_in_map (CTRL('I'), rl_insert, vi_insertion_keymap); - if (rl_vi_comment_begin) - free (rl_vi_comment_begin); - rl_vi_comment_begin = savestring ("#"); + perform_hostname_completion = 1; + rl_special_prefixes = "$@"; + rl_completer_word_break_characters = bash_completer_word_break_characters; } else - rl_bind_key_in_map (CTRL('I'), rl_complete, vi_insertion_keymap); -#endif -} + { + perform_hostname_completion = 0; + rl_special_prefixes = "$"; + rl_completer_word_break_characters = bash_nohostname_word_break_characters; + } +} /* Called once from parse.y if we are going to use readline. */ void @@ -136,15 +182,13 @@ initialize_readline () rl_terminal_name = get_string_value ("TERM"); rl_instream = stdin; rl_outstream = stderr; - rl_special_prefixes = "$@"; /* Allow conditional parsing of the ~/.inputrc file. */ rl_readline_name = "Bash"; /* Bind up our special shell functions. */ rl_add_defun ("shell-expand-line", (Function *)shell_expand_line, -1); - rl_bind_key_in_map - (CTRL('E'), (Function *)shell_expand_line, emacs_meta_keymap); + rl_bind_key_in_map (CTRL('E'), (Function *)shell_expand_line, emacs_meta_keymap); /* Bind up our special shell functions. */ rl_add_defun ("history-expand-line", (Function *)history_expand_line, -1); @@ -158,7 +202,6 @@ initialize_readline () rl_add_defun ("display-shell-version", (Function *)display_shell_version, -1); - rl_bind_key_in_map (CTRL ('V'), (Function *)display_shell_version, emacs_ctlx_keymap); @@ -170,7 +213,7 @@ initialize_readline () #if defined (VI_MODE) rl_unbind_key_in_map (CTRL('E'), vi_movement_keymap); #endif - + #if defined (BRACE_COMPLETION) rl_add_defun ("complete-into-braces", bash_brace_completion, -1); rl_bind_key_in_map ('{', bash_brace_completion, emacs_meta_keymap); @@ -181,43 +224,41 @@ initialize_readline () rl_bind_key_in_map ('/', bash_complete_filename, emacs_meta_keymap); rl_add_defun ("possible-filename-completions", bash_possible_filename_completions, -1); - rl_bind_key_in_map ('/', bash_possible_filename_completions, - emacs_ctlx_keymap); + rl_bind_key_in_map ('/', bash_possible_filename_completions, emacs_ctlx_keymap); rl_add_defun ("complete-username", bash_complete_username, -1); rl_bind_key_in_map ('~', bash_complete_username, emacs_meta_keymap); rl_add_defun ("possible-username-completions", bash_possible_username_completions, -1); - rl_bind_key_in_map ('~', bash_possible_username_completions, - emacs_ctlx_keymap); + rl_bind_key_in_map ('~', bash_possible_username_completions, emacs_ctlx_keymap); rl_add_defun ("complete-hostname", bash_complete_hostname, -1); rl_bind_key_in_map ('@', bash_complete_hostname, emacs_meta_keymap); rl_add_defun ("possible-hostname-completions", bash_possible_hostname_completions, -1); - rl_bind_key_in_map ('@', bash_possible_hostname_completions, - emacs_ctlx_keymap); + rl_bind_key_in_map ('@', bash_possible_hostname_completions, emacs_ctlx_keymap); rl_add_defun ("complete-variable", bash_complete_variable, -1); rl_bind_key_in_map ('$', bash_complete_variable, emacs_meta_keymap); rl_add_defun ("possible-variable-completions", bash_possible_variable_completions, -1); - rl_bind_key_in_map ('$', bash_possible_variable_completions, - emacs_ctlx_keymap); + rl_bind_key_in_map ('$', bash_possible_variable_completions, emacs_ctlx_keymap); rl_add_defun ("complete-command", bash_complete_command, -1); rl_bind_key_in_map ('!', bash_complete_command, emacs_meta_keymap); rl_add_defun ("possible-command-completions", bash_possible_command_completions, -1); - rl_bind_key_in_map ('!', bash_possible_command_completions, - emacs_ctlx_keymap); + rl_bind_key_in_map ('!', bash_possible_command_completions, emacs_ctlx_keymap); + + rl_add_defun ("glob-expand-word", bash_glob_expand_word, -1); + rl_add_defun ("glob-list-expansions", bash_glob_list_expansions, -1); + rl_bind_key_in_map ('*', bash_glob_expand_word, emacs_ctlx_keymap); + rl_bind_key_in_map ('g', bash_glob_list_expansions, emacs_ctlx_keymap); #endif /* SPECIFIC_COMPLETION_FUNCTIONS */ -#if defined (DYNAMIC_HISTORY_COMPLETION) rl_add_defun ("dynamic-complete-history", dynamic_complete_history, -1); rl_bind_key_in_map (TAB, dynamic_complete_history, emacs_meta_keymap); -#endif /* DYNAMIC_HISTORY_COMPLETION */ /* Tell the completer that we want a crack first. */ rl_attempted_completion_function = (CPPFunction *)attempt_shell_completion; @@ -231,12 +272,23 @@ initialize_readline () #if defined (VI_MODE) rl_bind_key_in_map ('v', vi_edit_and_execute_command, vi_movement_keymap); +# if defined (ALIAS) + rl_bind_key_in_map ('@', posix_edit_macros, vi_movement_keymap); +# endif #endif rl_completer_quote_characters = "'\""; - /* Need to modify this from the default; `$', `{', `\', and ``' are not - word break characters. */ - rl_completer_word_break_characters = " \t\n\"'@><=;|&("; /**/ + + /* This sets rl_completer_word_break_characters and rl_special_prefixes + to the appropriate values, depending on whether or not hostname + completion is enabled. */ + enable_hostname_completion (perform_hostname_completion); + + /* characters that need to be quoted when appearing in filenames. */ + rl_filename_quote_characters = " \t\n\\\"'@<>=;|&()#$`?*[!"; + rl_filename_quoting_function = bash_quote_filename; + rl_filename_dequoting_function = bash_dequote_filename; + rl_char_is_quoted_p = char_is_quoted; if (posixly_correct) posix_readline_initialize (1); @@ -282,8 +334,7 @@ int bash_re_edit (line) char *line; { - if (push_to_readline) - free (push_to_readline); + FREE (push_to_readline); push_to_readline = savestring (line); old_rl_startup_hook = rl_startup_hook; @@ -297,7 +348,7 @@ display_shell_version (count, c) int count, c; { crlf (); - show_shell_version (); + show_shell_version (0); putc ('\r', rl_outstream); fflush (rl_outstream); rl_on_new_line (); @@ -312,25 +363,19 @@ display_shell_version (count, c) /* If the user requests hostname completion, then simply build a list of hosts, and complete from that forever more. */ -#if !defined (ETCHOSTS) -#define ETCHOSTS "/etc/hosts" -#endif /* The kept list of hostnames. */ static char **hostname_list = (char **)NULL; /* The physical size of the above list. */ -static int hostname_list_size = 0; +static int hostname_list_size; -/* The length of the above list. */ -static int hostname_list_length = 0; +/* The number of hostnames in the above list. */ +static int hostname_list_length; /* Whether or not HOSTNAME_LIST has been initialized. */ int hostname_list_initialized = 0; -/* Non-zero means that HOSTNAME_LIST needs to be sorted. */ -static int hostname_list_needs_sorting = 0; - /* Initialize the hostname completion table. */ static void initialize_hostname_list () @@ -338,13 +383,12 @@ initialize_hostname_list () char *temp; temp = get_string_value ("HOSTFILE"); - if (!temp) + if (temp == 0) temp = get_string_value ("hostname_completion_file"); - if (!temp) - temp = ETCHOSTS; + if (temp == 0) + temp = DEFAULT_HOSTS_FILE; snarf_hosts_from_file (temp); - sort_hostname_list (); if (hostname_list) hostname_list_initialized++; @@ -355,25 +399,17 @@ static void add_host_name (name) char *name; { + long size; + if (hostname_list_length + 2 > hostname_list_size) { - hostname_list = (char **) - xrealloc (hostname_list, - (1 + (hostname_list_size += 100)) * sizeof (char *)); + hostname_list_size = (hostname_list_size + 32) - (hostname_list_size % 32); + size = hostname_list_size * sizeof (char *); + hostname_list = (char **)xrealloc (hostname_list, size); } - hostname_list[hostname_list_length] = savestring (name); - hostname_list[++hostname_list_length] = (char *)NULL; - hostname_list_needs_sorting++; -} - -/* After you have added some names, you should sort the list of names. */ -static void -sort_hostname_list () -{ - if (hostname_list_needs_sorting && hostname_list) - sort_char_array (hostname_list); - hostname_list_needs_sorting = 0; + hostname_list[hostname_list_length++] = savestring (name); + hostname_list[hostname_list_length] = (char *)NULL; } #define cr_whitespace(c) ((c) == '\r' || (c) == '\n' || whitespace(c)) @@ -382,55 +418,59 @@ static void snarf_hosts_from_file (filename) char *filename; { - FILE *file = fopen (filename, "r"); + FILE *file; char *temp, buffer[256], name[256]; register int i, start; - if (!file) + file = fopen (filename, "r"); + if (file == 0) return; while (temp = fgets (buffer, 255, file)) { /* Skip to first character. */ - for (i = 0; buffer[i] && cr_whitespace (buffer[i]); i++); + for (i = 0; buffer[i] && cr_whitespace (buffer[i]); i++) + ; - /* If comment, ignore. */ - if (buffer[i] == '#') + /* If comment or blank line, ignore. */ + if (buffer[i] == '\0' || buffer[i] == '#') continue; /* If `preprocessor' directive, do the include. */ - if (strncmp (&buffer[i], "$include ", 9) == 0) + if (strncmp (buffer + i, "$include ", 9) == 0) { - char *includefile = &buffer[i + 9]; - char *t; + char *incfile, *t; /* Find start of filename. */ - while (*includefile && whitespace (*includefile)) - includefile++; - - t = includefile; + for (incfile = buffer + i + 9; *incfile && whitespace (*incfile); incfile++) + ; /* Find end of filename. */ - while (*t && !cr_whitespace (*t)) - t++; + for (t = incfile; *t && cr_whitespace (*t) == 0; t++) + ; *t = '\0'; - snarf_hosts_from_file (includefile); + snarf_hosts_from_file (incfile); continue; } - /* Skip internet address. */ - for (; buffer[i] && !cr_whitespace (buffer[i]); i++); + /* Skip internet address if present. */ + if (digit (buffer[i])) + for (; buffer[i] && cr_whitespace (buffer[i]) == 0; i++); /* Gobble up names. Each name is separated with whitespace. */ - while (buffer[i] && buffer[i] != '#') + while (buffer[i]) { - for (; i && cr_whitespace (buffer[i]); i++); - if (buffer[i] == '#') - continue; - for (start = i; buffer[i] && !cr_whitespace (buffer[i]); i++); - if ((i - start) == 0) + for (; cr_whitespace (buffer[i]); i++) + ; + if (buffer[i] == '\0' || buffer[i] == '#') + break; + + /* Isolate the current word. */ + for (start = i; buffer[i] && cr_whitespace (buffer[i]) == 0; i++) + ; + if (i == start) continue; strncpy (name, buffer + start, i - start); name[i - start] = '\0'; @@ -447,28 +487,18 @@ static char ** hostnames_matching (text) char *text; { - register int i, len = strlen (text); - register int begin, end; - int last_search = -1; - char **result = (char **)NULL; + register int i, len, nmatch, rsize; + char **result; - if (!hostname_list_initialized) - { - initialize_hostname_list (); + if (hostname_list_initialized == 0) + initialize_hostname_list (); - if (!hostname_list_initialized) - return ((char **)NULL); - } - - sort_hostname_list (); - - /* The list is sorted. Do a binary search on it for the first character - in TEXT, and then grovel the names of interest. */ - begin = 0; end = hostname_list_length; + if (hostname_list_initialized == 0) + return ((char **)NULL); /* Special case. If TEXT consists of nothing, then the whole list is what is desired. */ - if (!*text) + if (*text == '\0') { result = (char **)xmalloc ((1 + hostname_list_length) * sizeof (char *)); for (i = 0; i < hostname_list_length; i++) @@ -478,54 +508,39 @@ hostnames_matching (text) } /* Scan until found, or failure. */ - while (end != begin) + len = strlen (text); + result = (char **)NULL; + for (i = nmatch = rsize = 0; i < hostname_list_length; i++) { - int r = 0; - - i = ((end - begin) / 2) + begin; - if (i == last_search) - break; + if (STREQN (text, hostname_list[i], len) == 0) + continue; - if (hostname_list[i] && - (r = strncmp (hostname_list[i], text, len)) == 0) + /* OK, it matches. Add it to the list. */ + if (nmatch >= rsize) { - while (strncmp (hostname_list[i], text, len) == 0 && i) i--; - if (strncmp (hostname_list[i], text, len) != 0) i++; - - begin = i; - while (hostname_list[i] && - strncmp (hostname_list[i], text, len) == 0) i++; - end = i; - - result = (char **)xmalloc ((1 + (end - begin)) * sizeof (char *)); - for (i = 0; i + begin < end; i++) - result[i] = hostname_list[begin + i]; - result[i] = (char *)NULL; - return (result); + rsize = (rsize + 16) - (rsize % 16); + result = (char **)xrealloc (result, rsize * sizeof (char *)); } - last_search = i; - - if (r < 0) - begin = i; - else - end = i; + result[nmatch++] = hostname_list[i]; } - return ((char **)NULL); + if (nmatch) + result[nmatch] = (char *)NULL; + return (result); } -/* The equivalent of the K*rn shell C-o operate-and-get-next-history-line +/* The equivalent of the Korn shell C-o operate-and-get-next-history-line editing command. */ -static int saved_history_line_to_use = 0; +static int saved_history_line_to_use = -1; static void set_saved_history () { - if (saved_history_line_to_use) + if (saved_history_line_to_use >= 0) rl_get_previous_history (history_length - saved_history_line_to_use); - saved_history_line_to_use = 0; + saved_history_line_to_use = -1; rl_startup_hook = old_rl_startup_hook; -} +} static void operate_and_get_next (count, c) @@ -534,7 +549,7 @@ operate_and_get_next (count, c) int where; /* Accept the current line. */ - rl_newline (); + rl_newline (); /* Find the current line, and find the next line to use. */ where = where_history (); @@ -558,11 +573,12 @@ operate_and_get_next (count, c) static void vi_edit_and_execute_command (count, c) + int count, c; { char *command; /* Accept the current line. */ - rl_newline (); + rl_newline (); if (rl_explicit_arg) { @@ -583,10 +599,33 @@ vi_edit_and_execute_command (count, c) command = savestring (VI_EDIT_COMMAND); } parse_and_execute (command, "v", -1); - rl_line_buffer[0] = '\0'; /* erase pre-edited command */ + rl_line_buffer[0] = '\0'; /* XXX */ } #endif /* VI_MODE */ +#if defined (ALIAS) +static int +posix_edit_macros (count, key) + int count, key; +{ + int c; + char alias_name[3], *alias_value, *macro; + + c = rl_read_key (); + alias_name[0] = '_'; + alias_name[1] = c; + alias_name[2] = '\0'; + + alias_value = get_alias_value (alias_name); + if (alias_value && *alias_value) + { + macro = savestring (alias_value); + rl_push_macro_input (macro); + } + return 0; +} +#endif + /* **************************************************************** */ /* */ /* How To Do Shell Completion */ @@ -601,11 +640,11 @@ attempt_shell_completion (text, start, end) int start, end; { int in_command_position, ti; - char **matches = (char **)NULL; - char *command_separator_chars = ";|&{(`"; + char **matches, *command_separator_chars; - rl_ignore_some_completions_function = - (Function *)filename_completion_ignore; + command_separator_chars = ";|&{(`"; + matches = (char **)NULL; + rl_ignore_some_completions_function = (Function *)filename_completion_ignore; /* Determine if this could be a command word. It is if it appears at the start of the line (ignoring preceding whitespace), or if it @@ -638,7 +677,8 @@ attempt_shell_completion (text, start, end) if ((this_char == '&' && (prev_char == '<' || prev_char == '>')) || (this_char == '|' && prev_char == '>')) in_command_position = 0; - else if (char_is_quoted (rl_line_buffer, ti)) + else if ((this_char == '{' && prev_char == '$') || + (char_is_quoted (rl_line_buffer, ti))) in_command_position = 0; } else @@ -648,8 +688,7 @@ attempt_shell_completion (text, start, end) assignments. */ } - /* Special handling for command substitution. XXX - this should handle - `$(' as well. */ + /* Special handling for command substitution. */ if (*text == '`' && unclosed_pair (rl_line_buffer, start, "`")) matches = completion_matches (text, command_subst_completion_function); @@ -664,7 +703,7 @@ attempt_shell_completion (text, start, end) /* Another one. Why not? If the word starts in '@', then look through the world of known hostnames for completion first. */ - if (!matches && *text == '@') + if (!matches && perform_hostname_completion && *text == '@') matches = completion_matches (text, hostname_completion_function); /* And last, (but not least) if this word is in a command position, then @@ -682,6 +721,11 @@ attempt_shell_completion (text, start, end) rl_ignore_some_completions_function = (Function *)bash_ignore_filenames; } + /* This could be a globbing pattern, so try to expand it using pathname + expansion. */ + if (!matches && glob_pattern_p (text)) + matches = completion_matches (text, glob_complete_word); + return (matches); } @@ -702,12 +746,11 @@ command_word_completion_function (hint_text, state) static int mapping_over, local_index; static SHELL_VAR **varlist = (SHELL_VAR **)NULL; #if defined (ALIAS) - static ASSOC **alias_list = (ASSOC **)NULL; + static alias_t **alias_list = (alias_t **)NULL; #endif /* ALIAS */ /* We have to map over the possibilities for command words. If we have no state, then make one just for that purpose. */ - if (!state) { if (hint) @@ -725,7 +768,7 @@ command_word_completion_function (hint_text, state) /* Perform tilde expansion on what's passed, so we don't end up passing filenames with tildes directly to stat(). */ if (*hint_text == '~') - hint = tilde_expand (hint_text); + hint = bash_tilde_expand (hint_text); else hint = savestring (hint_text); hint_len = strlen (hint); @@ -829,7 +872,7 @@ command_word_completion_function (hint_text, state) mapping_over++; } - /* Repeatedly call filename_completion_funcname)); + char *value = xmalloc (4 + strlen (var->name)); if (first_char_loc) - *value = first_char; + { + value[0] = first_char; + if (first_char_loc == 2) + value[1] = '{'; + } strcpy (&value[first_char_loc], var->name); + if (first_char_loc == 2) + strcat (value, "}"); varlist_index++; return (value); @@ -1058,10 +1110,9 @@ hostname_completion_function (text, state) static int first_char, first_char_loc; /* If we don't have any state, make some. */ - if (!state) + if (state == 0) { - if (list) - free (list); + FREE (list); list = (char **)NULL; @@ -1077,15 +1128,16 @@ hostname_completion_function (text, state) if (list && list[list_index]) { - char *t = xmalloc (2 + strlen (list[list_index])); + char *t; + t = xmalloc (2 + strlen (list[list_index])); *t = first_char; strcpy (t + first_char_loc, list[list_index]); list_index++; return (t); } - else - return ((char *)NULL); + + return ((char *)NULL); } /* History and alias expand the line. */ @@ -1183,7 +1235,7 @@ history_expand_line (ignore) else cleanup_expansion_error (); } - + /* History and alias expand the line. */ static void history_and_alias_expand_line (ignore) @@ -1217,6 +1269,7 @@ shell_expand_line (ignore) int ignore; { char *new_line; + WORD_LIST *expanded_string; new_line = pre_process_line (rl_line_buffer, 0, 0); @@ -1243,139 +1296,54 @@ shell_expand_line (ignore) /* If there is variable expansion to perform, do that as a separate operation to be undone. */ - { - WORD_LIST *expanded_string; - - expanded_string = expand_string (rl_line_buffer, 0); - if (!expanded_string) - new_line = savestring (""); - else - { - new_line = string_list (expanded_string); - dispose_words (expanded_string); - } + expanded_string = expand_string (rl_line_buffer, 0); + if (expanded_string == 0) + { + new_line = xmalloc (1); + new_line[0] = '\0'; + } + else + { + new_line = string_list (expanded_string); + dispose_words (expanded_string); + } - maybe_make_readline_line (new_line); - free (new_line); + maybe_make_readline_line (new_line); + free (new_line); - /* Place rl_point where we think it should go. */ - if (at_end) - rl_point = rl_end; - else if (old_point < rl_end) - { - rl_point = old_point; - if (!whitespace (rl_line_buffer[rl_point])) - rl_forward_word (1); - } - } + /* Place rl_point where we think it should go. */ + if (at_end) + rl_point = rl_end; + else if (old_point < rl_end) + { + rl_point = old_point; + if (!whitespace (rl_line_buffer[rl_point])) + rl_forward_word (1); + } } else cleanup_expansion_error (); } -/* Filename completion ignore. Emulates the "fignore" facility of - tcsh. If FIGNORE is set, then don't match files with the - given suffixes. If only one of the possibilities has an acceptable +/* If FIGNORE is set, then don't match files with the given suffixes when + completing filenames. If only one of the possibilities has an acceptable suffix, delete the others, else just return and let the completer signal an error. It is called by the completer when real completions are done on filenames by the completer's internal function, not for completion lists (M-?) and not on "other" - completion types, such as hostnames or commands. - - It is passed a NULL-terminated array of (char *)'s that must be - free()'d if they are deleted. The first element (names[0]) is the - least-common-denominator string of the matching patterns (i.e. - u produces names[0] = "und", names[1] = "under.c", names[2] = - "undun.c", name[3] = NULL). */ - -struct ign { - char *val; - int len; -}; + completion types, such as hostnames or commands. */ -static struct ign *ignores; /* Store the ignore strings here */ -static int num_ignores; /* How many are there? */ -static char *last_fignore; /* Last value of fignore - cached for speed */ - -static void -setup_ignore_patterns () +static struct ignorevar fignore = { - int numitems, maxitems, ptr; - char *colon_bit; - struct ign *p; - - char *this_fignore = get_string_value ("FIGNORE"); - - /* If nothing has changed then just exit now. */ - if ((this_fignore && - last_fignore && - strcmp (this_fignore, last_fignore) == 0) || - (!this_fignore && !last_fignore)) - { - return; - } - - /* Oops. FIGNORE has changed. Re-parse it. */ - num_ignores = 0; - - if (ignores) - { - for (p = ignores; p->val; p++) free(p->val); - free (ignores); - ignores = (struct ign*)NULL; - } - - if (last_fignore) - { - free (last_fignore); - last_fignore = (char *)NULL; - } - - if (!this_fignore || !*this_fignore) - return; - - last_fignore = savestring (this_fignore); - - numitems = maxitems = ptr = 0; - - while (colon_bit = extract_colon_unit (this_fignore, &ptr)) - { - if (numitems + 1 > maxitems) - ignores = (struct ign *) - xrealloc (ignores, (maxitems += 10) * sizeof (struct ign)); - - ignores[numitems].val = colon_bit; - ignores[numitems].len = strlen (colon_bit); - numitems++; - } - ignores[numitems].val = NULL; - num_ignores = numitems; -} - -static int -name_is_acceptable (name) - char *name; -{ - struct ign *p; - int nlen = strlen (name); - - for (p = ignores; p->val; p++) - { - if (nlen > p->len && p->len > 0 && - strcmp (p->val, &name[nlen - p->len]) == 0) - return (0); - } - - return (1); -} + "FIGNORE", + (struct ign *)0, + 0, + (char *)0, + (Function *) 0, +}; -/* Internal function to test whether filenames in NAMES should be - ignored. NAME_FUNC is a pointer to a function to call with each - name. It returns non-zero if the name is acceptable to the particular - ignore function which called _ignore_names; zero if the name should - be removed from NAMES. */ static void -_ignore_names (names, name_func) +_ignore_completion_names (names, name_func) char **names; Function *name_func; { @@ -1408,7 +1376,7 @@ _ignore_names (names, name_func) if ((*name_func) (names[idx])) newnames[nidx++] = names[idx]; else - free (names[idx]); + free (names[idx]); } newnames[nidx] = (char *)NULL; @@ -1431,24 +1399,41 @@ _ignore_names (names, name_func) free (newnames); return; } - + /* Copy the acceptable names back to NAMES, set the new array end, and return. */ for (nidx = 1; newnames[nidx]; nidx++) names[nidx] = newnames[nidx]; names[nidx] = (char *)NULL; + free (newnames); +} + +static int +name_is_acceptable (name) + char *name; +{ + struct ign *p; + int nlen; + + for (nlen = strlen (name), p = fignore.ignores; p->val; p++) + { + if (nlen > p->len && p->len > 0 && STREQ (p->val, &name[nlen - p->len])) + return (0); + } + + return (1); } static void filename_completion_ignore (names) char **names; { - setup_ignore_patterns (); + setup_ignore_patterns (&fignore); - if (num_ignores == 0) + if (fignore.num_ignores == 0) return; - _ignore_names (names, name_is_acceptable); + _ignore_completion_names (names, name_is_acceptable); } /* Return 1 if NAME is a directory. */ @@ -1459,7 +1444,7 @@ test_for_directory (name) struct stat finfo; char *fn; - fn = tilde_expand (name); + fn = bash_tilde_expand (name); if (stat (fn, &finfo) != 0) { free (fn); @@ -1474,7 +1459,7 @@ static void bash_ignore_filenames (names) char **names; { - _ignore_names (names, test_for_directory); + _ignore_completion_names (names, test_for_directory); } /* Handle symbolic link references and other directory name @@ -1504,7 +1489,8 @@ bash_directory_completion_hook (dirname) else { free (local_dirname); - *dirname = savestring (""); + *dirname = xmalloc (1); + **dirname = '\0'; return 1; } } @@ -1518,6 +1504,12 @@ bash_directory_completion_hook (dirname) temp1 = make_absolute (local_dirname, t); free (t); temp2 = canonicalize_pathname (temp1); + /* If we can't canonicalize, bail. */ + if (temp2 == 0) + { + free (temp1); + return 1; + } len1 = strlen (temp1); if (temp1[len1 - 1] == '/') { @@ -1533,15 +1525,16 @@ bash_directory_completion_hook (dirname) return (return_value); } -#if defined (DYNAMIC_HISTORY_COMPLETION) static char **history_completion_array = (char **)NULL; -static int harry_size = 0; -static int harry_len = 0; +static int harry_size; +static int harry_len; static void build_history_completion_array () { - register int i; + register int i, j; + HIST_ENTRY **hlist; + char **tokens; /* First, clear out the current dynamic history completion list. */ if (harry_size) @@ -1558,43 +1551,33 @@ build_history_completion_array () /* Next, grovel each line of history, making each shell-sized token a separate entry in the history_completion_array. */ - { - HIST_ENTRY **hlist; - - hlist = history_list (); - - if (hlist) - { - register int j; + hlist = history_list (); - for (i = 0; hlist[i]; i++) - { - char **tokens; - - /* Separate each token, and place into an array. */ - tokens = history_tokenize (hlist[i]->line); + if (hlist) + { + for (i = 0; hlist[i]; i++) + { + /* Separate each token, and place into an array. */ + tokens = history_tokenize (hlist[i]->line); - for (j = 0; tokens && tokens[j]; j++) - { - if (harry_len + 2 > harry_size) + for (j = 0; tokens && tokens[j]; j++) + { + if (harry_len + 2 > harry_size) + { + harry_size += 10; history_completion_array = (char **) xrealloc - (history_completion_array, - (harry_size += 10) * sizeof (char *)); - - history_completion_array[harry_len++] = tokens[j]; - history_completion_array[harry_len] = (char *)NULL; - } - free (tokens); - } + (history_completion_array, harry_size * sizeof (char *)); + } - /* Sort the complete list of tokens. */ - qsort (history_completion_array, harry_len, sizeof (char *), - (Function *)qsort_string_compare); + history_completion_array[harry_len++] = tokens[j]; + history_completion_array[harry_len] = (char *)NULL; + } + free (tokens); + } - /* Instead of removing the duplicate entries here, we let the - code in the completer handle it. */ - } - } + /* Sort the complete list of tokens. */ + qsort (history_completion_array, harry_len, sizeof (char *), (Function *)qsort_string_compare); + } } static char * @@ -1602,13 +1585,12 @@ history_completion_generator (hint_text, state) char *hint_text; int state; { - static int local_index = 0; - static char *text = (char *)NULL; - static int len = 0; + static int local_index, len; + static char *text; /* If this is the first call to the generator, then initialize the list of strings to complete over. */ - if (!state) + if (state == 0) { local_index = 0; build_history_completion_array (); @@ -1645,8 +1627,6 @@ dynamic_complete_history (count, key) rl_attempted_completion_function = orig_attempt_func; } -#endif /* DYNAMIC_HISTORY_COMPLETION */ - #if defined (SPECIFIC_COMPLETION_FUNCTIONS) static void bash_complete_username (ignore, ignore2) @@ -1775,6 +1755,51 @@ bash_complete_command_internal (what_to_do) (what_to_do, (Function *)command_word_completion_function); } +static char * +glob_complete_word (text, state) + char *text; + int state; +{ + static char **matches = (char **)NULL; + static int ind; + char *ret; + + if (state == 0) + { + if (matches) + free (matches); + matches = shell_glob_filename (text); + if (GLOB_FAILED (matches)) + matches = (char **)NULL; + ind = 0; + } + + ret = matches ? matches[ind] : (char *)NULL; + ind++; + return ret; +} + +static void +bash_glob_completion_internal (what_to_do) + int what_to_do; +{ + bash_specific_completion (what_to_do, (Function *)glob_complete_word); +} + +static void +bash_glob_expand_word (count, key) + int count, key; +{ + bash_glob_completion_internal ('*'); +} + +static void +bash_glob_list_expansions (count, key) + int count, key; +{ + bash_glob_completion_internal ('?'); +} + static void bash_specific_completion (what_to_do, generator) int what_to_do; @@ -1795,3 +1820,111 @@ bash_specific_completion (what_to_do, generator) } #endif /* SPECIFIC_COMPLETION_FUNCTIONS */ + +/* Filename quoting for completion. */ +/* A function to strip quotes that are not protected by backquotes. It + allows single quotes to appear within double quotes, and vice versa. + It should be smarter. */ +static char * +bash_dequote_filename (text, quote_char) + char *text; +{ + char *ret, *p, *r; + int l, quoted; + + l = strlen (text); + ret = xmalloc (l + 1); + for (quoted = quote_char, p = text, r = ret; p && *p; p++) + { + /* Allow backslash-quoted characters to pass through unscathed. */ + if (*p == '\\') + { + *r++ = *++p; + if (*p == '\0') + break; + continue; + } + /* Close quote. */ + if (quoted && *p == quoted) + { + quoted = 0; + continue; + } + /* Open quote. */ + if (quoted == 0 && (*p == '\'' || *p == '"')) + { + quoted = *p; + continue; + } + *r++ = *p; + } + *r = '\0'; + return ret; +} + +/* Quote a filename using double quotes. */ +static char * +bash_quote_filename (s, rtype, qcp) + char *s; + int rtype; + char *qcp; +{ + char *rtext, *mtext, *ret; + int rlen, cs; + + rtext = (char *)NULL; + + /* If RTYPE == MULT_MATCH, it means that there is + more than one match. In this case, we do not add + the closing quote or attempt to perform tilde + expansion. If RTYPE == SINGLE_MATCH, we try + to perform tilde expansion, because single and double + quotes inhibit tilde expansion by the shell. */ + + mtext = s; + if (mtext[0] == '~' && rtype == SINGLE_MATCH) + mtext = bash_tilde_expand (s); + + cs = completion_quoting_style; + /* Might need to modify the default completion style based on *qcp, + since it's set to any user-provided opening quote. */ + if (*qcp == '"') + cs = COMPLETE_DQUOTE; + else if (*qcp == '\'') + cs = COMPLETE_SQUOTE; +#if defined (BANG_HISTORY) + else if (*qcp == '\0' && history_expansion && cs == COMPLETE_DQUOTE && + history_expansion_inhibited == 0 && strchr (mtext, '!')) + cs = COMPLETE_BSQUOTE; +#endif + + switch (cs) + { + case COMPLETE_DQUOTE: + rtext = double_quote (mtext); + break; + case COMPLETE_SQUOTE: + rtext = single_quote (mtext); + break; + case COMPLETE_BSQUOTE: + rtext = backslash_quote (mtext); + break; + } + + if (mtext != s) + free (mtext); + + /* Leave the opening quote intact. The readline completion code takes + care of avoiding doubled opening quotes. */ + rlen = strlen (rtext); + ret = xmalloc (rlen + 1); + strcpy (ret, rtext); + + /* If there are multiple matches, cut off the closing quote. */ + if (rtype == MULT_MATCH && cs != COMPLETE_BSQUOTE) + ret[rlen - 1] = '\0'; + free (rtext); + return ret; +} + +#endif /* READLINE */ diff --git a/bashline.h b/bashline.h new file mode 100644 index 0000000..8e84a01 --- /dev/null +++ b/bashline.h @@ -0,0 +1,33 @@ +/* bashline.h -- interface to the bash readline functions in bashline.c. */ + +/* Copyright (C) 1993 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, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#if !defined (_BASHLINE_H_) +#define _BASHLINE_H_ + +#include "stdc.h" + +extern int bash_readline_initialized; + +extern void posix_readline_initialize __P((int)); +extern void initialize_readline __P((void)); +extern void bashline_reinitialize __P((void)); +extern int bash_re_edit __P((char *)); + +#endif /* _BASHLINE_H_ */ diff --git a/bashtty.h b/bashtty.h new file mode 100644 index 0000000..f2ceb25 --- /dev/null +++ b/bashtty.h @@ -0,0 +1,34 @@ +/* bashtty.h -- what kind of tty driver do we have? */ + +/* Copyright (C) 1993 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, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#if !defined (_BASHTTY_H_) +#define _BASHTTY_H_ + +#if defined (_POSIX_VERSION) && defined (HAVE_TERMIOS_H) && defined (HAVE_TCGETATTR) && !defined (TERMIOS_MISSING) +# define TERMIOS_TTY_DRIVER +#else +# if defined (HAVE_TERMIO_H) +# define TERMIO_TTY_DRIVER +# else +# define NEW_TTY_DRIVER +# endif +#endif + +#endif /* _BASHTTY_H */ diff --git a/bashtypes.h b/bashtypes.h index a725d61..540ff5b 100644 --- a/bashtypes.h +++ b/bashtypes.h @@ -18,8 +18,8 @@ with Bash; see the file COPYING. If not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ -#if !defined (__BASHTYPES_H) -# define __BASHTYPES_H +#if !defined (_BASHTYPES_H_) +# define _BASHTYPES_H_ #if defined (CRAY) # define word __word @@ -31,4 +31,4 @@ # undef word #endif -#endif /* __BASHTYPES_H */ +#endif /* _BASHTYPES_H_ */ diff --git a/bashwait.h b/bashwait.h new file mode 100644 index 0000000..97f62db --- /dev/null +++ b/bashwait.h @@ -0,0 +1,98 @@ +/* bashwait.h -- definitions for using a `union wait' on systems without + one. */ + +/* Copyright (C) 1996 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, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#ifndef _BASH_WAIT_H +#define _BASH_WAIT_H + +#if !defined (WORDS_BIGENDIAN) +union wait + { + int w_status; /* used in syscall */ + + /* Terminated process status. */ + struct + { + unsigned short + w_Termsig : 7, /* termination signal */ + w_Coredump : 1, /* core dump indicator */ + w_Retcode : 8, /* exit code if w_termsig==0 */ + w_Fill1 : 16; /* high 16 bits unused */ + } w_T; + + /* Stopped process status. Returned + only for traced children unless requested + with the WUNTRACED option bit. */ + struct + { + unsigned short + w_Stopval : 8, /* == W_STOPPED if stopped */ + w_Stopsig : 8, /* actually zero on XENIX */ + w_Fill2 : 16; /* high 16 bits unused */ + } w_S; + }; + +#else /* WORDS_BIGENDIAN */ + +/* This is for big-endian machines like the IBM RT, HP 9000, or Sun-3 */ + +union wait + { + int w_status; /* used in syscall */ + + /* Terminated process status. */ + struct + { + unsigned short w_Fill1 : 16; /* high 16 bits unused */ + unsigned w_Retcode : 8; /* exit code if w_termsig==0 */ + unsigned w_Coredump : 1; /* core dump indicator */ + unsigned w_Termsig : 7; /* termination signal */ + } w_T; + + /* Stopped process status. Returned + only for traced children unless requested + with the WUNTRACED option bit. */ + struct + { + unsigned short w_Fill2 : 16; /* high 16 bits unused */ + unsigned w_Stopsig : 8; /* signal that stopped us */ + unsigned w_Stopval : 8; /* == W_STOPPED if stopped */ + } w_S; + }; + +#endif /* WORDS_BIGENDIAN */ + +#define w_termsig w_T.w_Termsig +#define w_coredump w_T.w_Coredump +#define w_retcode w_T.w_Retcode +#define w_stopval w_S.w_Stopval +#define w_stopsig w_S.w_Stopsig + +#define WSTOPPED 0177 +#define WIFSTOPPED(x) ((x).w_stopval == WSTOPPED) +#define WIFEXITED(x) ((x).w_stopval != WSTOPPED && (x).w_termsig == 0) +#define WIFSIGNALED(x) ((x).w_stopval != WSTOPPED && (x).w_termsig != 0) + +#define WTERMSIG(x) ((x).w_termsig) +#define WSTOPSIG(x) ((x).w_stopsig) +#define WEXITSTATUS(x) ((x).w_retcode) +#define WIFCORED(x) ((x).w_coredump) + +#endif /* _BASH_WAIT_H */ diff --git a/bracecomp.c b/bracecomp.c index c07e15d..3edfcdc 100644 --- a/bracecomp.c +++ b/bracecomp.c @@ -22,8 +22,15 @@ with Bash; see the file COPYING. If not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include "config.h" +#if defined (BRACE_EXPANSION) && defined (READLINE) + #include +#if defined (HAVE_UNISTD_H) +# include +#endif + #if defined (HAVE_STRING_H) # include #else /* !HAVE_STRING_H */ @@ -71,7 +78,7 @@ really_munge_braces (array, real_start, real_end, gcd_zero) return (savestring (array[0])); } - result = (char *) xmalloc (result_size = 1); + result = xmalloc (result_size = 1); *result = '\0'; for (start = real_start; start < real_end; start = end + 1) @@ -95,7 +102,7 @@ really_munge_braces (array, real_start, real_end, gcd_zero) /* In this case, add in a leading '{', because we are at top level, and there isn't a consistent prefix. */ result_size += 1; - result = (char *) xrealloc (result, result_size); + result = xrealloc (result, result_size); strcpy (result, "{"); flag++; } @@ -107,7 +114,7 @@ really_munge_braces (array, real_start, real_end, gcd_zero) /* If there is more than one element in the subarray, insert the prefix and an opening brace. */ result_size += gcd - gcd_zero + 1; - result = (char *) xrealloc (result, result_size); + result = xrealloc (result, result_size); strncat (result, array[start] + gcd_zero, gcd - gcd_zero); strcat (result, "{"); subterm = really_munge_braces (array, start, end + 1, gcd); @@ -115,7 +122,7 @@ really_munge_braces (array, real_start, real_end, gcd_zero) } result_size += strlen (subterm) + 1; - result = (char *) xrealloc (result, result_size); + result = xrealloc (result, result_size); strcat (result, subterm); strcat (result, ","); free (subterm); @@ -164,3 +171,4 @@ bash_brace_completion () rl_attempted_completion_function = orig_attempt_func; rl_completion_entry_function = orig_entry_func; } +#endif /* BRACE_EXPANSION && READLINE */ diff --git a/braces.c b/braces.c index 2eb4de4..00952db 100644 --- a/braces.c +++ b/braces.c @@ -18,12 +18,15 @@ along with Bash; see the file COPYING. If not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ -/* Stuff in curly braces gets expanded after variable and command - substitution, but before filename globbing. +/* Stuff in curly braces gets expanded before all other shell expansions. */ - (Actually, this should be true for the sake of efficiency, but it - isn't because of quoting hacks. Once I rebuild quoting it will be - true. */ +#include "config.h" + +#if defined (BRACE_EXPANSION) + +#if defined (HAVE_UNISTD_H) +# include +#endif #if defined (HAVE_STRING_H) # include @@ -32,7 +35,7 @@ #endif /* !HAVE_STRING_H */ #if defined (SHELL) -#include "shell.h" +# include "shell.h" #endif /* SHELL */ #include "general.h" @@ -61,7 +64,7 @@ brace_expand (text) register int start; char *preamble, *postamble, *amble; char **tack, **result; - int i, c; + int i, j, c; /* Find the text of the preamble. */ i = 0; @@ -74,7 +77,7 @@ brace_expand (text) result = (char **)xmalloc (2 * sizeof (char *)); result[0] = preamble; result[1] = (char *)NULL; - + /* Special case. If we never found an exciting character, then the preamble is all of the text, so just return that. */ if (c != '{') @@ -85,11 +88,9 @@ brace_expand (text) c = brace_gobbler (text, &i, '}'); /* What if there isn't a matching close brace? */ - if (!c) + if (c == 0) { #if defined (NOTDEF) - register int j; - /* Well, if we found an unquoted BRACE_ARG_SEPARATOR between START and I, then this should be an error. Otherwise, it isn't. */ for (j = start; j < i; j++) @@ -103,7 +104,7 @@ brace_expand (text) if (text[j] == brace_arg_separator) { free_array (result); - report_error ("Missing `}'"); + report_error ("missing `}'"); throw_to_top_level (); } } @@ -120,28 +121,24 @@ brace_expand (text) #if defined (SHELL) /* If the amble does not contain an unquoted BRACE_ARG_SEPARATOR, then just return without doing any expansion. */ - { - register int j; - - for (j = 0; amble[j]; j++) - { - if (amble[j] == '\\') - { - j++; - continue; - } - if (amble[j] == brace_arg_separator) - break; - } - - if (!amble[j]) - { - free (amble); - free (preamble); - result[0] = savestring (text); - return (result); - } - } + for (j = 0; amble[j]; j++) + { + if (amble[j] == '\\') + { + j++; + continue; + } + if (amble[j] == brace_arg_separator) + break; + } + + if (!amble[j]) + { + free (amble); + free (preamble); + result[0] = savestring (text); + return (result); + } #endif /* SHELL */ postamble = &text[i + 1]; @@ -244,12 +241,12 @@ brace_gobbler (text, indx, satisfy) quoted = c; continue; } - - if (c == satisfy && !level && !quoted) + + if (c == satisfy && level == 0 && quoted == 0) { /* We ignore an open brace surrounded by whitespace, and also - an open brace followed immediately by a close brace, that - was preceded with whitespace. */ + an open brace followed immediately by a close brace preceded + by whitespace. */ if (c == '{' && ((!i || brace_whitespace (text[i - 1])) && (brace_whitespace (text[i + 1]) || text[i + 1] == '}'))) @@ -257,10 +254,8 @@ brace_gobbler (text, indx, satisfy) #if defined (SHELL) /* If this is being compiled as part of bash, ignore the `{' in a `${}' construct */ - if ((c != '{') || !i || (text[i - 1] != '$')) -#else /* !SHELL */ - if ((c != '{') || !i) -#endif /* !SHELL */ + if ((c != '{') || i == 0 || (text[i - 1] != '$')) +#endif /* SHELL */ break; } @@ -286,10 +281,10 @@ array_concat (arr1, arr2) register int i, j, len, len1, len2; register char **result; - if (!arr1) + if (arr1 == 0) return (copy_array (arr2)); - if (!arr2) + if (arr2 == 0) return (copy_array (arr1)); len1 = array_len (arr1); @@ -369,3 +364,4 @@ main () */ #endif /* TEST */ +#endif /* BRACE_EXPANSION */ diff --git a/builtins.h b/builtins.h index 6d4d8e8..cc4b700 100644 --- a/builtins.h +++ b/builtins.h @@ -19,6 +19,11 @@ Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "config.h" + +#if defined (HAVE_UNISTD_H) +# include +#endif + #include "command.h" #include "general.h" @@ -28,8 +33,10 @@ /* Flags describing various things about a builtin. */ #define BUILTIN_ENABLED 0x1 /* This builtin is enabled. */ -#define STATIC_BUILTIN 0x2 /* This builtin is not dynamically loaded. */ -#define SPECIAL_BUILTIN 0x4 /* This is a Posix `special' builtin. */ +#define BUILTIN_DELETED 0x2 /* This has been deleted with enable -d. */ +#define STATIC_BUILTIN 0x4 /* This builtin is not dynamically loaded. */ +#define SPECIAL_BUILTIN 0x8 /* This is a Posix `special' builtin. */ +#define ASSIGNMENT_BUILTIN 0x10 /* This builtin takes assignment statements. */ /* The thing that we build the array of builtins out of. */ struct builtin { @@ -38,8 +45,11 @@ struct builtin { int flags; /* One of the #defines above. */ char **long_doc; /* NULL terminated array of strings. */ char *short_doc; /* Short version of documenation. */ + char *handle; /* for future use */ }; /* Found in builtins.c, created by builtins/mkbuiltins. */ extern int num_shell_builtins; /* Number of shell builtins. */ -extern struct builtin shell_builtins[]; +extern struct builtin static_shell_builtins[]; +extern struct builtin *shell_builtins; +extern struct builtin *current_builtin; diff --git a/builtins/Makefile b/builtins/Makefile deleted file mode 100644 index 6472f7d..0000000 --- a/builtins/Makefile +++ /dev/null @@ -1,267 +0,0 @@ -# This Makefile for building libbuiltins.a is in -*- text -*- for Emacs. -# -MKBUILTINS = mkbuiltins -RANLIB = /usr/bin/ranlib -CFLAGS = -g -I.. -I. -SHELL = /bin/sh -# CC = cc -AR = ar -RM = rm -f -CP = cp - -srcdir = . -VPATH = .:$(srcdir) - -.SUFFIXES: -.SUFFIXES: .def .c .o -# How to make a .o file from a .def file. -.def.o: - $(RM) $@ - ./$(MKBUILTINS) $(DIRECTDEFINE) $< - $(CC) -c $(CFLAGS) $(CPPFLAGS) $*.c || ( $(RM) $*.c ; exit 1 ) - $(RM) $*.c - -# How to make a .c file from a .def file. -.def.c: - $(RM) $@ - ./$(MKBUILTINS) $(DIRECTDEFINE) $< - -# Here is a rule for making .o files from .c files that does not -# force the type of the machine (like -M_MACHINE) into the flags. -.c.o: - $(RM) $@ - $(CC) -c $(CFLAGS) $(CPPFLAGS) $< - -DEFS = $(srcdir)/alias.def $(srcdir)/bind.def $(srcdir)/break.def \ - $(srcdir)/builtin.def $(srcdir)/cd.def $(srcdir)/colon.def \ - $(srcdir)/command.def $(srcdir)/declare.def $(srcdir)/echo.def \ - $(srcdir)/enable.def $(srcdir)/eval.def $(srcdir)/getopts.def \ - $(srcdir)/exec.def $(srcdir)/exit.def $(srcdir)/fc.def \ - $(srcdir)/fg_bg.def $(srcdir)/hash.def $(srcdir)/help.def \ - $(srcdir)/history.def $(srcdir)/jobs.def $(srcdir)/kill.def \ - $(srcdir)/let.def $(srcdir)/read.def $(srcdir)/return.def \ - $(srcdir)/set.def $(srcdir)/setattr.def $(srcdir)/shift.def \ - $(srcdir)/source.def $(srcdir)/suspend.def $(srcdir)/test.def \ - $(srcdir)/times.def $(srcdir)/trap.def $(srcdir)/type.def \ - $(srcdir)/ulimit.def $(srcdir)/umask.def $(srcdir)/wait.def \ - $(srcdir)/reserved.def - -STATIC_SOURCE = common.c getopt.c bashgetopt.c getopt.h - -OFILES = builtins.o \ - alias.o bind.o break.o builtin.o cd.o colon.o command.o \ - common.o declare.o echo.o enable.o eval.o exec.o exit.o \ - fc.o fg_bg.o hash.o help.o history.o jobs.o kill.o \ - let.o read.o return.o set.o setattr.o shift.o source.o \ - suspend.o test.o times.o trap.o type.o ulimit.o umask.o \ - wait.o getopts.o getopt.o bashgetopt.o - -THINGS_TO_TAR = $(DEFS) $(STATIC_SOURCE) Makefile ChangeLog - -CREATED_FILES = builtext.h builtins.c psize.aux pipesize.h - -all: $(MKBUILTINS) libbuiltins.a - -libbuiltins.a: $(MKBUILTINS) $(OFILES) - $(RM) $@ - $(AR) cq $@ $(OFILES) - -$(RANLIB) $@ - -builtext.h builtins.c: $(MKBUILTINS) $(DEFS) - $(RM) builtext.h builtins.c - ./$(MKBUILTINS) -externfile builtext.h -structfile builtins.c \ - -noproduction $(DIRECTDEFINE) $(DEFS) - -mkbuiltins: $(srcdir)/mkbuiltins.c ../config.h - $(CC) $(CFLAGS) -o $(MKBUILTINS) $(srcdir)/mkbuiltins.c - -ulimit.o: ulimit.def pipesize.h - -pipesize.h: psize.aux - $(SHELL) $(srcdir)/psize.sh > pipesize.h - -psize.aux: psize.c - $(CC) $(CFLAGS) -o $@ $(srcdir)/psize.c - -documentation: builtins.texi - -$(OFILES): $(MKBUILTINS) ../config.h - -builtins.texi: $(MKBUILTINS) - ./$(MKBUILTINS) -documentonly $(DEFS) - -clean: - $(RM) $(OFILES) $(CREATED_FILES) $(MKBUILTINS) - -mostlyclean: - $(RM) $(OFILES) libbuiltins.a - -distclean realclean maintainer-clean: clean - $(RM) libbuiltins.a - -alias.o: alias.def -bind.o: bind.def -break.o: break.def -builtin.o: builtin.def -cd.o: cd.def -colon.o: colon.def -command.o: command.def -declare.o: declare.def -echo.o: echo.def -enable.o: enable.def -eval.o: eval.def -exec.o: exec.def -exit.o: exit.def -fc.o: fc.def -fg_bg.o: fg_bg.def -hash.o: hash.def -help.o: help.def -history.o: history.def -jobs.o: jobs.def -kill.o: kill.def -let.o: let.def -read.o: read.def -return.o: return.def -set.o: set.def -setattr.o: setattr.def -shift.o: shift.def -source.o: source.def -suspend.o: suspend.def -test.o: test.def -times.o: times.def -trap.o: trap.def -type.o: type.def -umask.o: umask.def -wait.o: wait.def -getopts.o: getopts.def -reserved.o: reserved.def - -common.o: ../shell.h ../command.h ../config.h ../memalloc.h ../general.h -common.o: ../variables.h ../input.h hashcom.h ../bashhist.h -common.o: ../quit.h ../unwind_prot.h ../maxpath.h ../jobs.h ../builtins.h -common.o: ../dispose_cmd.h ../make_cmd.h ../subst.h ../externs.h -common.o: ../execute_cmd.h ../error.h -alias.o: ../command.h ../config.h ../memalloc.h ../error.h ../general.h -alias.o: ../quit.h ../dispose_cmd.h ../make_cmd.h ../subst.h ../externs.h -alias.o: ../shell.h ../unwind_prot.h ../variables.h common.h ../maxpath.h -bind.o: ../command.h ../config.h ../memalloc.h ../error.h ../general.h -bind.o: ../quit.h ../dispose_cmd.h ../make_cmd.h ../subst.h ../externs.h -bind.o: ../maxpath.h -bind.o: ../shell.h ../unwind_prot.h ../variables.h bashgetopt.h -break.o: ../command.h ../config.h ../memalloc.h ../error.h ../general.h -break.o: ../quit.h ../dispose_cmd.h ../make_cmd.h ../subst.h ../externs.h -break.o: ../shell.h ../unwind_prot.h ../variables.h ../maxpath.h -builtin.o: ../command.h ../config.h ../memalloc.h ../error.h ../general.h -builtin.o: ../quit.h common.h ../maxpath.h -builtin.o: ../dispose_cmd.h ../make_cmd.h ../subst.h ../externs.h -builtin.o: ../shell.h ../unwind_prot.h ../variables.h -cd.o: ../command.h ../config.h ../memalloc.h ../error.h ../general.h -cd.o: ../quit.h ../dispose_cmd.h ../make_cmd.h ../subst.h ../externs.h -cd.o: ../shell.h ../unwind_prot.h ../variables.h common.h ../maxpath.h -command.o: ../command.h ../config.h ../memalloc.h ../error.h ../general.h -command.o: ../quit.h bashgetopt.h ../maxpath.h -command.o: ../dispose_cmd.h ../make_cmd.h ../subst.h ../externs.h -command.o: ../shell.h ../unwind_prot.h ../variables.h -declare.o: ../command.h ../config.h ../memalloc.h ../error.h ../general.h -declare.o: ../quit.h ../dispose_cmd.h ../make_cmd.h ../subst.h ../externs.h -declare.o: ../shell.h ../unwind_prot.h ../variables.h ../maxpath.h -echo.o: ../command.h ../config.h ../memalloc.h ../error.h ../general.h -echo.o: ../quit.h ../dispose_cmd.h ../make_cmd.h ../subst.h ../externs.h -echo.o: ../shell.h ../unwind_prot.h ../variables.h ../maxpath.h -enable.o: ../command.h ../config.h ../memalloc.h ../error.h ../general.h -enable.o: ../quit.h ../dispose_cmd.h ../make_cmd.h ../subst.h ../externs.h -enable.o: ../shell.h ../unwind_prot.h ../variables.h ../maxpath.h -eval.o: ../command.h ../config.h ../memalloc.h ../error.h ../general.h -eval.o: ../quit.h ../dispose_cmd.h ../make_cmd.h ../subst.h ../externs.h -eval.o: ../shell.h ../unwind_prot.h ../variables.h ../maxpath.h -exec.o: ../command.h ../config.h ../memalloc.h ../error.h ../general.h -exec.o: ../quit.h ../dispose_cmd.h ../make_cmd.h ../subst.h ../externs.h -exec.o: ../shell.h ../unwind_prot.h ../variables.h common.h ../execute_cmd.h -exec.o: ../maxpath.h ../flags.h -exit.o: ../command.h ../config.h ../memalloc.h ../error.h ../general.h -exit.o: ../quit.h ../dispose_cmd.h ../make_cmd.h ../subst.h ../externs.h -exit.o: ../shell.h ../unwind_prot.h ../variables.h ../maxpath.h -fc.o: ../builtins.h ../command.h bashgetopt.h ../bashhist.h -fc.o: ../command.h ../config.h ../memalloc.h ../error.h ../general.h -fc.o: ../quit.h ../dispose_cmd.h ../make_cmd.h ../subst.h ../externs.h -fc.o: ../flags.h ../unwind_prot.h ../variables.h ../shell.h ../maxpath.h -fg_bg.o: ../command.h ../config.h ../memalloc.h ../error.h ../general.h -fg_bg.o: ../quit.h ../dispose_cmd.h ../make_cmd.h ../subst.h ../externs.h -fg_bg.o: ../shell.h ../unwind_prot.h ../variables.h ../maxpath.h -getopts.o: ../command.h ../config.h ../memalloc.h ../error.h ../general.h -getopts.o: ../quit.h ../dispose_cmd.h ../make_cmd.h ../subst.h ../externs.h -getopts.o: ../shell.h ../unwind_prot.h ../variables.h ../maxpath.h -hash.o: ../builtins.h ../command.h ../quit.h ../execute_cmd.h -hash.o: ../command.h ../config.h ../memalloc.h ../error.h ../general.h -hash.o: ../shell.h ../unwind_prot.h ../variables.h common.h ../maxpath.h -help.o: ../command.h ../config.h ../memalloc.h ../error.h ../general.h -help.o: ../quit.h ../dispose_cmd.h ../make_cmd.h ../subst.h ../externs.h -help.o: ../shell.h ../unwind_prot.h ../variables.h ../maxpath.h -history.o: ../command.h ../config.h ../memalloc.h ../error.h ../general.h -history.o: ../quit.h ../dispose_cmd.h ../make_cmd.h ../subst.h ../externs.h -history.o: ../filecntl.h ../shell.h ../unwind_prot.h ../variables.h -history.o: ../bashhist.h ../maxpath.h -inlib.o: ../command.h ../config.h ../memalloc.h ../error.h ../general.h -inlib.o: ../shell.h ../unwind_prot.h ../variables.h ../maxpath.h -inlib.o: ../quit.h ../dispose_cmd.h ../make_cmd.h ../subst.h ../externs.h -jobs.o: ../command.h ../config.h ../memalloc.h ../error.h ../general.h -jobs.o: ../quit.h bashgetopt.h ../maxpath.h -jobs.o: ../dispose_cmd.h ../make_cmd.h ../subst.h ../externs.h -jobs.o: ../shell.h ../unwind_prot.h ../variables.h -kill.o: ../command.h ../config.h ../memalloc.h ../error.h ../general.h -kill.o: ../quit.h ../dispose_cmd.h ../make_cmd.h ../subst.h ../externs.h -kill.o: ../shell.h ../trap.h ../unwind_prot.h ../variables.h ../maxpath.h -let.o: ../command.h ../config.h ../memalloc.h ../error.h ../general.h -let.o: ../quit.h ../dispose_cmd.h ../make_cmd.h ../subst.h ../externs.h -let.o: ../shell.h ../unwind_prot.h ../variables.h ../maxpath.h -read.o: ../command.h ../config.h ../memalloc.h ../error.h ../general.h -read.o: ../quit.h ../dispose_cmd.h ../make_cmd.h ../subst.h ../externs.h -read.o: ../shell.h ../unwind_prot.h ../variables.h ../maxpath.h -return.o: ../command.h ../config.h ../memalloc.h ../error.h ../general.h -return.o: ../quit.h ../dispose_cmd.h ../make_cmd.h ../subst.h ../externs.h -return.o: ../shell.h ../unwind_prot.h ../variables.h ../maxpath.h -set.o: ../command.h ../config.h ../memalloc.h ../error.h ../general.h -set.o: ../quit.h ../dispose_cmd.h ../make_cmd.h ../subst.h ../externs.h -set.o: ../shell.h ../unwind_prot.h ../variables.h ../maxpath.h -setattr.o: ../command.h ../config.h ../memalloc.h ../error.h ../general.h -setattr.o: ../quit.h common.h bashgetopt.h ../maxpath.h -setattr.o: ../dispose_cmd.h ../make_cmd.h ../subst.h ../externs.h -setattr.o: ../shell.h ../unwind_prot.h ../variables.h -shift.o: ../command.h ../config.h ../memalloc.h ../error.h ../general.h -shift.o: ../quit.h ../dispose_cmd.h ../make_cmd.h ../subst.h ../externs.h -shift.o: ../shell.h ../unwind_prot.h ../variables.h ../maxpath.h -source.o: ../command.h ../config.h ../memalloc.h ../error.h ../general.h -source.o: ../quit.h ../dispose_cmd.h ../make_cmd.h ../subst.h ../externs.h -source.o: ../shell.h ../unwind_prot.h ../variables.h ../maxpath.h -suspend.o: ../command.h ../config.h ../memalloc.h ../error.h ../general.h -suspend.o: ../quit.h ../dispose_cmd.h ../make_cmd.h ../subst.h ../externs.h -suspend.o: ../shell.h ../unwind_prot.h ../variables.h ../maxpath.h -test.o: ../command.h ../config.h ../memalloc.h ../error.h ../general.h -test.o: ../quit.h ../dispose_cmd.h ../make_cmd.h ../subst.h ../externs.h -test.o: ../shell.h ../unwind_prot.h ../variables.h ../maxpath.h -times.o: ../command.h ../config.h ../memalloc.h ../error.h ../general.h -times.o: ../quit.h ../dispose_cmd.h ../make_cmd.h ../subst.h ../externs.h -times.o: ../shell.h ../unwind_prot.h ../variables.h ../maxpath.h -trap.o: ../command.h ../config.h ../memalloc.h ../error.h ../general.h -trap.o: ../quit.h common.h ../maxpath.h -trap.o: ../dispose_cmd.h ../make_cmd.h ../subst.h ../externs.h -trap.o: ../shell.h ../unwind_prot.h ../variables.h ../execute_cmd.h -type.o: ../command.h ../config.h ../memalloc.h ../error.h ../general.h -type.o: ../quit.h common.h ../maxpath.h -type.o: ../dispose_cmd.h ../make_cmd.h ../subst.h ../externs.h -type.o: ../shell.h ../unwind_prot.h ../variables.h -ulimit.o: ../command.h ../config.h ../memalloc.h ../error.h ../general.h -ulimit.o: ../quit.h ../dispose_cmd.h ../make_cmd.h ../subst.h ../externs.h -ulimit.o: ../shell.h ../unwind_prot.h ../variables.h ../maxpath.h -umask.o: ../command.h ../config.h ../memalloc.h ../error.h ../general.h -umask.o: ../quit.h ../dispose_cmd.h ../make_cmd.h ../subst.h ../externs.h -umask.o: ../shell.h ../unwind_prot.h ../variables.h ../maxpath.h -wait.o: ../command.h ../config.h ../memalloc.h ../error.h ../general.h -wait.o: ../quit.h ../dispose_cmd.h ../make_cmd.h ../subst.h ../externs.h -wait.o: ../shell.h ../unwind_prot.h ../variables.h ../maxpath.h - -bashgetopt.o: ../bashansi.h ../ansi_stdlib.h -mkbuiltins.o: ../bashansi.h ../ansi_stdlib.h -fc.o: ../bashansi.h ../ansi_stdlib.h - -#bind.o: $(RL_LIBSRC)chardefs.h $(RL_LIBSRC)readline.h $(RL_LIBSRC)keymaps.h diff --git a/builtins/Makefile.in b/builtins/Makefile.in new file mode 100644 index 0000000..f38917b --- /dev/null +++ b/builtins/Makefile.in @@ -0,0 +1,375 @@ +# This Makefile for building libbuiltins.a is in -*- text -*- for Emacs. +# +MKBUILTINS = mkbuiltins +RANLIB = @RANLIB@ +CFLAGS = @CFLAGS@ +LOCAL_CFLAGS = @LOCAL_CFLAGS@ +CPPFLAGS = @CPPFLAGS@ +SHELL = /bin/sh +CC = @CC@ +AR = @AR@ +RM = rm -f +CP = cp + +LIBS = @LIBS@ + +srcdir = @srcdir@ +VPATH = .:@srcdir@ +topdir = @top_srcdir@ +includedir = @includedir@ + +DEFS = @DEFS@ + +INCLUDES = -I. -I.. -I$(topdir) -I$(topdir)/lib -I$(srcdir) + +CCFLAGS = $(DEFS) $(SYSTEM_FLAGS) $(CPPFLAGS) ${INCLUDES} $(LOCAL_CFLAGS) $(CFLAGS) + +DIRECTDEFINE = -D $(srcdir) + +# xxx this is bad style +RL_LIBSRC = $(topdir)/lib/readline + +.SUFFIXES: +.SUFFIXES: .def .c .o +# How to make a .o file from a .def file. +.def.o: + $(RM) $@ + ./$(MKBUILTINS) $(DIRECTDEFINE) $< + $(CC) -c $(CCFLAGS) $*.c || ( $(RM) $*.c ; exit 1 ) + $(RM) $*.c + +# How to make a .c file from a .def file. +.def.c: + $(RM) $@ + ./$(MKBUILTINS) $(DIRECTDEFINE) $< + +# default rule for making a .o file from a .c file +.c.o: + $(RM) $@ + $(CC) -c $(CCFLAGS) $< + +DEFSRC = $(srcdir)/alias.def $(srcdir)/bind.def $(srcdir)/break.def \ + $(srcdir)/builtin.def $(srcdir)/cd.def $(srcdir)/colon.def \ + $(srcdir)/command.def $(srcdir)/declare.def $(srcdir)/echo.def \ + $(srcdir)/enable.def $(srcdir)/eval.def $(srcdir)/getopts.def \ + $(srcdir)/exec.def $(srcdir)/exit.def $(srcdir)/fc.def \ + $(srcdir)/fg_bg.def $(srcdir)/hash.def $(srcdir)/help.def \ + $(srcdir)/history.def $(srcdir)/jobs.def $(srcdir)/kill.def \ + $(srcdir)/let.def $(srcdir)/read.def $(srcdir)/return.def \ + $(srcdir)/set.def $(srcdir)/setattr.def $(srcdir)/shift.def \ + $(srcdir)/source.def $(srcdir)/suspend.def $(srcdir)/test.def \ + $(srcdir)/times.def $(srcdir)/trap.def $(srcdir)/type.def \ + $(srcdir)/ulimit.def $(srcdir)/umask.def $(srcdir)/wait.def \ + $(srcdir)/reserved.def $(srcdir)/pushd.def $(srcdir)/shopt.def + +STATIC_SOURCE = common.c evalstring.c evalfile.c getopt.c bashgetopt.c \ + getopt.h + +OFILES = builtins.o \ + alias.o bind.o break.o builtin.o cd.o colon.o command.o \ + common.o declare.o echo.o enable.o eval.o evalfile.o \ + evalstring.o exec.o \ + exit.o fc.o fg_bg.o hash.o help.o history.o jobs.o kill.o let.o \ + pushd.o read.o return.o set.o setattr.o shift.o source.o \ + suspend.o test.o times.o trap.o type.o ulimit.o umask.o \ + wait.o getopts.o shopt.o getopt.o bashgetopt.o + +CREATED_FILES = builtext.h builtins.c psize.aux pipesize.h + +all: $(MKBUILTINS) libbuiltins.a + +libbuiltins.a: $(MKBUILTINS) $(OFILES) + $(RM) $@ + $(AR) cr $@ $(OFILES) + -$(RANLIB) $@ + +builtext.h builtins.c: $(MKBUILTINS) $(DEFSRC) + $(RM) builtext.h builtins.c + ./$(MKBUILTINS) -externfile builtext.h -structfile builtins.c \ + -noproduction $(DIRECTDEFINE) $(DEFSRC) + +mkbuiltins: $(srcdir)/mkbuiltins.c ../config.h + $(CC) $(CCFLAGS) -o $(MKBUILTINS) $(srcdir)/mkbuiltins.c $(LIBS) + +# rules for deficient makes, like SunOS +common.o: common.c +bashgetopt.o: bashgetopt.c +getopt.o: getopt.c + +ulimit.o: ulimit.def pipesize.h + +pipesize.h: psize.aux + $(SHELL) $(srcdir)/psize.sh > pipesize.h + +psize.aux: psize.c + $(CC) $(CCFLAGS) -o $@ $(srcdir)/psize.c + +documentation: builtins.texi + +$(OFILES): $(MKBUILTINS) ../config.h + +builtins.texi: $(MKBUILTINS) + ./$(MKBUILTINS) -documentonly $(DEFSRC) + +clean: + $(RM) $(OFILES) $(CREATED_FILES) $(MKBUILTINS) libbuiltins.a + +mostlyclean: + $(RM) $(OFILES) libbuiltins.a + +distclean maintainer-clean: clean + $(RM) Makefile + +alias.o: alias.def +bind.o: bind.def +break.o: break.def +builtin.o: builtin.def +cd.o: cd.def +colon.o: colon.def +command.o: command.def +declare.o: declare.def +echo.o: echo.def +enable.o: enable.def +eval.o: eval.def +exec.o: exec.def +exit.o: exit.def +fc.o: fc.def +fg_bg.o: fg_bg.def +hash.o: hash.def +help.o: help.def +history.o: history.def +jobs.o: jobs.def +kill.o: kill.def +let.o: let.def +pushd.o: pushd.def +read.o: read.def +return.o: return.def +set.o: set.def +setattr.o: setattr.def +shift.o: shift.def +source.o: source.def +suspend.o: suspend.def +test.o: test.def +times.o: times.def +trap.o: trap.def +type.o: type.def +umask.o: umask.def +wait.o: wait.def +getopts.o: getopts.def +reserved.o: reserved.def + +common.o: $(topdir)/shell.h $(topdir)/command.h ../config.h +common.o: $(topdir)/memalloc.h $(topdir)/general.h +common.o: $(topdir)/variables.h $(topdir)/input.h $(srcdir)/hashcom.h +common.o: $(topdir)/bashhist.h $(topdir)/quit.h $(topdir)/unwind_prot.h +common.o: $(topdir)/maxpath.h $(topdir)/jobs.h $(topdir)/builtins.h +common.o: $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h $(topdir)/subst.h +common.o: $(topdir)/execute_cmd.h $(topdir)/error.h $(topdir)/externs.h +alias.o: $(topdir)/command.h ../config.h $(topdir)/memalloc.h +alias.o: $(topdir)/error.h $(topdir)/general.h $(topdir)/maxpath.h +alias.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h +alias.o: $(topdir)/subst.h $(topdir)/externs.h $(srcdir)/common.h +alias.o: $(topdir)/shell.h $(topdir)/unwind_prot.h $(topdir)/variables.h +bind.o: $(topdir)/command.h ../config.h $(topdir)/memalloc.h $(topdir)/error.h +bind.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h +bind.o: $(topdir)/subst.h $(topdir)/externs.h $(srcdir)/bashgetopt.h +bind.o: $(topdir)/general.h $(topdir)/maxpath.h $(topdir)/bashline.h +bind.o: $(topdir)/shell.h $(topdir)/unwind_prot.h $(topdir)/variables.h +break.o: $(topdir)/command.h ../config.h $(topdir)/memalloc.h +break.o: $(topdir)/error.h $(topdir)/general.h +break.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h +break.o: $(topdir)/subst.h $(topdir)/externs.h $(topdir)/maxpath.h +break.o: $(topdir)/shell.h $(topdir)/unwind_prot.h $(topdir)/variables.h +builtin.o: $(topdir)/command.h ../config.h $(topdir)/memalloc.h +builtin.o: $(topdir)/error.h $(topdir)/general.h $(topdir)/externs.h +builtin.o: $(topdir)/quit.h $(srcdir)/common.h $(topdir)/maxpath.h +builtin.o: $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h $(topdir)/subst.h +builtin.o: $(topdir)/shell.h $(topdir)/unwind_prot.h $(topdir)/variables.h +cd.o: $(topdir)/command.h ../config.h $(topdir)/memalloc.h $(topdir)/error.h +cd.o: $(topdir)/general.h $(topdir)/quit.h $(topdir)/dispose_cmd.h +cd.o: $(topdir)/make_cmd.h $(topdir)/subst.h $(topdir)/externs.h +cd.o: $(topdir)/shell.h $(topdir)/unwind_prot.h $(topdir)/variables.h +cd.o: $(srcdir)/common.h $(topdir)/maxpath.h +command.o: $(topdir)/command.h ../config.h $(topdir)/memalloc.h +command.o: $(topdir)/error.h $(topdir)/general.h $(topdir)/externs.h +command.o: $(topdir)/quit.h $(srcdir)/bashgetopt.h $(topdir)/maxpath.h +command.o: $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h $(topdir)/subst.h +command.o: $(topdir)/shell.h $(topdir)/unwind_prot.h $(topdir)/variables.h +declare.o: $(topdir)/command.h ../config.h $(topdir)/memalloc.h +declare.o: $(topdir)/error.h $(topdir)/general.h +declare.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h +declare.o: $(topdir)/subst.h $(topdir)/externs.h $(topdir)/maxpath.h +declare.o: $(topdir)/shell.h $(topdir)/unwind_prot.h $(topdir)/variables.h +echo.o: $(topdir)/command.h ../config.h $(topdir)/memalloc.h $(topdir)/error.h +echo.o: $(topdir)/general.h $(topdir)/subst.h $(topdir)/externs.h +echo.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h +echo.o: $(topdir)/shell.h $(topdir)/unwind_prot.h $(topdir)/variables.h +echo.o: $(topdir)/maxpath.h +enable.o: $(topdir)/command.h ../config.h $(topdir)/memalloc.h +enable.o: $(topdir)/error.h $(topdir)/general.h +enable.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h +enable.o: $(topdir)/subst.h $(topdir)/externs.h +enable.o: $(topdir)/shell.h $(topdir)/unwind_prot.h $(topdir)/variables.h +enable.o: $(topdir)/maxpath.h +eval.o: $(topdir)/command.h ../config.h $(topdir)/memalloc.h +eval.o: $(topdir)/error.h $(topdir)/general.h +eval.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h +eval.o: $(topdir)/subst.h $(topdir)/externs.h +eval.o: $(topdir)/shell.h $(topdir)/unwind_prot.h $(topdir)/variables.h +eval.o: $(topdir)/maxpath.h +exec.o: $(topdir)/command.h ../config.h $(topdir)/memalloc.h +exec.o: $(topdir)/error.h $(topdir)/general.h +exec.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h +exec.o: $(topdir)/subst.h $(topdir)/externs.h $(topdir)/flags.h +exec.o: $(topdir)/shell.h $(topdir)/unwind_prot.h $(topdir)/variables.h +exec.o: $(srcdir)/common.h $(topdir)/execute_cmd.h $(topdir)/maxpath.h +exit.o: $(topdir)/command.h ../config.h $(topdir)/memalloc.h +exit.o: $(topdir)/error.h $(topdir)/general.h +exit.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h +exit.o: $(topdir)/subst.h $(topdir)/externs.h +exit.o: $(topdir)/shell.h $(topdir)/unwind_prot.h $(topdir)/variables.h +exit.o: $(topdir)/maxpath.h +fc.o: $(topdir)/builtins.h $(topdir)/command.h $(srcdir)/bashgetopt.h +fc.o: $(topdir)/bashhist.h +fc.o: $(topdir)/command.h ../config.h $(topdir)/memalloc.h $(topdir)/error.h +fc.o: $(topdir)/general.h $(topdir)/maxpath.h +fc.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h +fc.o: $(topdir)/subst.h $(topdir)/externs.h $(topdir)/shell.h +fc.o: $(topdir)/flags.h $(topdir)/unwind_prot.h $(topdir)/variables.h +fg_bg.o: $(topdir)/command.h ../config.h $(topdir)/memalloc.h +fg_bg.o: $(topdir)/error.h $(topdir)/general.h +fg_bg.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h +fg_bg.o: $(topdir)/subst.h $(topdir)/externs.h $(topdir)/maxpath.h +fg_bg.o: $(topdir)/shell.h $(topdir)/unwind_prot.h $(topdir)/variables.h +getopts.o: $(topdir)/command.h ../config.h $(topdir)/memalloc.h +getopts.o: $(topdir)/error.h $(topdir)/general.h +getopts.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h +getopts.o: $(topdir)/subst.h $(topdir)/externs.h $(topdir)/maxpath.h +getopts.o: $(topdir)/shell.h $(topdir)/unwind_prot.h $(topdir)/variables.h +hash.o: $(topdir)/builtins.h $(topdir)/command.h $(topdir)/quit.h +hash.o: $(topdir)/execute_cmd.h $(topdir)/hashlib.h +hash.o: $(topdir)/command.h ../config.h $(topdir)/memalloc.h +hash.o: $(topdir)/error.h $(topdir)/general.h +hash.o: $(topdir)/shell.h $(topdir)/unwind_prot.h $(topdir)/variables.h +hash.o: $(srcdir)/common.h $(topdir)/maxpath.h +help.o: $(topdir)/command.h ../config.h $(topdir)/memalloc.h +help.o: $(topdir)/error.h $(topdir)/general.h +help.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h +help.o: $(topdir)/subst.h $(topdir)/externs.h $(topdir)/maxpath.h +help.o: $(topdir)/shell.h $(topdir)/unwind_prot.h $(topdir)/variables.h +history.o: $(topdir)/command.h ../config.h $(topdir)/memalloc.h +history.o: $(topdir)/error.h $(topdir)/general.h +history.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h +history.o: $(topdir)/subst.h $(topdir)/externs.h +history.o: $(topdir)/filecntl.h $(topdir)/shell.h $(topdir)/unwind_prot.h +history.o: $(topdir)/variables.h $(topdir)/bashhist.h $(topdir)/maxpath.h +inlib.o: $(topdir)/command.h ../config.h $(topdir)/memalloc.h +inlib.o: $(topdir)/error.h $(topdir)/general.h +inlib.o: $(topdir)/shell.h $(topdir)/unwind_prot.h $(topdir)/variables.h +inlib.o: $(topdir)/maxpath.h $(topdir)/subst.h $(topdir)/externs.h +inlib.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h +jobs.o: $(topdir)/command.h ../config.h $(topdir)/memalloc.h $(topdir)/error.h +jobs.o: $(topdir)/general.h $(topdir)/quit.h $(srcdir)/bashgetopt.h +jobs.o: $(topdir)/maxpath.h $(topdir)/externs.h +jobs.o: $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h $(topdir)/subst.h +jobs.o: $(topdir)/shell.h $(topdir)/unwind_prot.h $(topdir)/variables.h +kill.o: $(topdir)/command.h ../config.h $(topdir)/memalloc.h $(topdir)/error.h +kill.o: $(topdir)/general.h $(topdir)/subst.h $(topdir)/externs.h +kill.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h +kill.o: $(topdir)/shell.h $(topdir)/trap.h $(topdir)/unwind_prot.h +kill.o: $(topdir)/variables.h $(topdir)/maxpath.h +let.o: $(topdir)/command.h ../config.h $(topdir)/memalloc.h +let.o: $(topdir)/error.h $(topdir)/general.h +let.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h +let.o: $(topdir)/subst.h $(topdir)/externs.h $(topdir)/maxpath.h +let.o: $(topdir)/shell.h $(topdir)/unwind_prot.h $(topdir)/variables.h +pushd.o: $(topdir)/command.h ../config.h $(topdir)/memalloc.h +pushd.o: $(topdir)/error.h $(topdir)/general.h +pushd.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h +pushd.o: $(topdir)/subst.h $(topdir)/externs.h +pushd.o: $(topdir)/shell.h $(topdir)/unwind_prot.h $(topdir)/variables.h +pushd.o: $(topdir)/maxpath.h $(srcdir)/common.h +read.o: $(topdir)/command.h ../config.h $(topdir)/memalloc.h +read.o: $(topdir)/error.h $(topdir)/general.h +read.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h +read.o: $(topdir)/subst.h $(topdir)/externs.h $(topdir)/maxpath.h +read.o: $(topdir)/shell.h $(topdir)/unwind_prot.h $(topdir)/variables.h +return.o: $(topdir)/command.h ../config.h $(topdir)/memalloc.h +return.o: $(topdir)/error.h $(topdir)/general.h +return.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h +return.o: $(topdir)/subst.h $(topdir)/externs.h $(topdir)/maxpath.h +return.o: $(topdir)/shell.h $(topdir)/unwind_prot.h $(topdir)/variables.h +set.o: $(topdir)/command.h ../config.h $(topdir)/memalloc.h +set.o: $(topdir)/general.h $(topdir)/subst.h $(topdir)/externs.h +set.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h +set.o: $(topdir)/shell.h $(topdir)/unwind_prot.h $(topdir)/variables.h +set.o: $(topdir)/maxpath.h $(topdir)/error.h +setattr.o: $(topdir)/command.h ../config.h $(topdir)/memalloc.h +setattr.o: $(topdir)/error.h $(topdir)/general.h $(topdir)/maxpath.h +setattr.o: $(topdir)/quit.h $(srcdir)/common.h $(srcdir)/bashgetopt.h +setattr.o: $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h $(topdir)/subst.h +setattr.o: $(topdir)/externs.h +setattr.o: $(topdir)/shell.h $(topdir)/unwind_prot.h $(topdir)/variables.h +shift.o: $(topdir)/command.h ../config.h $(topdir)/memalloc.h +shift.o: $(topdir)/error.h $(topdir)/general.h +shift.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h +shift.o: $(topdir)/subst.h $(topdir)/externs.h $(topdir)/maxpath.h +shift.o: $(topdir)/shell.h $(topdir)/unwind_prot.h $(topdir)/variables.h +source.o: $(topdir)/command.h ../config.h $(topdir)/memalloc.h +source.o: $(topdir)/error.h $(topdir)/general.h +source.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h +source.o: $(topdir)/subst.h $(topdir)/externs.h $(topdir)/maxpath.h +source.o: $(topdir)/shell.h $(topdir)/unwind_prot.h $(topdir)/variables.h +suspend.o: $(topdir)/command.h ../config.h $(topdir)/memalloc.h +suspend.o: $(topdir)/error.h $(topdir)/general.h +suspend.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h +suspend.o: $(topdir)/subst.h $(topdir)/externs.h $(topdir)/maxpath.h +suspend.o: $(topdir)/shell.h $(topdir)/unwind_prot.h $(topdir)/variables.h +test.o: $(topdir)/command.h ../config.h $(topdir)/memalloc.h +test.o: $(topdir)/error.h $(topdir)/general.h +test.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h +test.o: $(topdir)/subst.h $(topdir)/externs.h $(topdir)/maxpath.h +test.o: $(topdir)/shell.h $(topdir)/unwind_prot.h $(topdir)/variables.h +times.o: $(topdir)/command.h ../config.h $(topdir)/memalloc.h +times.o: $(topdir)/error.h $(topdir)/general.h +times.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h +times.o: $(topdir)/subst.h $(topdir)/externs.h $(topdir)/maxpath.h +times.o: $(topdir)/shell.h $(topdir)/unwind_prot.h $(topdir)/variables.h +trap.o: $(topdir)/command.h ../config.h $(topdir)/memalloc.h +trap.o: $(topdir)/error.h $(topdir)/general.h $(topdir)/externs.h +trap.o: $(topdir)/quit.h $(srcdir)/common.h $(topdir)/maxpath.h +trap.o: $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h $(topdir)/subst.h +trap.o: $(topdir)/shell.h $(topdir)/unwind_prot.h $(topdir)/variables.h +trap.o: $(topdir)/execute_cmd.h +type.o: $(topdir)/command.h ../config.h $(topdir)/memalloc.h +type.o: $(topdir)/error.h $(topdir)/general.h +type.o: $(topdir)/quit.h $(srcdir)/common.h $(topdir)/maxpath.h +type.o: $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h $(topdir)/subst.h +type.o: $(topdir)/externs.h +type.o: $(topdir)/shell.h $(topdir)/unwind_prot.h $(topdir)/variables.h +ulimit.o: $(topdir)/command.h ../config.h $(topdir)/memalloc.h +ulimit.o: $(topdir)/error.h $(topdir)/general.h +ulimit.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h +ulimit.o: $(topdir)/subst.h $(topdir)/externs.h $(topdir)/maxpath.h +ulimit.o: $(topdir)/shell.h $(topdir)/unwind_prot.h $(topdir)/variables.h +umask.o: $(topdir)/command.h ../config.h $(topdir)/memalloc.h +umask.o: $(topdir)/error.h $(topdir)/general.h +umask.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h +umask.o: $(topdir)/subst.h $(topdir)/externs.h $(topdir)/maxpath.h +umask.o: $(topdir)/shell.h $(topdir)/unwind_prot.h $(topdir)/variables.h +wait.o: $(topdir)/command.h ../config.h $(topdir)/memalloc.h +wait.o: $(topdir)/error.h $(topdir)/general.h +wait.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h +wait.o: $(topdir)/subst.h $(topdir)/externs.h $(topdir)/maxpath.h +wait.o: $(topdir)/shell.h $(topdir)/unwind_prot.h $(topdir)/variables.h +shopt.o: $(topdir)/command.h ../config.h $(topdir)/memalloc.h +shopt.o: $(topdir)/error.h $(topdir)/general.h +shopt.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h +shopt.o: $(topdir)/subst.h $(topdir)/externs.h $(topdir)/maxpath.h +shopt.o: $(topdir)/shell.h $(topdir)/unwind_prot.h $(topdir)/variables.h +shopt.o: $(srcdir)/common.h $(srcdir)/bashgetopt.h +bashgetopt.o: $(topdir)/bashansi.h $(topdir)/ansi_stdlib.h +mkbuiltins.o: $(topdir)/bashansi.h $(topdir)/ansi_stdlib.h +fc.o: $(topdir)/bashansi.h $(topdir)/ansi_stdlib.h + +#bind.o: $(RL_LIBSRC)chardefs.h $(RL_LIBSRC)readline.h $(RL_LIBSRC)keymaps.h diff --git a/builtins/alias.def b/builtins/alias.def index a878c70..42955b7 100644 --- a/builtins/alias.def +++ b/builtins/alias.def @@ -23,85 +23,108 @@ $BUILTIN alias $FUNCTION alias_builtin $DEPENDS_ON ALIAS $PRODUCES alias.c -$SHORT_DOC alias [ name[=value] ... ] -`alias' with no arguments prints the list of aliases in the form -NAME=VALUE on standard output. An alias is defined for each NAME -whose VALUE is given. A trailing space in VALUE causes the next -word to be checked for alias substitution. Alias returns true -unless a NAME is given for which no alias has been defined. +$SHORT_DOC alias [-p] [name[=value] ... ] +`alias' with no arguments or with the -p option prints the list +of aliases in the form alias NAME=VALUE on standard output. +Otherwise, an alias is defined for each NAME whose VALUE is given. +A trailing space in VALUE causes the next word to be checked for +alias substitution when the alias is expanded. Alias returns +true unless a NAME is given for which no alias has been defined. $END -#include "../config.h" +#include #if defined (ALIAS) + +#if defined (HAVE_UNISTD_H) +# include +#endif + # include # include "../shell.h" # include "../alias.h" # include "common.h" +# include "bashgetopt.h" extern int interactive; static void print_alias (); /* Hack the alias command in a Korn shell way. */ +int alias_builtin (list) WORD_LIST *list; { - int any_failed = 0; + int any_failed, offset, pflag; + alias_t **alias_list, *t; + char *name, *value; - if (!list) + pflag = 0; + reset_internal_getopt (); + while ((offset = internal_getopt (list, "p")) != -1) { - register int i; - ASSOC **alias_list; + switch (offset) + { + case 'p': + pflag = 1; + break; + default: + builtin_usage (); + return (EX_USAGE); + } + } - if (!aliases) + list = loptend; + + if (list == 0 || pflag) + { + if (aliases == 0) return (EXECUTION_FAILURE); alias_list = all_aliases (); - if (!alias_list) + if (alias_list == 0) return (EXECUTION_FAILURE); - for (i = 0; alias_list[i]; i++) - print_alias (alias_list[i]); + for (offset = 0; alias_list[offset]; offset++) + print_alias (alias_list[offset]); free (alias_list); /* XXX - Do not free the strings. */ + + if (list == 0) + return (EXECUTION_SUCCESS); } - else + + any_failed = 0; + while (list) { - while (list) - { - register char *value, *name = list->word->word; - register int offset; + name = list->word->word; - for (offset = 0; name[offset] && name[offset] != '='; offset++) - ; + for (offset = 0; name[offset] && name[offset] != '='; offset++) + ; - if (offset && name[offset] == '=') - { - name[offset] = '\0'; - value = name + offset + 1; + if (offset && name[offset] == '=') + { + name[offset] = '\0'; + value = name + offset + 1; - add_alias (name, value); - } + add_alias (name, value); + } + else + { + t = find_alias (name); + if (t) + print_alias (t); else { - ASSOC *t = find_alias (name); - if (t) - print_alias (t); - else - { - if (interactive) - builtin_error ("`%s' not found", name); - any_failed++; - } + if (interactive) + builtin_error ("`%s' not found", name); + any_failed++; } - list = list->next; } + list = list->next; } - if (any_failed) - return (EXECUTION_FAILURE); - else - return (EXECUTION_SUCCESS); + + return (any_failed ? EXECUTION_FAILURE : EXECUTION_SUCCESS); } #endif /* ALIAS */ @@ -115,33 +138,37 @@ $END #if defined (ALIAS) /* Remove aliases named in LIST from the aliases database. */ +int unalias_builtin (list) register WORD_LIST *list; { - register ASSOC *alias; - int any_failed = 0; + register alias_t *alias; + int opt, aflag; - while (list && *list->word->word == '-') + aflag = 0; + reset_internal_getopt (); + while ((opt = internal_getopt (list, "a")) != -1) { - register char *word = list->word->word; - - if (ISOPTION (word, 'a')) - { - delete_all_aliases (); - list = list->next; - } - else if (ISOPTION (word, '-')) + switch (opt) { - list = list->next; + case 'a': + aflag = 1; break; + default: + builtin_usage (); + return (EX_USAGE); } - else - { - bad_option (word); - return (EXECUTION_FAILURE); - } } + list = loptend; + + if (aflag) + { + delete_all_aliases (); + return (EXECUTION_SUCCESS); + } + + aflag = 0; while (list) { alias = find_alias (list->word->word); @@ -151,27 +178,25 @@ unalias_builtin (list) else { if (interactive) - builtin_error ("`%s' not an alias", list->word->word); + builtin_error ("`%s': not an alias", list->word->word); - any_failed++; + aflag++; } list = list->next; } - if (any_failed) - return (EXECUTION_FAILURE); - else - return (EXECUTION_SUCCESS); + return (aflag ? EXECUTION_FAILURE : EXECUTION_SUCCESS); } /* Output ALIAS in such a way as to allow it to be read back in. */ static void print_alias (alias) - ASSOC *alias; + alias_t *alias; { - char *value = single_quote (alias->value); + char *value; + value = single_quote (alias->value); printf ("alias %s=%s\n", alias->name, value); free (value); diff --git a/builtins/bashgetopt.c b/builtins/bashgetopt.c index 95dcaac..72ac900 100644 --- a/builtins/bashgetopt.c +++ b/builtins/bashgetopt.c @@ -18,10 +18,17 @@ 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, 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include + +#if defined (HAVE_UNISTD_H) +# include +#endif + +#include "../bashansi.h" #include -#include "shell.h" -#include "bashansi.h" +#include "../shell.h" +#include "common.h" #define ERR(S, C) builtin_error("%s%c", (S), (C)) @@ -41,14 +48,21 @@ char *opts; { register int c; register char *cp; + int plus; /* nonzero means to handle +option */ - if (!list) { + if (*opts == '+') { + plus = 1; + opts++; + } else + plus = 0; + + if (list == 0) { list_optarg = (char *)NULL; loptend = (WORD_LIST *)NULL; /* No non-option arguments */ return -1; } - if (list != lhead || !lhead) { + if (list != lhead || lhead == 0) { /* Hmmm.... called with a different word list. Reset. */ sp = 1; lcurrent = lhead = list; @@ -56,7 +70,7 @@ char *opts; } if (sp == 1) { - if (!lcurrent || + if (lcurrent == 0 || (lcurrent->word->word[0] != '-' || lcurrent->word->word[1] == '\0')) { lhead = (WORD_LIST *)NULL; loptend = lcurrent; @@ -84,23 +98,46 @@ char *opts; return('?'); } - if (*++cp == ':') { - /* Option requires an argument. */ + if (*++cp == ':' || *cp == ';') { + /* `:': Option requires an argument. */ + /* `;': option argument may be missing */ /* We allow -l2 as equivalent to -l 2 */ - if (lcurrent->word->word[sp+1] != '\0') { - list_optarg = &(lcurrent->word->word[sp+1]); + if (lcurrent->word->word[sp+1]) { + list_optarg = lcurrent->word->word + sp + 1; + lcurrent = lcurrent->next; + /* If the specifier is `;', don't set optarg if the next + argument looks like another option. */ + } else if (lcurrent->next && (*cp == ':' || lcurrent->next->word->word[0] != '-')) { + lcurrent = lcurrent->next; + list_optarg = lcurrent->word->word; + lcurrent = lcurrent->next; + } else if (*cp == ';') { + list_optarg = (char *)NULL; lcurrent = lcurrent->next; - } else if (lcurrent->next == NULL) { + } else { /* lcurrent->next == NULL */ ERR("option requires an argument: -", c); sp = 1; list_optarg = (char *)NULL; return('?'); - } else { - lcurrent = lcurrent->next; - list_optarg = lcurrent->word->word; - lcurrent = lcurrent->next; } sp = 1; + } else if (*cp == '#') { + /* optional numeric argument */ + if (lcurrent->word->word[sp+1]) { + if (digit(lcurrent->word->word[sp+1])) { + list_optarg = lcurrent->word->word + sp + 1; + lcurrent = lcurrent->next; + } else + list_optarg = (char *)NULL; + } else { + if (lcurrent->next && legal_number(lcurrent->next->word->word, (long *)0)) { + lcurrent = lcurrent->next; + list_optarg = lcurrent->word->word; + lcurrent = lcurrent->next; + } else + list_optarg = (char *)NULL; + } + } else { /* No argument, just return the option. */ if (lcurrent->word->word[++sp] == '\0') { diff --git a/builtins/bind.def b/builtins/bind.def index cdcd6a3..908803a 100644 --- a/builtins/bind.def +++ b/builtins/bind.def @@ -21,10 +21,12 @@ Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. $PRODUCES bind.c +#include + $BUILTIN bind $DEPENDS_ON READLINE $FUNCTION bind_builtin -$SHORT_DOC bind [-lvd] [-m keymap] [-f filename] [-q name] [keyseq:readline-function] +$SHORT_DOC bind [-lpvsPVS] [-m keymap] [-f filename] [-q name] [-r keyseq] [keyseq:readline-function] Bind a key sequence to a Readline function, or to a macro. The syntax is equivalent to that found in ~/.inputrc, but must be passed as a single argument: bind '"\C-x\C-r": re-read-init-file'. @@ -34,49 +36,75 @@ Arguments we accept: emacs-standard, emacs-meta, emacs-ctlx, vi, vi-move, vi-command, and vi-insert. -l List names of functions. - -v List function names and bindings. - -d Dump functions and bindings such that they - can be read back in. + -P List function names and bindings. + -p List functions and bindings in a form that can be + reused as input. + -r keyseq Remove the binding for KEYSEQ. -f filename Read key bindings from FILENAME. -q function-name Query about which keys invoke the named function. + -V List variable names and values + -v List variable names and values in a form that can + be reused as input. + -S List key sequences that invoke macros and their values + -s List key sequences that invoke macros and their values in + a form that can be reused as input. $END -#include -#include "../shell.h" #if defined (READLINE) + +#if defined (HAVE_UNISTD_H) +# include +#endif + +#include #include #if !defined (errno) extern int errno; #endif /* !errno */ + #include #include + +#include "../shell.h" +#include "../bashline.h" #include "bashgetopt.h" +#include "common.h" static int query_bindings (); -extern int bash_readline_initialized; extern int no_line_editing; #define BIND_RETURN(x) do { return_code = x; goto bind_exit; } while (0) -#define USAGE "usage: bind [-lvd] [-m keymap] [-f filename] [-q name] [keyseq:readline_func]" +#define LFLAG 0x01 +#define PFLAG 0x02 +#define FFLAG 0x04 +#define VFLAG 0x08 +#define QFLAG 0x10 +#define MFLAG 0x20 +#define RFLAG 0x40 +#define PPFLAG 0x80 +#define VVFLAG 0x100 +#define SFLAG 0x200 +#define SSFLAG 0x400 int bind_builtin (list) WORD_LIST *list; { - int return_code = EXECUTION_SUCCESS; + int return_code; FILE *old_rl_outstream; Keymap kmap, saved_keymap; - int lflag, dflag, fflag, vflag, qflag, mflag, opt; - char *initfile, *map_name, *fun_name; + int flags, opt; + char *initfile, *map_name, *fun_name, *remove_seq; if (no_line_editing) return (EXECUTION_FAILURE); kmap = saved_keymap = (Keymap) NULL; - lflag = dflag = vflag = fflag = qflag = mflag = 0; - initfile = map_name = fun_name = (char *)NULL; + flags = 0; + initfile = map_name = fun_name = remove_seq = (char *)NULL; + return_code = EXECUTION_SUCCESS; if (!bash_readline_initialized) initialize_readline (); @@ -88,39 +116,49 @@ bind_builtin (list) rl_outstream = stdout; reset_internal_getopt (); - while ((opt = internal_getopt (list, "lvdf:q:m:")) != EOF) + while ((opt = internal_getopt (list, "lvpVPsSf:q:m:r:")) != EOF) { switch (opt) { case 'l': - lflag++; + flags |= LFLAG; break; - case 'v': - vflag++; + flags |= VFLAG; break; - - case 'd': - dflag++; + case 'p': + flags |= PFLAG; break; - case 'f': - fflag++; + flags |= FFLAG; initfile = list_optarg; break; - case 'm': - mflag++; + flags |= MFLAG; map_name = list_optarg; break; - case 'q': - qflag++; + flags |= QFLAG; fun_name = list_optarg; break; - + case 'r': + flags |= RFLAG; + remove_seq = list_optarg; + break; + case 'V': + flags |= VVFLAG; + break; + case 'P': + flags |= PPFLAG; + break; + case 's': + flags |= SFLAG; + break; + case 'S': + flags |= SSFLAG; + break; default: - builtin_error (USAGE); + builtin_usage (); BIND_RETURN (EX_USAGE); } } @@ -130,12 +168,12 @@ bind_builtin (list) /* First, see if we need to install a special keymap for this command. Then start on the arguments. */ - if (mflag && map_name) + if ((flags & MFLAG) && map_name) { kmap = rl_get_keymap_by_name (map_name); if (!kmap) { - builtin_error ("`%s': illegal keymap name", map_name); + builtin_error ("`%s': invalid keymap name", map_name); BIND_RETURN (EXECUTION_FAILURE); } } @@ -149,16 +187,28 @@ bind_builtin (list) /* XXX - we need to add exclusive use tests here. It doesn't make sense to use some of these options together. */ /* Now hack the option arguments */ - if (lflag) - rl_list_funmap_names (0); + if (flags & LFLAG) + rl_list_funmap_names (); - if (vflag) + if (flags & PFLAG) + rl_function_dumper (1); + + if (flags & PPFLAG) rl_function_dumper (0); - if (dflag) - rl_function_dumper (1); + if (flags & SFLAG) + rl_macro_dumper (1); + + if (flags & SSFLAG) + rl_macro_dumper (0); - if (fflag && initfile) + if (flags & VFLAG) + rl_variable_dumper (1); + + if (flags & VVFLAG) + rl_variable_dumper (0); + + if ((flags & FFLAG) && initfile) { if (rl_read_init_file (initfile) != 0) { @@ -167,9 +217,18 @@ bind_builtin (list) } } - if (qflag && fun_name) + if ((flags & QFLAG) && fun_name) return_code = query_bindings (fun_name); + if ((flags & RFLAG) && remove_seq) + { + if (rl_set_key (remove_seq, (Function *)NULL, rl_get_keymap ()) != 0) + { + builtin_error ("cannot unbind %s", remove_seq); + BIND_RETURN (EXECUTION_FAILURE); + } + } + /* Process the rest of the arguments as binding specifications. */ while (list) { diff --git a/builtins/break.def b/builtins/break.def index d72f9e3..d6f8598 100644 --- a/builtins/break.def +++ b/builtins/break.def @@ -27,8 +27,14 @@ $SHORT_DOC break [n] Exit from within a FOR, WHILE or UNTIL loop. If N is specified, break N levels. $END +#include + +#if defined (HAVE_UNISTD_H) +#include +#endif #include "../shell.h" +#include "common.h" extern char *this_command_name; @@ -45,6 +51,7 @@ int continuing = 0; /* Set up to break x levels, where x defaults to 1, but can be specified as the first argument. */ +int break_builtin (list) WORD_LIST *list; { @@ -75,6 +82,7 @@ $END /* Set up to continue x levels, where x defaults to 1, but can be specified as the first argument. */ +int continue_builtin (list) WORD_LIST *list; { @@ -103,7 +111,7 @@ check_loop_level () { #if defined (BREAK_COMPLAINS) if (!loop_level) - builtin_error ("Only meaningful in a `for', `while', or `until' loop"); + builtin_error ("only meaningful in a `for', `while', or `until' loop"); #endif /* BREAK_COMPLAINS */ return (loop_level); diff --git a/builtins/builtin.def b/builtins/builtin.def index 824b30d..75d25a0 100644 --- a/builtins/builtin.def +++ b/builtins/builtin.def @@ -28,15 +28,20 @@ Run a shell builtin. This is useful when you wish to rename a shell builtin to be a function, but need the functionality of the builtin within the function itself. $END +#include -#include "../shell.h" +#if defined (HAVE_UNISTD_H) +# include +#endif +#include "../shell.h" #include "common.h" extern char *this_command_name; /* Run the command mentioned in list directly, without going through the normal alias/function/builtin/filename lookup process. */ +int builtin_builtin (list) WORD_LIST *list; { diff --git a/builtins/cd.def b/builtins/cd.def index 338f694..e6611d0 100644 --- a/builtins/cd.def +++ b/builtins/cd.def @@ -1,5 +1,5 @@ This file is cd.def, from which is created cd.c. It implements the -builtins "cd", "pwd", "pushd", "popd", and "dirs" in Bash. +builtins "cd" and "pwd" in Bash. Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc. @@ -20,15 +20,20 @@ with Bash; see the file COPYING. If not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. $PRODUCES cd.c +#include -#include +#if defined (HAVE_UNISTD_H) +# include +#endif + +#include "../bashtypes.h" +#include "../posixdir.h" +#include "../posixstat.h" #include -#if defined (HAVE_STRING_H) -# include -#else /* !HAVE_STRING_H */ -# include -#endif /* !HAVE_STRING_H */ +#include + +#include "../bashansi.h" #include #include @@ -37,27 +42,102 @@ $PRODUCES cd.c #include "../flags.h" #include "../maxpath.h" #include "common.h" +#include "bashgetopt.h" #if !defined (errno) extern int errno; #endif /* !errno */ -static int change_to_directory (), cd_to_string (); +extern int posixly_correct, interactive; +extern char *bash_getcwd_errstr; + +static int change_to_directory (); + +static char *cdspell (); +static int spname (), mindist (), spdist (); +int cdspelling = 1; + +int cdable_vars; $BUILTIN cd $FUNCTION cd_builtin -$SHORT_DOC cd [dir] +$SHORT_DOC cd [-PL] [dir] Change the current directory to DIR. The variable $HOME is the default DIR. The variable $CDPATH defines the search path for -the directory containing DIR. Alternative directory names are -separated by a colon (:). A null directory name is the same as +the directory containing DIR. Alternative directory names in CDPATH +are separated by a colon (:). A null directory name is the same as the current directory, i.e. `.'. If DIR begins with a slash (/), then $CDPATH is not used. If the directory is not found, and the -shell variable `cdable_vars' exists, then try the word as a variable +shell option `cdable_vars' is set, then try the word as a variable name. If that variable has a value, then cd to the value of that -variable. +variable. The -P option says to use the physical directory structure +instead of following symbolic links; the -L option forces symbolic links +to be followed. $END +/* Take PATH, an element from $CDPATH, and DIR, a directory name, and paste + them together into PATH/DIR. Tilde expansion is performed on PATH if + DOTILDE is non-zero. If PATH is the empty string, it is converted to + `./', since a null element in $CDPATH means the current directory. */ +static char * +mkpath (path, dir, dotilde) + char *path, *dir; + int dotilde; +{ + int dirlen, pathlen; + char *ret, *xpath; + + if (*path == '\0') + { + xpath = xmalloc (2); + xpath[0] = '.'; + xpath[1] = '\0'; + pathlen = 1; + } + else + { + xpath = (dotilde && *path == '~') ? bash_tilde_expand (path) : path; + pathlen = strlen (xpath); + } + + dirlen = strlen (dir); + ret = xmalloc (2 + dirlen + pathlen); + strcpy (ret, xpath); + if (xpath[pathlen - 1] != '/') + { + ret[pathlen++] = '/'; + ret[pathlen] = '\0'; + } + strcpy (ret + pathlen, dir); + if (xpath != path) + free (xpath); + return (ret); +} + +static int +bindpwd (no_symlinks) + int no_symlinks; +{ + char *dirname; + int old_symlinks; + + if (no_symlinks) + { + old_symlinks = no_symbolic_links; + no_symbolic_links = 1; + dirname = get_working_directory ("cd"); + no_symbolic_links = old_symlinks; + } + else + dirname = get_working_directory ("cd"); + + bind_variable ("OLDPWD", get_string_value ("PWD")); + bind_variable ("PWD", dirname); + + FREE (dirname); + return (EXECUTION_SUCCESS); +} + /* This builtin is ultimately the way that all user-visible commands should change the current working directory. It is called by cd_to_string (), so the programming interface is simple, and it handles errors and @@ -66,7 +146,9 @@ int cd_builtin (list) WORD_LIST *list; { - char *dirname; + char *dirname, *cdpath, *path, *temp; + int path_index, no_symlinks, opt; + struct stat sb; #if defined (RESTRICTED_SHELL) if (restricted) @@ -76,535 +158,210 @@ cd_builtin (list) } #endif /* RESTRICTED_SHELL */ - if (list) + no_symlinks = no_symbolic_links; + reset_internal_getopt (); + while ((opt = internal_getopt (list, "LP")) != -1) { - char *extract_colon_unit (); - char *path_string = get_string_value ("CDPATH"); - char *path; - int path_index = 0, dirlen, pathlen; - - dirname = list->word->word; - - if (path_string && !absolute_pathname (dirname)) + switch (opt) { - while ((path = extract_colon_unit (path_string, &path_index))) - { - char *dir; - - if (*path == '~') - { - char *te_string = tilde_expand (path); - - free (path); - path = te_string; - } - - if (!*path) - { - free (path); - path = xmalloc (2); - path[0] = '.'; /* by definition. */ - path[1] = '\0'; - } - - dirlen = strlen (dirname); - pathlen = strlen (path); - dir = xmalloc (2 + dirlen + pathlen); - strcpy (dir, path); - if (path[pathlen - 1] != '/') - { - dir[pathlen++] = '/'; - dir[pathlen] = '\0'; - } - strcpy (dir + pathlen, dirname); - free (path); - - if (change_to_directory (dir)) - { - /* replaces (strncmp (dir, "./", 2) != 0) */ - if (dir[0] != '.' || dir[1] != '/') - printf ("%s\n", dir); - - free (dir); - goto bind_and_exit; - } - else - free (dir); - } - } - - if (!change_to_directory (dirname)) - { - /* Maybe this is `cd -', equivalent to `cd $OLDPWD' */ - if (dirname[0] == '-' && dirname[1] == '\0') - { - char *t = get_string_value ("OLDPWD"); - - if (t && change_to_directory (t)) - goto bind_and_exit; - } - - /* If the user requests it, then perhaps this is the name of - a shell variable, whose value contains the directory to - change to. If that is the case, then change to that - directory. */ - if (find_variable ("cdable_vars")) - { - char *t = get_string_value (dirname); - - if (t && change_to_directory (t)) - { - printf ("%s\n", t); - goto bind_and_exit; - } - } - - file_error (dirname); + case 'P': + no_symlinks = 1; + break; + case 'L': + no_symlinks = 0; + break; + default: + builtin_usage (); return (EXECUTION_FAILURE); } - goto bind_and_exit; } - else + list = loptend; + + if (list == 0) { + /* `cd' without arguments is equivalent to `cd $HOME' */ dirname = get_string_value ("HOME"); - if (!dirname) - return (EXECUTION_FAILURE); - - if (!change_to_directory (dirname)) + if (dirname == 0) { - file_error (dirname); + builtin_error ("HOME not set"); return (EXECUTION_FAILURE); } - bind_and_exit: - { - char *directory; - - directory = get_working_directory ("cd"); - - bind_variable ("OLDPWD", get_string_value ("PWD")); - bind_variable ("PWD", directory); - - FREE (directory); - } - return (EXECUTION_SUCCESS); - } -} - -$BUILTIN pwd -$FUNCTION pwd_builtin -$SHORT_DOC pwd -Print the current working directory. -$END - -/* Non-zero means that pwd always give verbatim directory, regardless of - symbolic link following. */ -static int verbatim_pwd; - -/* Print the name of the current working directory. */ -pwd_builtin (list) - WORD_LIST *list; -{ - char *directory, *s; - -#if 0 - no_args (list); -#else - verbatim_pwd = no_symbolic_links; - if (list && (s = list->word->word) && s[0] == '-' && s[1] == 'P' && !s[2]) - verbatim_pwd = 1; -#endif - - if (verbatim_pwd) - { - char *buffer = xmalloc (MAXPATHLEN); - directory = getwd (buffer); - - if (!directory) + if (change_to_directory (dirname, no_symlinks) == 0) { - builtin_error ("%s", buffer); - free (buffer); + builtin_error ("%s: %s", dirname, strerror (errno)); + return (EXECUTION_FAILURE); } } - else - directory = get_working_directory ("pwd"); - - if (directory) + else if (list->word->word[0] == '-' && list->word->word[1] == '\0') { - printf ("%s\n", directory); - fflush (stdout); - free (directory); - return (EXECUTION_SUCCESS); - } - else - return (EXECUTION_FAILURE); -} - -$BUILTIN pushd -$FUNCTION pushd_builtin -$DEPENDS_ON PUSHD_AND_POPD -$SHORT_DOC pushd [dir | +n | -n] -Adds a directory to the top of the directory stack, or rotates -the stack, making the new top of the stack the current working -directory. With no arguments, exchanges the top two directories. - -+n Rotates the stack so that the Nth directory (counting - from the left of the list shown by `dirs') is at the top. - --n Rotates the stack so that the Nth directory (counting - from the right) is at the top. - -dir adds DIR to the directory stack at the top, making it the - new current working directory. + /* This is `cd -', equivalent to `cd $OLDPWD' */ + dirname = get_string_value ("OLDPWD"); -You can see the directory stack with the `dirs' command. -$END - -#if defined (PUSHD_AND_POPD) -/* Some useful commands whose behaviour has been observed in Csh. */ - -/* The list of remembered directories. */ -static char **pushd_directory_list = (char **)NULL; - -/* Number of existing slots in this list. */ -static int directory_list_size = 0; - -/* Offset to the end of the list. */ -static int directory_list_offset = 0; - -pushd_builtin (list) - WORD_LIST *list; -{ - char *temp, *current_directory; - int j = directory_list_offset - 1; - char direction = '+'; - - /* If there is no argument list then switch current and - top of list. */ - if (!list) - { - if (!directory_list_offset) + if (dirname == 0 || change_to_directory (dirname, no_symlinks) == 0) { - builtin_error ("No other directory"); + if (dirname == 0) + builtin_error ("OLDPWD not set"); + else + builtin_error ("%s: %s", dirname, strerror (errno)); return (EXECUTION_FAILURE); } - - current_directory = get_working_directory ("pushd"); - if (!current_directory) - return (EXECUTION_FAILURE); - - temp = pushd_directory_list[j]; - pushd_directory_list[j] = current_directory; - goto change_to_temp; } else { - direction = *(list->word->word); - if (direction == '+' || direction == '-') + dirname = list->word->word; + + if (absolute_pathname (dirname) == 0 && (cdpath = get_string_value ("CDPATH"))) { - int num; - if (1 == sscanf (&(list->word->word)[1], "%d", &num)) + /* Find directory in $CDPATH. */ + path_index = 0; + while ((path = extract_colon_unit (cdpath, &path_index))) { - if (direction == '-') - num = directory_list_offset - num; + temp = mkpath (path, dirname, 1); + free (path); - if (num > directory_list_offset || num < 0) + if (stat (temp, &sb) < 0 || S_ISDIR (sb.st_mode) == 0) { - if (!directory_list_offset) - builtin_error ("Directory stack empty"); - else - builtin_error ("Stack contains only %d directories", - directory_list_offset + 1); - return (EXECUTION_FAILURE); + free (temp); + continue; } - else - { - /* Rotate the stack num times. Remember, the - current directory acts like it is part of the - stack. */ - temp = get_working_directory ("pushd"); - - if (!num) - goto change_to_temp; - - do - { - char *top = - pushd_directory_list[directory_list_offset - 1]; - - for (j = directory_list_offset - 2; j > -1; j--) - pushd_directory_list[j + 1] = pushd_directory_list[j]; - - pushd_directory_list[j + 1] = temp; - - temp = top; - num--; - } - while (num); - temp = savestring (temp); - change_to_temp: - { - int tt = EXECUTION_FAILURE; - - if (temp) - { - tt = cd_to_string (temp); - free (temp); - } - - if ((tt == EXECUTION_SUCCESS)) - dirs_builtin ((WORD_LIST *)NULL); + if (change_to_directory (temp, no_symlinks)) + { + if (temp[0] != '.' || temp[1] != '/') + printf ("%s\n", temp); - return (tt); - } + free (temp); + /* Posix.2 says that after using CDPATH, the resultant + value of $PWD will not contain symlinks. */ + return (bindpwd (posixly_correct)); } + else + free (temp); } } - /* Change to the directory in list->word->word. Save the current - directory on the top of the stack. */ - current_directory = get_working_directory ("pushd"); - if (!current_directory) - return (EXECUTION_FAILURE); + if (change_to_directory (dirname, no_symlinks)) + return (bindpwd (no_symlinks)); - if (cd_builtin (list) == EXECUTION_SUCCESS) + /* If the user requests it, then perhaps this is the name of + a shell variable, whose value contains the directory to + change to. If that is the case, then change to that + directory. */ + if (cdable_vars) { - if (directory_list_offset == directory_list_size) + temp = get_string_value (dirname); + if (temp && change_to_directory (temp, no_symlinks)) { - pushd_directory_list = (char **) - xrealloc (pushd_directory_list, - (directory_list_size += 10) * sizeof (char *)); + printf ("%s\n", temp); + return (bindpwd (no_symlinks)); } - pushd_directory_list[directory_list_offset++] = current_directory; - - dirs_builtin ((WORD_LIST *)NULL); - - return (EXECUTION_SUCCESS); - } - else - { - free (current_directory); - return (EXECUTION_FAILURE); } - } -} -#endif /* PUSHD_AND_POPD */ - -$BUILTIN dirs -$FUNCTION dirs_builtin -$DEPENDS_ON PUSHD_AND_POPD -$SHORT_DOC dirs [-l] -Display the list of currently remembered directories. Directories -find their way onto the list with the `pushd' command; you can get -back up through the list with the `popd' command. - -The -l flag specifies that `dirs' should not print shorthand versions -of directories which are relative to your home directory. This means -that `~/bin' might be displayed as `/homes/bfox/bin'. -$END - -#if defined (PUSHD_AND_POPD) -/* Print the current list of directories on the directory stack. */ -dirs_builtin (list) - WORD_LIST *list; -{ - int i, format, desired_index, index_flag; - char *temp, *w; - format = index_flag = 0; - desired_index = -1; - /* Maybe do long form or print specific dir stack entry? */ - while (list) - { - if (strcmp (list->word->word, "-l") == 0) - { - format++; - list = list->next; - } - else if (*list->word->word == '+' && all_digits (list->word->word + 1)) + /* If the user requests it, try to find a directory name similar in + spelling to the one requested, in case the user made a simple + typo. This is similar to the UNIX 8th and 9th Edition shells. */ + if (interactive && cdspelling) { - w = list->word->word + 1; - index_flag = 1; - i = atoi (w); - /* dirs +0 prints the current working directory. */ - if (i == 0) - desired_index = i; - else if (i == directory_list_offset) - { - desired_index = 0; - index_flag = 2; - } - else - desired_index = directory_list_offset - i; - list = list->next; + temp = cdspell (dirname); + if (temp && change_to_directory (temp, no_symlinks)) + { + printf ("%s\n", temp); + free (temp); + return (bindpwd (no_symlinks)); + } + else + FREE (temp); } - else if (*list->word->word == '-' && all_digits (list->word->word + 1)) - { - w = list->word->word + 1; - i = atoi (w); - index_flag = 2; - /* dirs -X where X is directory_list_offset prints the current - working directory. */ - if (i == directory_list_offset) - { - index_flag = 1; - desired_index = 0; - } - else - desired_index = i; - list = list->next; - } - else - { - bad_option (list->word->word); - return (EXECUTION_FAILURE); - } - } - if (index_flag && (desired_index < 0 || desired_index > directory_list_offset)) - { - if (directory_list_offset == 0) - builtin_error ("directory stack empty"); - else - builtin_error ("%s: bad directory stack index", w); + builtin_error ("%s: %s", dirname, strerror (errno)); return (EXECUTION_FAILURE); } - /* The first directory printed is always the current working directory. */ - if (!index_flag || (index_flag == 1 && desired_index == 0)) - { - temp = get_working_directory ("dirs"); - if (!temp) - temp = savestring (""); - printf ("%s", format ? temp : polite_directory_format (temp)); - free (temp); - if (index_flag) - { - putchar ('\n'); - return EXECUTION_SUCCESS; - } - } - -#define DIRSTACK_ENTRY(i) \ - format ? pushd_directory_list[i] \ - : polite_directory_format (pushd_directory_list[i]) - - /* Now print the requested directory stack entries. */ - if (index_flag) - printf ("%s", DIRSTACK_ENTRY (desired_index)); - else - for (i = (directory_list_offset - 1); i > -1; i--) - printf (" %s", DIRSTACK_ENTRY (i)); - - putchar ('\n'); - fflush (stdout); - return (EXECUTION_SUCCESS); + return (bindpwd (no_symlinks)); } -#endif /* PUSHD_AND_POPD */ - -$BUILTIN popd -$FUNCTION popd_builtin -$DEPENDS_ON PUSHD_AND_POPD -$SHORT_DOC popd [+n | -n] -Removes entries from the directory stack. With no arguments, -removes the top directory from the stack, and cd's to the new -top directory. -+n removes the Nth entry counting from the left of the list - shown by `dirs', starting with zero. For example: `popd +0' - removes the first directory, `popd +1' the second. - --n removes the Nth entry counting from the right of the list - shown by `dirs', starting with zero. For example: `popd -0' - removes the last directory, `popd -1' the next to last. - -You can see the directory stack with the `dirs' command. +$BUILTIN pwd +$FUNCTION pwd_builtin +$SHORT_DOC pwd [-PL] +Print the current working directory. With the -P option, pwd prints +the physical directory, without any symbolic links; the -L option +makes pwd follow symbolic links. $END -#if defined (PUSHD_AND_POPD) -/* Pop the directory stack, and then change to the new top of the stack. - If LIST is non-null it should consist of a word +N or -N, which says - what element to delete from the stack. The default is the top one. */ -popd_builtin (list) +/* Non-zero means that pwd always prints the physical directory, without + symbolic links. */ +static int verbatim_pwd; + +/* Print the name of the current working directory. */ +int +pwd_builtin (list) WORD_LIST *list; { - register int i; - int which = 0; - char direction = '+'; + char *directory, *buffer; + int opt; - if (list) + verbatim_pwd = no_symbolic_links; + reset_internal_getopt (); + while ((opt = internal_getopt (list, "LP")) != -1) { - direction = *(list->word->word); - - if ((direction != '+' && direction != '-') || - (1 != sscanf (&((list->word->word)[1]), "%d", &which))) + switch (opt) { - builtin_error ("bad arg `%s'", list->word->word); + case 'P': + verbatim_pwd = 1; + break; + case 'L': + verbatim_pwd = 0; + break; + default: + builtin_usage (); return (EXECUTION_FAILURE); } } + list = loptend; - if (which > directory_list_offset || (!directory_list_offset && !which)) + if (verbatim_pwd) { - if (!directory_list_offset) - builtin_error ("Directory stack empty"); - else - builtin_error ("Stack contains only %d directories", - directory_list_offset + 1); - return (EXECUTION_FAILURE); - } + buffer = xmalloc (PATH_MAX); + directory = getcwd (buffer, PATH_MAX); - /* Handle case of no specification, or top of stack specification. */ - if ((direction == '+' && which == 0) || - (direction == '-' && which == directory_list_offset)) - { - i = cd_to_string (pushd_directory_list[directory_list_offset - 1]); - if (i != EXECUTION_SUCCESS) - return (i); - free (pushd_directory_list[--directory_list_offset]); + if (directory == 0) + { + builtin_error ("%s: %s", bash_getcwd_errstr, strerror (errno)); + free (buffer); + } } else - { - /* Since an offset other than the top directory was specified, - remove that directory from the list and shift the remainder - of the list into place. */ - - if (direction == '+') - i = directory_list_offset - which; - else - i = which; - - free (pushd_directory_list[i]); - directory_list_offset--; + directory = get_working_directory ("pwd"); - /* Shift the remainder of the list into place. */ - for (; i < directory_list_offset; i++) - pushd_directory_list[i] = pushd_directory_list[i + 1]; + if (directory) + { + printf ("%s\n", directory); + fflush (stdout); + free (directory); + return (EXECUTION_SUCCESS); } - - dirs_builtin ((WORD_LIST *)NULL); - - return (EXECUTION_SUCCESS); + else + return (EXECUTION_FAILURE); } -#endif /* PUSHD_AND_POPD */ /* Do the work of changing to the directory NEWDIR. Handle symbolic link following, etc. */ static int -change_to_directory (newdir) +change_to_directory (newdir, nolinks) char *newdir; + int nolinks; { char *t; - if (!no_symbolic_links) + if (nolinks == 0) { int chdir_return = 0; char *tdir = (char *)NULL; - if (!the_current_working_directory) + if (the_current_working_directory == 0) { t = get_working_directory ("cd_links"); FREE (t); @@ -625,7 +382,6 @@ change_to_directory (newdir) else { FREE (tdir); - tdir = t; } @@ -667,23 +423,171 @@ change_to_directory (newdir) return (chdir_return); } else + return (chdir (newdir) == 0); +} + +/* Code for cd spelling correction. Original patch submitted by + Neil Russel (caret@c-side.com). */ + +static char * +cdspell (dirname) + char *dirname; +{ + int n; + char *guess; + + n = (strlen (dirname) * 3 + 1) / 2 + 1; + guess = xmalloc (n); + + switch (spname (dirname, guess)) { - if (chdir (newdir) < 0) - return (0); - else - return (1); + case -1: + default: + free (guess); + return (char *)NULL; + case 0: + case 1: + return guess; + } +} + +/* + * `spname' and its helpers are inspired by the code in "The UNIX + * Programming Environment, Kernighan & Pike, Prentice-Hall 1984", + * pages 209 - 213. + */ + +/* + * `spname' -- return a correctly spelled filename + * + * int spname(char * oldname, char * newname) + * Returns: -1 if no reasonable match found + * 0 if exact match found + * 1 if corrected + * Stores corrected name in `newname'. + */ +static int +spname(oldname, newname) + char *oldname; + char *newname; +{ + char *op, *np, *p; + char guess[PATH_MAX + 1], best[PATH_MAX + 1]; + + op = oldname; + np = newname; + for (;;) + { + while (*op == '/') /* Skip slashes */ + *np++ = *op++; + *np = '\0'; + + if (*op == '\0') /* Exact or corrected */ + { + /* `.' is rarely the right thing. */ + if (oldname[1] == '\0' && newname[1] == '\0' && + oldname[0] != '.' && newname[0] == '.') + return -1; + return strcmp(oldname, newname) != 0; + } + + /* Copy next component into guess */ + for (p = guess; *op != '/' && *op != '\0'; op++) + if (p < guess + PATH_MAX) + *p++ = *op; + *p = '\0'; + + if (mindist(newname, guess, best) >= 3) + return -1; /* Hopeless */ + + /* + * Add to end of newname + */ + for (p = best; *np = *p++; np++) + ; } } -/* Switch to the directory in NAME. This uses the cd_builtin to do the work, - so if the result is EXECUTION_FAILURE then an error message has already - been printed. */ +/* + * Search directory for a guess + */ static int -cd_to_string (name) - char *name; +mindist(dir, guess, best) + char *dir; + char *guess; + char *best; { - WORD_LIST *tlist = make_word_list (make_word (name), NULL); - int result = (cd_builtin (tlist)); - dispose_words (tlist); - return (result); + DIR *fd; + struct dirent *dp; + int dist, x; + + dist = 3; /* Worst distance */ + if (*dir == '\0') + dir = "."; + + if ((fd = opendir(dir)) == NULL) + return dist; + + while ((dp = readdir(fd)) != NULL) + { + /* + * Look for a better guess. If the new guess is as + * good as the current one, we take it. This way, + * any single character match will be a better match + * than ".". + */ + x = spdist(dp->d_name, guess); + if (x <= dist && x != 3) + { + strcpy(best, dp->d_name); + dist = x; + if (dist == 0) /* Exact match */ + break; + } + } + (void)closedir(fd); + + return dist; +} + +/* + * `spdist' -- return the "distance" between two names. + * + * int spname(char * oldname, char * newname) + * Returns: 0 if strings are identical + * 1 if two characters are transposed + * 2 if one character is wrong, added or deleted + * 3 otherwise + */ +static int +spdist(cur, new) + char *cur, *new; +{ + while (*cur == *new) + { + if (*cur == '\0') + return 0; /* Exact match */ + cur++; + new++; + } + + if (*cur) + { + if (*new) + { + if (cur[1] && new[1] && cur[0] == new[1] && cur[1] == new[0] && strcmp (cur + 2, new + 2) == 0) + return 1; /* Transposition */ + + if (strcmp (cur + 1, new + 1) == 0) + return 2; /* One character mismatch */ + } + + if (strcmp(&cur[1], &new[0]) == 0) + return 2; /* Extra character */ + } + + if (*new && strcmp(cur, new + 1) == 0) + return 2; /* Missing character */ + + return 3; } diff --git a/builtins/colon.def b/builtins/colon.def index 4ae5b65..7fd9656 100644 --- a/builtins/colon.def +++ b/builtins/colon.def @@ -28,10 +28,32 @@ $SHORT_DOC : No effect; the command does nothing. A zero exit code is returned. $END -/* Do nothing. This command is a no-op. */ +$BUILTIN true +$DOCNAME true_builtin +$FUNCTION colon_builtin +$SHORT_DOC true +Return a successful result. +$END + +$BUILTIN false +$DOCNAME false_builtin +$FUNCTION false_builtin +$SHORT_DOC false +Return an unsuccessful result. +$END + +/* Return a successful result. */ int colon_builtin (ignore) char *ignore; { return (0); } + +/* Return an unsuccessful result. */ +int +false_builtin (ignore) + char *ignore; +{ + return (1); +} diff --git a/builtins/command.def b/builtins/command.def index b84613e..3a14dc6 100644 --- a/builtins/command.def +++ b/builtins/command.def @@ -23,7 +23,7 @@ $PRODUCES command.c $BUILTIN command $FUNCTION command_builtin -$SHORT_DOC command [-pVv] [command [arg ...]] +$SHORT_DOC command [-pVv] command [arg ...] Runs COMMAND with ARGS ignoring shell functions. If you have a shell function called `ls', and you wish to call the command `ls', you can say "command ls". If the -p option is given, a default value is used @@ -32,14 +32,19 @@ the -V or -v option is given, a string is printed describing COMMAND. The -V option produces a more verbose description. $END -#if defined (HAVE_STRING_H) -# include -#else /* !HAVE_STRING_H */ -# include -#endif /* !HAVE_STRING_H */ +#include + +#if defined (HAVE_UNISTD_H) +# include +#endif + +#include "../bashansi.h" #include "../shell.h" +#include "../execute_cmd.h" +#include "../flags.h" #include "bashgetopt.h" +#include "common.h" extern int subshell_environment; @@ -52,9 +57,11 @@ int command_builtin (list) WORD_LIST *list; { - int result, verbose = 0, use_standard_path = 0, opt; - char *old_path; - + int result, verbose, use_standard_path, opt; + char *old_path, *standard_path; + COMMAND *command; + + verbose = use_standard_path = 0; reset_internal_getopt (); while ((opt = internal_getopt (list, "pvV")) != -1) { @@ -69,73 +76,80 @@ command_builtin (list) case 'v': verbose = 4; break; - default: - report_bad_option (); - builtin_error ("usage: command [-pvV] [command [arg...]]"); + builtin_usage (); return (EX_USAGE); } } list = loptend; - if (!list) + if (list == 0) return (EXECUTION_SUCCESS); if (verbose) { - int found, any_found = 0; + int found, any_found; - while (list) + for (any_found = 0; list; list = list->next) { - found = describe_command (list->word->word, verbose, 0); - if (!found) + if (found == 0) builtin_error ("%s: not found", list->word->word); any_found += found; - list = list->next; } return (any_found ? EXECUTION_SUCCESS : EXECUTION_FAILURE); } +#if defined (RESTRICTED_SHELL) + if (use_standard_path && restricted) + { + builtin_error ("restricted: cannot use -p"); + return (EXECUTION_FAILURE); + } +#endif + begin_unwind_frame ("command_builtin"); /* We don't want this to be reparsed (consider command echo 'foo &'), so just make a simple_command structure and call execute_command with it. */ - { - COMMAND *command; - - if (use_standard_path) - { - char *standard_path; - - old_path = get_string_value ("PATH"); - if (old_path) - old_path = savestring (old_path); - else - old_path = savestring (""); - add_unwind_protect ((Function *)restore_path, old_path); - - standard_path = get_standard_path (); - bind_variable ("PATH", standard_path); - free (standard_path); - } - command = make_bare_simple_command (); - command->value.Simple->words = (WORD_LIST *)copy_word_list (list); - command->value.Simple->redirects = (REDIRECT *)NULL; - command->flags |= (CMD_NO_FUNCTIONS | CMD_INHIBIT_EXPANSION); - command->value.Simple->flags |= (CMD_NO_FUNCTIONS | CMD_INHIBIT_EXPANSION); - /* If we're in a subshell, see if we can get away without forking - again, since we've already forked to run this builtin. */ - if (subshell_environment) - { - command->flags |= CMD_NO_FORK; - command->value.Simple->flags |= CMD_NO_FORK; - } - add_unwind_protect ((char *)dispose_command, command); - result = execute_command (command); - } + if (use_standard_path) + { + old_path = get_string_value ("PATH"); + if (old_path) + old_path = savestring (old_path); + else + { + old_path = xmalloc (1); + old_path[0] = '\0'; + } + add_unwind_protect ((Function *)restore_path, old_path); + + standard_path = get_standard_path (); + bind_variable ("PATH", standard_path ? standard_path : ""); + FREE (standard_path); + } + + command = make_bare_simple_command (); + command->value.Simple->words = (WORD_LIST *)copy_word_list (list); + command->value.Simple->redirects = (REDIRECT *)NULL; + command->flags |= (CMD_NO_FUNCTIONS | CMD_INHIBIT_EXPANSION); + command->value.Simple->flags |= (CMD_NO_FUNCTIONS | CMD_INHIBIT_EXPANSION); +#if 0 + /* This breaks for things like ( cd /tmp ; command z ababa ; echo next ) + or $(command echo a ; command echo b;) or even + { command echo a; command echo b; } & */ + /* If we're in a subshell, see if we can get away without forking + again, since we've already forked to run this builtin. */ + if (subshell_environment) + { + command->flags |= CMD_NO_FORK; + command->value.Simple->flags |= CMD_NO_FORK; + } +#endif + add_unwind_protect ((char *)dispose_command, command); + result = execute_command (command); run_unwind_frame ("command_builtin"); @@ -158,7 +172,7 @@ restore_path (var) static char * get_standard_path () { -#if defined (_CS_PATH) && !defined (hpux_7) && !defined (NetBSD) +#if defined (_CS_PATH) && defined (HAVE_CONFSTR) char *p; size_t len; @@ -167,11 +181,11 @@ get_standard_path () *p = '\0'; confstr (_CS_PATH, p, len); return (p); -#else /* !_CSPATH || hpux_7 || NetBSD */ +#else /* !_CSPATH || !HAVE_CONFSTR */ # if defined (CS_PATH) return (savestring (CS_PATH)); # else return (savestring (STANDARD_UTILS_PATH)); # endif /* !CS_PATH */ -#endif /* !_CS_PATH || hpux_7 */ +#endif /* !_CS_PATH || !HAVE_CONFSTR */ } diff --git a/builtins/common.c b/builtins/common.c index ff940b5..2936b88 100644 --- a/builtins/common.c +++ b/builtins/common.c @@ -16,27 +16,37 @@ with Bash; see the file COPYING. If not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include + +#if defined (HAVE_UNISTD_H) +# include +#endif + #include #include #include "../posixstat.h" -#if defined (HAVE_VFPRINTF) -#include -#endif /* VFPRINTF */ +#include + +#if defined (PREFER_STDARG) +# include +#else +# if defined (PREFER_VARARGS) +# include +# endif +#endif -#if defined (HAVE_STRING_H) -# include -#else /* !HAVE_STRING_H */ -# include -#endif /* !HAVE_STRING_H */ +#include "../bashansi.h" #include "../shell.h" -#include "../unwind_prot.h" #include "../maxpath.h" +#include "../flags.h" #include "../jobs.h" #include "../builtins.h" #include "../input.h" #include "../execute_cmd.h" +#include "../trap.h" #include "hashcom.h" +#include "bashgetopt.h" #include "common.h" #include @@ -45,91 +55,57 @@ #endif extern int no_symbolic_links, interactive, interactive_shell; -extern int indirection_level, startup_state; +extern int indirection_level, startup_state, subshell_environment; +extern int line_number; extern int last_command_exit_value; -extern int hashing_disabled; +extern int running_trap; +extern int hashing_enabled; extern int variable_context; +extern int posixly_correct; extern char *this_command_name, *shell_name; extern COMMAND *global_command; extern HASH_TABLE *hashed_filenames; +extern char *bash_getcwd_errstr; -/* Read a numeric arg for this_command_name, the name of the shell builtin - that wants it. LIST is the word list that the arg is to come from. */ -int -get_numeric_arg (list) - WORD_LIST *list; -{ - int count = 1; - - if (list) - { - register char *arg; - int sign = 1; - - arg = list->word->word; - if (!arg) - goto bad_number; - - /* Skip optional leading white space. */ - while (whitespace (*arg)) - arg++; - - if (!*arg) - goto bad_number; - - /* We allow leading `-' or `+'. */ - if (*arg == '-' || *arg == '+') - { - if (!digit (arg[1])) - goto bad_number; - - if (*arg == '-') - sign = -1; - - arg++; - } - - for (count = 0; digit (*arg); arg++) - count = (count * 10) + digit_value (*arg); - - /* Skip trailing whitespace, if any. */ - while (whitespace (*arg)) - arg++; - - if (!*arg) - count = count * sign; - else - { - bad_number: - builtin_error ("bad non-numeric arg `%s'", list->word->word); - throw_to_top_level (); - } - no_args (list->next); - } - return (count); -} +/* **************************************************************** */ +/* */ +/* Error reporting, usage, and option processing */ +/* */ +/* **************************************************************** */ /* This is a lot like report_error (), but it is for shell builtins instead of shell control structures, and it won't ever exit the shell. */ -#if defined (HAVE_VFPRINTF) +#if defined (USE_VARARGS) void -builtin_error (va_alist) +#if defined (PREFER_STDARG) +builtin_error (const char *format, ...) +#else +builtin_error (format, va_alist) + const char *format; va_dcl +#endif { - char *format; va_list args; + char *name; + + name = get_name_for_error (); + fprintf (stderr, "%s: ", name); if (this_command_name && *this_command_name) fprintf (stderr, "%s: ", this_command_name); +#if defined (PREFER_STDARG) + va_start (args, format); +#else va_start (args); - format = va_arg (args, char *); +#endif + vfprintf (stderr, format, args); va_end (args); fprintf (stderr, "\n"); } -#else /* !HAVE_VFPRINTF */ +#else /* !USE_VARARGS */ void builtin_error (format, arg1, arg2, arg3, arg4, arg5) char *format, *arg1, *arg2, *arg3, *arg4, *arg5; @@ -141,7 +117,75 @@ builtin_error (format, arg1, arg2, arg3, arg4, arg5) fprintf (stderr, "\n"); fflush (stderr); } -#endif /* !HAVE_VFPRINTF */ +#endif /* !USE_VARARGS */ + +/* Print a usage summary for the currently-executing builtin command. */ +void +builtin_usage () +{ + if (this_command_name && *this_command_name) + fprintf (stderr, "%s: usage: ", this_command_name); + fprintf (stderr, "%s\n", current_builtin->short_doc); + fflush (stderr); +} + +/* Return if LIST is NULL else barf and jump to top_level. Used by some + builtins that do not accept arguments. */ +void +no_args (list) + WORD_LIST *list; +{ + if (list) + { + builtin_error ("too many arguments"); + jump_to_top_level (DISCARD); + } +} + +/* Function called when one of the builtin commands detects a bad + option. */ +void +bad_option (s) + char *s; +{ + builtin_error ("unknown option: %s", s); +} + +/* Check that no options were given to the currently-executing builtin, + and return 0 if there were options. */ +int +no_options (list) + WORD_LIST *list; +{ + reset_internal_getopt (); + if (internal_getopt (list, "") != -1) + { + builtin_usage (); + return (1); + } + return (0); +} + +/* **************************************************************** */ +/* */ +/* Shell positional parameter manipulation */ +/* */ +/* **************************************************************** */ + +/* Convert a WORD_LIST into a C-style argv. Return the number of elements + in the list in *IP, if IP is non-null. A convenience function for + loadable builtins; also used by `test'. */ +char ** +make_builtin_argv (list, ip) + WORD_LIST *list; + int *ip; +{ + char **argv; + + argv = word_list_to_argv (list, 0, 1, ip); + argv[0] = this_command_name; + return argv; +} /* Remember LIST in $0 ... $9, and REST_OF_ARGS. If DESTRUCTIVE is non-zero, then discard whatever the existing arguments are, else @@ -155,7 +199,7 @@ remember_args (list, destructive) for (i = 1; i < 10; i++) { - if (destructive && dollar_vars[i]) + if ((destructive || list) && dollar_vars[i]) { free (dollar_vars[i]); dollar_vars[i] = (char *)NULL; @@ -163,9 +207,6 @@ remember_args (list, destructive) if (list) { - if (!destructive && dollar_vars[i]) - free (dollar_vars[i]); - dollar_vars[i] = savestring (list->word->word); list = list->next; } @@ -184,142 +225,15 @@ remember_args (list, destructive) set_dollar_vars_changed (); } -/* Return if LIST is NULL else barf and jump to top_level. */ -void -no_args (list) - WORD_LIST *list; -{ - if (list) - { - builtin_error ("extra arguments"); - longjmp (top_level, DISCARD); - } -} - -/* Return the octal number parsed from STRING, or -1 to indicate - that the string contained a bad number. */ -int -read_octal (string) - char *string; -{ - int result = 0; - int digits = 0; - - while (*string && *string >= '0' && *string < '8') - { - digits++; - result = (result * 8) + *string++ - '0'; - } - - if (!digits || result > 0777 || *string) - result = -1; - - return (result); -} - -/* Temporary static. */ -static char *dotted_filename = (char *)NULL; - -/* Return the full pathname that FILENAME hashes to. If FILENAME - is hashed, but data->check_dot is non-zero, check ./FILENAME - and return that if it is executable. */ -char * -find_hashed_filename (filename) - char *filename; -{ - register BUCKET_CONTENTS *item; - - if (hashing_disabled) - return ((char *)NULL); - - item = find_hash_item (filename, hashed_filenames); - - if (item) - { - /* If this filename is hashed, but `.' comes before it in the path, - then see if `./filename' is an executable. */ - if (pathdata(item)->check_dot) - { - if (dotted_filename) - free (dotted_filename); - - dotted_filename = (char *)xmalloc (3 + strlen (filename)); - strcpy (dotted_filename, "./"); - strcat (dotted_filename, filename); - - if (executable_file (dotted_filename)) - return (dotted_filename); - - /* Watch out. If this file was hashed to "./filename", and - "./filename" is not executable, then return NULL. */ - - /* Since we already know "./filename" is not executable, what - we're really interested in is whether or not the `path' - portion of the hashed filename is equivalent to the current - directory, but only if it starts with a `.'. (This catches - ./. and so on.) same_file () is in execute_cmd.c; it tests - general Unix file equivalence -- same device and inode. */ - { - char *path = pathdata (item)->path; - - if (*path == '.') - { - int same = 0; - char *tail; - - tail = (char *) strrchr (path, '/'); - - if (tail) - { - *tail = '\0'; - same = same_file - (".", path, (struct stat *)NULL, (struct stat *)NULL); - *tail = '/'; - } - if (same) - return ((char *)NULL); - } - } - } - return (pathdata (item)->path); - } - else - return ((char *)NULL); -} - -/* Remove FILENAME from the table of hashed commands. */ -void -remove_hashed_filename (filename) - char *filename; -{ - register BUCKET_CONTENTS *item; - - if (hashing_disabled) - return; - - item = remove_hash_item (filename, hashed_filenames); - if (item) - { - if (item->data) - { - free (pathdata(item)->path); - free (item->data); - } - if (item->key) - free (item->key); - free (item); - } -} - /* **************************************************************** */ /* */ -/* Pushing and Popping a Context */ +/* Pushing and Popping variable contexts */ /* */ /* **************************************************************** */ static WORD_LIST **dollar_arg_stack = (WORD_LIST **)NULL; -static int dollar_arg_stack_slots = 0; -static int dollar_arg_stack_index = 0; +static int dollar_arg_stack_slots; +static int dollar_arg_stack_index; void push_context () @@ -346,15 +260,15 @@ push_dollar_vars () xrealloc (dollar_arg_stack, (dollar_arg_stack_slots += 10) * sizeof (WORD_LIST **)); } - dollar_arg_stack[dollar_arg_stack_index] = list_rest_of_args (); - dollar_arg_stack[++dollar_arg_stack_index] = (WORD_LIST *)NULL; + dollar_arg_stack[dollar_arg_stack_index++] = list_rest_of_args (); + dollar_arg_stack[dollar_arg_stack_index] = (WORD_LIST *)NULL; } /* Restore the positional parameters from our stack. */ void pop_dollar_vars () { - if (!dollar_arg_stack || !dollar_arg_stack_index) + if (!dollar_arg_stack || dollar_arg_stack_index == 0) return; remember_args (dollar_arg_stack[--dollar_arg_stack_index], 1); @@ -365,17 +279,18 @@ pop_dollar_vars () void dispose_saved_dollar_vars () { - if (!dollar_arg_stack || !dollar_arg_stack_index) + if (!dollar_arg_stack || dollar_arg_stack_index == 0) return; dispose_words (dollar_arg_stack[dollar_arg_stack_index]); dollar_arg_stack[dollar_arg_stack_index] = (WORD_LIST *)NULL; } -static int changed_dollar_vars = 0; +static int changed_dollar_vars; /* Have the dollar variables been reset to new values since we last checked? */ +int dollar_vars_changed () { return (changed_dollar_vars); @@ -390,18 +305,141 @@ set_dollar_vars_unchanged () void set_dollar_vars_changed () { - changed_dollar_vars = 1; + changed_dollar_vars = 1; } -/* Function called when one of the builtin commands detects a bad - option. */ -void -bad_option (s) - char *s; +/* **************************************************************** */ +/* */ +/* Validating numeric input and arguments */ +/* */ +/* **************************************************************** */ + +/* Read a numeric arg for this_command_name, the name of the shell builtin + that wants it. LIST is the word list that the arg is to come from. + Accept only the numeric argument; report an error if other arguments + follow. */ +int +get_numeric_arg (list) + WORD_LIST *list; { - builtin_error ("unknown option: %s", s); + long count = 1; + + if (list) + { + register char *arg; + + arg = list->word->word; + if (!arg || (legal_number (arg, &count) == 0)) + { + builtin_error ("bad non-numeric arg `%s'", list->word->word); + throw_to_top_level (); + } + no_args (list->next); + } + return (count); +} + +/* Return the octal number parsed from STRING, or -1 to indicate + that the string contained a bad number. */ +int +read_octal (string) + char *string; +{ + int result, digits; + + result = digits = 0; + while (*string && *string >= '0' && *string < '8') + { + digits++; + result = (result * 8) + *string++ - '0'; + } + + if (!digits || result > 0777 || *string) + result = -1; + + return (result); +} + +/* **************************************************************** */ +/* */ +/* Command name hashing */ +/* */ +/* **************************************************************** */ + +/* Return the full pathname that FILENAME hashes to. If FILENAME + is hashed, but (data->flags & HASH_CHKDOT) is non-zero, check + ./FILENAME and return that if it is executable. */ +char * +find_hashed_filename (filename) + char *filename; +{ + register BUCKET_CONTENTS *item; + char *path, *dotted_filename, *tail; + int same; + + if (hashing_enabled == 0) + return ((char *)NULL); + + item = find_hash_item (filename, hashed_filenames); + + if (item == NULL) + return ((char *)NULL); + + /* If this filename is hashed, but `.' comes before it in the path, + see if ./filename is executable. If the hashed value is not an + absolute pathname, see if ./`hashed-value' exists. */ + path = pathdata(item)->path; + if (pathdata(item)->flags & (HASH_CHKDOT|HASH_RELPATH)) + { + tail = (pathdata(item)->flags & HASH_RELPATH) ? path : filename; + dotted_filename = xmalloc (3 + strlen (tail)); + dotted_filename[0] = '.'; dotted_filename[1] = '/'; + strcpy (dotted_filename + 2, tail); + + if (executable_file (dotted_filename)) + return (dotted_filename); + + free (dotted_filename); + +#if 0 + if (pathdata(item)->flags & HASH_RELPATH) + return ((char *)NULL); +#endif + + /* Watch out. If this file was hashed to "./filename", and + "./filename" is not executable, then return NULL. */ + + /* Since we already know "./filename" is not executable, what + we're really interested in is whether or not the `path' + portion of the hashed filename is equivalent to the current + directory, but only if it starts with a `.'. (This catches + ./. and so on.) same_file () tests general Unix file + equivalence -- same device and inode. */ + if (*path == '.') + { + same = 0; + tail = (char *)strrchr (path, '/'); + + if (tail) + { + *tail = '\0'; + same = same_file (".", path, (struct stat *)NULL, (struct stat *)NULL); + *tail = '/'; + } + + return same ? (char *)NULL : path; + } + } + + return (path); } +/* **************************************************************** */ +/* */ +/* Manipulating the current working directory */ +/* */ +/* **************************************************************** */ + /* Return a consed string which is the current working directory. FOR_WHOM is the name of the caller for error printing. */ char *the_current_working_directory = (char *)NULL; @@ -410,6 +448,8 @@ char * get_working_directory (for_whom) char *for_whom; { + char *directory; + if (no_symbolic_links) { if (the_current_working_directory) @@ -418,21 +458,18 @@ get_working_directory (for_whom) the_current_working_directory = (char *)NULL; } - if (!the_current_working_directory) + if (the_current_working_directory == 0) { - char *directory; - - the_current_working_directory = xmalloc (MAXPATHLEN); - directory = getwd (the_current_working_directory); - if (!directory) + the_current_working_directory = xmalloc (PATH_MAX); + the_current_working_directory[0] = '\0'; + directory = getcwd (the_current_working_directory, PATH_MAX); + if (directory == 0) { - if (for_whom && *for_whom) - fprintf (stderr, "%s: ", for_whom); - else - fprintf (stderr, "%s: ", get_name_for_error ()); - - fprintf (stderr, "could not get current directory: %s\n", - the_current_working_directory); + fprintf (stderr, "%s: could not get current directory: %s\n", + (for_whom && *for_whom) ? for_whom : get_name_for_error (), + the_current_working_directory[0] + ? the_current_working_directory + : bash_getcwd_errstr); free (the_current_working_directory); the_current_working_directory = (char *)NULL; @@ -448,35 +485,43 @@ void set_working_directory (name) char *name; { - if (the_current_working_directory) - free (the_current_working_directory); - + FREE (the_current_working_directory); the_current_working_directory = savestring (name); } +/* **************************************************************** */ +/* */ +/* Job control support functions */ +/* */ +/* **************************************************************** */ + #if defined (JOB_CONTROL) /* Return the job spec found in LIST. */ +int get_job_spec (list) WORD_LIST *list; { register char *word; - int job = NO_JOB; - int substring = 0; + int job, substring; - if (!list) + if (list == 0) return (current_job); word = list->word->word; - if (!*word) + if (*word == '\0') return (current_job); if (*word == '%') word++; - if (digit (*word) && (sscanf (word, "%d", &job) == 1)) - return (job - 1); + if (digit (*word) && all_digits (word)) + { + job = atoi (word); + return (job - 1); + } + substring = 0; switch (*word) { case 0: @@ -490,21 +535,24 @@ get_job_spec (list) case '?': /* Substring search requested. */ substring++; word++; - goto find_string; + /* FALLTHROUGH */ default: - find_string: { - register int i, wl = strlen (word); + register int i, wl; + + job = NO_JOB; + wl = strlen (word); for (i = 0; i < job_slots; i++) { if (jobs[i]) { - register PROCESS *p = jobs[i]->pipe; + register PROCESS *p; + p = jobs[i]->pipe; do { if ((substring && strindex (p->command, word)) || - (strncmp (p->command, word, wl) == 0)) + (STREQN (p->command, word, wl))) if (job != NO_JOB) { builtin_error ("ambigious job spec: %s", word); @@ -524,171 +572,100 @@ get_job_spec (list) } #endif /* JOB_CONTROL */ -int parse_and_execute_level = 0; - -/* How to force parse_and_execute () to clean up after itself. */ -void -parse_and_execute_cleanup () -{ - run_unwind_frame ("parse_and_execute_top"); -} - -/* Parse and execute the commands in STRING. Returns whatever - execute_command () returns. This frees STRING. INTERACT is - the new value for `interactive' while the commands are being - executed. A value of -1 means don't change it. */ int -parse_and_execute (string, from_file, interact) - char *string; - char *from_file; - int interact; +display_signal_list (list, forcecols) + WORD_LIST *list; + int forcecols; { - int last_result = EXECUTION_SUCCESS; - int code = 0, jump_to_top_level = 0; - char *orig_string = string; - - /* Unwind protect this invocation of parse_and_execute (). */ - begin_unwind_frame ("parse_and_execute_top"); - unwind_protect_int (parse_and_execute_level); - unwind_protect_jmp_buf (top_level); - unwind_protect_int (indirection_level); - if (interact != -1 && interactive != interact) - unwind_protect_int (interactive); + register int i, column; + char *name; + int result; + long signum; -#if defined (HISTORY) - if (interactive_shell) + result = EXECUTION_SUCCESS; + if (!list) { - unwind_protect_int (remember_on_history); -# if defined (BANG_HISTORY) - unwind_protect_int (history_expansion_inhibited); -# endif /* BANG_HISTORY */ - } -#endif /* HISTORY */ - - add_unwind_protect (pop_stream, (char *)NULL); - if (orig_string) - add_unwind_protect (xfree, orig_string); - end_unwind_frame (); - - parse_and_execute_level++; - push_stream (); - indirection_level++; - if (interact != -1) - interactive = interact; - -#if defined (HISTORY) - /* We don't remember text read by the shell this way on - the history list, and we don't use !$ in shell scripts. */ - remember_on_history = 0; -# if defined (BANG_HISTORY) - history_expansion_inhibited = 1; -# endif /* BANG_HISTORY */ -#endif /* HISTORY */ - - with_input_from_string (string, from_file); - { - COMMAND *command; - - while (*(bash_input.location.string)) - { - if (interrupt_state) - { - last_result = EXECUTION_FAILURE; - break; - } - - /* Provide a location for functions which `longjmp (top_level)' to - jump to. This prevents errors in substitution from restarting - the reader loop directly, for example. */ - code = setjmp (top_level); - - if (code) - { - jump_to_top_level = 0; - switch (code) - { - case FORCE_EOF: - case EXITPROG: - run_unwind_frame ("pe_dispose"); - /* Remember to call longjmp (top_level) after the old - value for it is restored. */ - jump_to_top_level = 1; - goto out; - - case DISCARD: - dispose_command (command); - run_unwind_frame ("pe_dispose"); - last_command_exit_value = 1; - continue; - - default: - programming_error ("bad jump to top_level: %d", code); - break; - } - } - - if (parse_command () == 0) - { - if ((command = global_command) != (COMMAND *)NULL) - { - struct fd_bitmap *bitmap; - - bitmap = new_fd_bitmap (FD_BITMAP_SIZE); - begin_unwind_frame ("pe_dispose"); - add_unwind_protect (dispose_fd_bitmap, bitmap); - - global_command = (COMMAND *)NULL; - -#if defined (ONESHOT) - if (startup_state == 2 && *bash_input.location.string == '\0' && - command->type == cm_simple && !command->redirects && - !command->value.Simple->redirects) - { - command->flags |= CMD_NO_FORK; - command->value.Simple->flags |= CMD_NO_FORK; - } -#endif /* ONESHOT */ - - last_result = execute_command_internal - (command, 0, NO_PIPE, NO_PIPE, bitmap); - - dispose_command (command); - run_unwind_frame ("pe_dispose"); - } - } - else - { - last_result = EXECUTION_FAILURE; - - /* Since we are shell compatible, syntax errors in a script - abort the execution of the script. Right? */ - break; - } - } - } + for (i = 1, column = 0; i < NSIG; i++) + { + name = signal_name (i); + if (STREQN (name, "SIGJUNK", 7) || STREQN (name, "Unknown", 7)) + continue; - out: + if (posixly_correct && !forcecols) + printf ("%s%s", name, (i == NSIG - 1) ? "" : " "); + else + { + printf ("%2d) %s", i, name); + + if (++column < 4) + printf ("\t"); + else + { + printf ("\n"); + column = 0; + } + } + } - run_unwind_frame ("parse_and_execute_top"); + if ((posixly_correct && !forcecols) || column != 0) + printf ("\n"); + return result; + } - if (interrupt_state && parse_and_execute_level == 0) + /* List individual signal names or numbers. */ + while (list) { - /* An interrupt during non-interactive execution in an - interactive shell (e.g. via $PROMPT_COMMAND) should - not cause the shell to exit. */ - interactive = interactive_shell; - throw_to_top_level (); + if (legal_number (list->word->word, &signum)) + { + /* This is specified by Posix.2 so that exit statuses can be + mapped into signal numbers. */ + if (signum > 128) + signum -= 128; + if (signum < 0 || signum >= NSIG) + { + builtin_error ("bad signal number: %s", list->word->word); + result = EXECUTION_FAILURE; + list = list->next; + continue; + } + + name = signal_name (signum); + if (STREQN (name, "SIGJUNK", 7) || STREQN (name, "Unknown", 7)) + { + list = list->next; + continue; + } + printf ("%s\n", name); + } + else + { + signum = decode_signal (list->word->word); + if (signum == NO_SIG) + { + builtin_error ("%s: not a signal specification", list->word->word); + result = EXECUTION_FAILURE; + list = list->next; + continue; + } + printf ("%ld\n", signum); + } + list = list->next; } - - if (jump_to_top_level) - longjmp (top_level, code); - - return (last_result); + return (result); } -/* Return the address of the builtin named NAME. +/* **************************************************************** */ +/* */ +/* Finding builtin commands and their functions */ +/* */ +/* **************************************************************** */ + +/* Perform a binary search and return the address of the builtin function + whose name is NAME. If the function couldn't be found, or the builtin + is disabled or has no function associated with it, return NULL. + Return the address of the builtin. DISABLED_OKAY means find it even if the builtin is disabled. */ -static Function * +struct builtin * builtin_address_internal (name, disabled_okay) char *name; int disabled_okay; @@ -710,40 +687,53 @@ builtin_address_internal (name, disabled_okay) if (j == 0) { /* It must have a function pointer. It must be enabled, or we - must have explicitly allowed disabled functions to be found. */ + must have explicitly allowed disabled functions to be found, + and it must not have been deleted. */ if (shell_builtins[mid].function && + ((shell_builtins[mid].flags & BUILTIN_DELETED) == 0) && ((shell_builtins[mid].flags & BUILTIN_ENABLED) || disabled_okay)) - return (shell_builtins[mid].function); + return (&shell_builtins[mid]); else - return ((Function *)NULL); + return ((struct builtin *)NULL); } if (j > 0) hi = mid - 1; else lo = mid + 1; } - return ((Function *)NULL); + return ((struct builtin *)NULL); } -/* Perform a binary search and return the address of the builtin function - whose name is NAME. If the function couldn't be found, or the builtin - is disabled or has no function associated with it, return NULL. */ +/* Return the pointer to the function implementing builtin command NAME. */ Function * find_shell_builtin (name) - char *name; + char *name; { - return (builtin_address_internal (name, 0)); + current_builtin = builtin_address_internal (name, 0); + return (current_builtin ? current_builtin->function : (Function *)NULL); } -/* Return the address of builtin with NAME, irregardless of its state of - enableness. */ +/* Return the address of builtin with NAME, whether it is enabled or not. */ Function * builtin_address (name) char *name; { - return (builtin_address_internal (name, 1)); + current_builtin = builtin_address_internal (name, 1); + return (current_builtin ? current_builtin->function : (Function *)NULL); } +/* Return the function implementing the builtin NAME, but only if it is a + POSIX.2 special builtin. */ +Function * +find_special_builtin (name) + char *name; +{ + current_builtin = builtin_address_internal (name, 0); + return ((current_builtin && (current_builtin->flags & SPECIAL_BUILTIN)) ? + current_builtin->function : + (Function *)NULL); +} + static int shell_builtin_compare (sbp1, sbp2) struct builtin *sbp1, *sbp2; @@ -765,49 +755,56 @@ initialize_shell_builtins () shell_builtin_compare); } -/* Return a new string which is the quoted version of STRING. This is used - by alias and trap. */ +/* **************************************************************** */ +/* */ +/* Functions for quoting strings to be re-read as input */ +/* */ +/* **************************************************************** */ + +/* Return a new string which is the single-quoted version of STRING. + Used by alias and trap, among others. */ char * single_quote (string) char *string; { - register int i, j, c; - char *result; - - result = (char *)xmalloc (3 + (3 * strlen (string))); + register int c; + char *result, *r, *s; - result[0] = '\''; + result = (char *)xmalloc (3 + (4 * strlen (string))); + r = result; + *r++ = '\''; - for (i = 0, j = 1; string && (c = string[i]); i++) + for (s = string; s && (c = *s); s++) { - result[j++] = c; + *r++ = c; if (c == '\'') { - result[j++] = '\\'; /* insert escaped single quote */ - result[j++] = '\''; - result[j++] = '\''; /* start new quoted string */ + *r++ = '\\'; /* insert escaped single quote */ + *r++ = '\''; + *r++ = '\''; /* start new quoted string */ } } - result[j++] = '\''; - result[j] = '\0'; + *r++ = '\''; + *r = '\0'; return (result); } +/* Quote STRING using double quotes. Return a new string. */ char * double_quote (string) char *string; { - register int i, j, c; - char *result; - - result = (char *)xmalloc (3 + (3 * strlen (string))); + register int c; + char *result, *r, *s; - result[0] = '"'; + result = (char *)xmalloc (3 + (2 * strlen (string))); + r = result; + *r++ = '"'; - for (i = 0, j = 1; string && (c = string[i]); i++) + for (s = string; s && (c = *s); s++) { switch (c) { @@ -815,15 +812,86 @@ double_quote (string) case '$': case '`': case '\\': - result[j++] = '\\'; + *r++ = '\\'; default: - result[j++] = c; + *r++ = c; break; } } - result[j++] = '"'; - result[j] = '\0'; + *r++ = '"'; + *r = '\0'; return (result); } + +/* Quote special characters in STRING using backslashes. Return a new + string. */ +char * +backslash_quote (string) + char *string; +{ + int c; + char *result, *r, *s; + + result = xmalloc (2 * strlen (string) + 1); + + for (r = result, s = string; s && (c = *s); s++) + { + switch (c) + { + case ' ': case '\t': case '\n': /* IFS white space */ + case '\'': case '"': case '\\': /* quoting chars */ + case '|': case '&': case ';': /* shell metacharacters */ + case '(': case ')': case '<': case '>': + case '!': case '{': case '}': /* reserved words */ + case '*': case '[': case '?': case ']': /* globbing chars */ + case '^': + case '$': case '`': /* expansion chars */ + *r++ = '\\'; + *r++ = c; + break; + case '#': /* comment char */ + if (s == string) + *r++ = '\\'; + /* FALLTHROUGH */ + default: + *r++ = c; + break; + } + } + + *r = '\0'; + return (result); +} + +int +contains_shell_metas (string) + char *string; +{ + char *s; + + for (s = string; s && *s; s++) + { + switch (*s) + { + case ' ': case '\t': case '\n': /* IFS white space */ + case '\'': case '"': case '\\': /* quoting chars */ + case '|': case '&': case ';': /* shell metacharacters */ + case '(': case ')': case '<': case '>': + case '!': case '{': case '}': /* reserved words */ + case '*': case '[': case '?': case ']': /* globbing chars */ + case '^': + case '$': case '`': /* expansion chars */ + return (1); + case '#': + if (s == string) /* comment char */ + return (1); + /* FALLTHROUGH */ + default: + break; + } + } + + return (0); +} diff --git a/builtins/common.h b/builtins/common.h index c7c99e7..ce831f7 100644 --- a/builtins/common.h +++ b/builtins/common.h @@ -21,23 +21,23 @@ #if !defined (__COMMON_H) # define __COMMON_H +#include "../stdc.h" + #define ISOPTION(s, c) (s[0] == '-' && !s[2] && s[1] == c) -extern void builtin_error (); +extern void builtin_error __P((const char *, ...)); +extern void builtin_usage (); extern void bad_option (); -extern int get_numeric_arg (); +extern char **make_builtin_argv (); +extern int get_numeric_arg (); extern void remember_args (); - extern void no_args (); +extern int no_options (); extern int read_octal (); -extern char *find_hashed_filename (); -extern void remove_hashed_filename (); -extern void remember_filename (); - extern void push_context (), pop_context (); extern void push_dollar_vars (), pop_dollar_vars (); extern void dispose_saved_dollar_vars (); @@ -53,17 +53,55 @@ extern void set_working_directory (); extern int get_job_spec (); #endif -extern int parse_and_execute (); -extern void parse_and_execute_cleanup (); - -extern void initialize_shell_builtins (); +extern int display_signal_list (); /* It's OK to declare a function as returning a Function * without providing a definition of what a `Function' is. */ +extern struct builtin *builtin_address_internal (); extern Function *find_shell_builtin (); extern Function *builtin_address (); +extern Function *find_special_builtin (); + +extern void initialize_shell_builtins (); extern char *single_quote (); extern char *double_quote (); +extern char *backslash_quote (); +extern int contains_shell_metas (); + +/* Functions from hash.def */ +extern void initialize_filename_hashing (); +extern void flush_hashed_filenames (); +extern char *find_hashed_filename (); +extern void remove_hashed_filename (); +extern void remember_filename (); + +/* Functions from set.def */ +extern void initialize_shell_options (); +extern void list_minus_o_opts (); +extern int set_minus_o_option (); +extern int minus_o_option_value (); + +/* Functions from type.def */ +extern int describe_command (); + +/* Functions from setattr.def */ +extern int set_or_show_attributes (); +extern int show_var_attributes (); +extern int show_name_attributes (); +extern void set_var_attribute (); + +/* Functions from pushd.def */ +extern char *get_dirstack_element (); +extern void set_dirstack_element (); +extern WORD_LIST *get_directory_stack (); + +/* Functions from evalstring.c */ +extern int parse_and_execute (); +extern void parse_and_execute_cleanup (); + +/* Functions from evalfile.c */ +extern int maybe_execute_file __P((char *, int)); +extern int source_file __P((char *)); #endif /* !__COMMON_H */ diff --git a/builtins/declare.def b/builtins/declare.def index 17b7ea2..68514d3 100644 --- a/builtins/declare.def +++ b/builtins/declare.def @@ -23,39 +23,50 @@ $PRODUCES declare.c $BUILTIN declare $FUNCTION declare_builtin -$SHORT_DOC declare [-[frxi]] name[=value] ... +$SHORT_DOC declare [-afFrxi] [-p] name[=value] ... Declare variables and/or give them attributes. If no NAMEs are -given, then display the values of variables instead. +given, then display the values of variables instead. The -p option +will display the attributes and values of each NAME. The flags are: - -f to select from among function names only, - -r to make NAMEs readonly, - -x to make NAMEs export, - -i to make NAMEs have the `integer' attribute set. + -a to make NAMEs arrays (if supported) + -f to select from among function names only + -F to display function names without definitions + -r to make NAMEs readonly + -x to make NAMEs export + -i to make NAMEs have the `integer' attribute set Variables with the integer attribute have arithmetic evaluation (see `let') done when the variable is assigned to. +When displaying values of variables, -f displays a function's name +and definition. The -F option restricts the display to function +name only. + Using `+' instead of `-' turns off the given attribute instead. When used in a function, makes NAMEs local, as with the `local' command. $END $BUILTIN typeset $FUNCTION declare_builtin -$SHORT_DOC typeset [-[frxi]] name[=value] ... +$SHORT_DOC typeset [-afFrxi] [-p] name[=value] ... Obsolete. See `declare'. $END +#include + +#if defined (HAVE_UNISTD_H) +# include +#endif + #include -#if defined (HAVE_STRING_H) -# include -#else /* !HAVE_STRING_H */ -# include -#endif /* !HAVE_STRING_H */ +#include "../bashansi.h" #include "../shell.h" +#include "common.h" +#include "builtext.h" extern int variable_context, array_needs_making; @@ -84,7 +95,7 @@ local_builtin (list) return (declare_internal (list, 1)); else { - builtin_error ("Can only be used in a function"); + builtin_error ("can only be used in a function"); return (EXECUTION_FAILURE); } } @@ -95,14 +106,14 @@ declare_internal (list, local_var) register WORD_LIST *list; int local_var; { - int flags_on = 0, flags_off = 0; - int any_failed = 0; + int flags_on, flags_off, *flags, any_failed, assign_error, pflag, nodefs; + char *t; + SHELL_VAR *var; + flags_on = flags_off = any_failed = assign_error = pflag = nodefs = 0; while (list) { - register char *t = list->word->word; - int *flags; - + t = list->word->word; if (t[0] == '-' && t[1] == '-' && t[2] == '\0') { list = list->next; @@ -112,16 +123,18 @@ declare_internal (list, local_var) if (*t != '+' && *t != '-') break; - if (*t == '+') - flags = &flags_off; - else - flags = &flags_on; - - t++; + flags = (*t++ == '+') ? &flags_off : &flags_on; while (*t) { - if (*t == 'f') + if (*t == 'p' && local_var == 0) + pflag++, t++; + else if (*t == 'F') + { + nodefs++; + *flags |= att_function; t++; + } + else if (*t == 'f') *flags |= att_function, t++; else if (*t == 'x') *flags |= att_exported, t++, array_needs_making = 1; @@ -129,9 +142,14 @@ declare_internal (list, local_var) *flags |= att_readonly, t++; else if (*t == 'i') *flags |= att_integer, t++; +#if defined (ARRAY_VARS) + else if (*t == 'a') + *flags |= att_array, t++; +#endif else { builtin_error ("unknown option: `-%c'", *t); + builtin_usage (); return (EX_USAGE); } } @@ -141,7 +159,7 @@ declare_internal (list, local_var) /* If there are no more arguments left, then we just want to show some variables. */ - if (!list) + if (list == 0) /* declare -[afFirx] */ { /* Show local variables defined at this context level if this is the `local' builtin. */ @@ -162,25 +180,45 @@ declare_internal (list, local_var) } else { - if (!flags_on) + if (flags_on == 0) set_builtin ((WORD_LIST *)NULL); else - set_or_show_attributes ((WORD_LIST *)NULL, flags_on); + set_or_show_attributes ((WORD_LIST *)NULL, flags_on, nodefs); } fflush (stdout); return (EXECUTION_SUCCESS); } + if (pflag) /* declare -p [-afFirx] name [name...] */ + { + for (any_failed = 0; list; list = list->next) + { + pflag = show_name_attributes (list->word->word, nodefs); + if (pflag) + { + builtin_error ("%s: not found", list->word->word); + any_failed++; + } + } + return (any_failed ? EXECUTION_FAILURE : EXECUTION_SUCCESS); + } + #define NEXT_VARIABLE() free (name); list = list->next; continue /* There are arguments left, so we are making variables. */ - while (list) + while (list) /* declare [-afFirx] name [name ...] */ { - char *value, *name = savestring (list->word->word); - int offset = assignment (name); + char *value, *name; + int offset; +#if defined (ARRAY_VARS) + int making_array_special, assigning_array_special; +#endif + + name = savestring (list->word->word); + offset = assignment (name); - if (offset) + if (offset) /* declare [-afFirx] name=value */ { name[offset] = '\0'; value = name + offset + 1; @@ -188,10 +226,21 @@ declare_internal (list, local_var) else value = ""; +#if defined (ARRAY_VARS) + assigning_array_special = 0; + if (t = strchr (name, '[')) + { + *t = '\0'; + making_array_special = 1; + } + else + making_array_special = 0; +#endif + if (legal_identifier (name) == 0) { - builtin_error ("%s: not a legal variable name", name); - any_failed++; + builtin_error ("`%s': not a valid identifier", name); + assign_error++; NEXT_VARIABLE (); } @@ -200,7 +249,14 @@ declare_internal (list, local_var) not global ones. */ if (variable_context) - make_local_variable (name); + { +#if defined (ARRAY_VARS) + if ((flags_on & att_array) || making_array_special) + make_local_array_variable (name); + else +#endif + make_local_variable (name); + } /* If we are declaring a function, then complain about it in some way. We don't let people make functions by saying `typeset -f foo=bar'. */ @@ -210,36 +266,35 @@ declare_internal (list, local_var) if (flags_on & att_function) { - if (offset) + if (offset) /* declare -f [-rix] foo=bar */ { builtin_error ("Can't use `-f' to make functions"); return (EXECUTION_FAILURE); } - else + else /* declare -f [-rx] name [name...] */ { - SHELL_VAR *find_function (), *funvar; - - funvar = find_function (name); + var = find_function (name); - if (funvar) + if (var) { - if (readonly_p (funvar) && (flags_off & att_readonly)) + if (readonly_p (var) && (flags_off & att_readonly)) { builtin_error ("%s: readonly function", name); any_failed++; NEXT_VARIABLE (); } + /* declare -[Ff] name [name...] */ if (flags_on == att_function && flags_off == 0) { - char *result = named_function_string - (name, (COMMAND *)function_cell (funvar), 1); - printf ("%s\n", result); + t = nodefs ? var->name + : named_function_string (name, function_cell (var), 1); + printf ("%s\n", t); } - else + else /* declare -[fF] -[rx] name [name...] */ { - funvar->attributes |= flags_on; - funvar->attributes &= ~flags_off; + var->attributes |= flags_on; + var->attributes &= ~flags_off; } } else @@ -247,15 +302,21 @@ declare_internal (list, local_var) NEXT_VARIABLE (); } } - else + else /* declare -[airx] name [name...] */ { - SHELL_VAR *var; - var = find_variable (name); - if (!var) - var = bind_variable (name, ""); + if (var == 0) + { +#if defined (ARRAY_VARS) + if ((flags_on & att_array) || making_array_special) + var = make_new_array_variable (name); + else +#endif + var = bind_variable (name, ""); + } + /* Cannot use declare +r to turn off readonly attribute. */ if (readonly_p (var) && (flags_off & att_readonly)) { builtin_error ("%s: readonly variable", name); @@ -263,22 +324,55 @@ declare_internal (list, local_var) NEXT_VARIABLE (); } + /* Cannot use declare to assign value to readonly variable. */ + if (readonly_p (var) && offset) + { + builtin_error ("%s: readonly variable", name); + assign_error++; + NEXT_VARIABLE (); + } + +#if defined (ARRAY_VARS) + /* declare -a name=value does not work; declare name=value when + name is already an array does not work. */ + if ((making_array_special || (flags_on & att_array) || array_p (var)) && offset) + { + if (value[0] == '(' && strchr (value, ')')) + assigning_array_special = 1; + else + { + builtin_error ("%s: cannot assign to array variables in this way", name); + assign_error++; + NEXT_VARIABLE (); + } + } + + /* Cannot use declare +a name to remove an array variable. */ + if ((flags_off & att_array) && array_p (var)) + { + builtin_error ("%s: cannot destroy array variables in this way", name); + any_failed++; + NEXT_VARIABLE (); + } + + /* declare -a name makes name an array variable. */ + if ((making_array_special || (flags_on & att_array)) && array_p (var) == 0) + var = convert_var_to_array (var); +#endif /* ARRAY_VARS */ + var->attributes |= flags_on; var->attributes &= ~flags_off; +#if defined (ARRAY_VARS) + if (offset && assigning_array_special) + assign_array_var_from_string (var, value); + else +#endif if (offset) { - free (var->value); - if (integer_p (var)) - { - long val, evalexp (); - char *itos (); - - val = evalexp (value); - var->value = itos ((int)val); - } - else - var->value = savestring (value); + t = make_variable_value (var, value); + FREE (var->value); + var->value = t; } } @@ -286,5 +380,8 @@ declare_internal (list, local_var) NEXT_VARIABLE (); } - return (any_failed ? EXECUTION_FAILURE : EXECUTION_SUCCESS); + + return (assign_error ? EX_BADASSIGN + : ((any_failed == 0) ? EXECUTION_SUCCESS + : EXECUTION_FAILURE)); } diff --git a/builtins/echo.def b/builtins/echo.def index 7539103..74ca0f4 100644 --- a/builtins/echo.def +++ b/builtins/echo.def @@ -20,6 +20,12 @@ with Bash; see the file COPYING. If not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. $PRODUCES echo.c +#include + +#if defined (HAVE_UNISTD_H) +# include +#endif + #include #include "../shell.h" @@ -33,6 +39,7 @@ following backslash-escaped characters is turned on: \a alert (bell) \b backspace \c suppress trailing newline + \E escape character \f form feed \n new line \r carriage return @@ -60,109 +67,91 @@ $END /* Print the words in LIST to standard output. If the first word is `-n', then don't print a trailing newline. We also support the - echo syntax from Version 9 unix systems. */ + echo syntax from Version 9 Unix systems. */ +int echo_builtin (list) WORD_LIST *list; { - int display_return = 1, do_v9 = 0; + int display_return, do_v9, i; + char *temp; #if defined (DEFAULT_ECHO_TO_USG) /* System V machines already have a /bin/sh with a v9 behaviour. We give Bash the identical behaviour for these machines so that the existing system shells won't barf. */ do_v9 = 1; +#else + do_v9 = 0; #endif /* DEFAULT_ECHO_TO_USG */ - while (list && list->word->word[0] == '-') - { - register char *temp; - register int i; + display_return = 1; + for (; list && (temp = list->word->word) && *temp == '-'; list = list->next) + { /* If it appears that we are handling options, then make sure that all of the options specified are actually valid. Otherwise, the string should just be echoed. */ - temp = &(list->word->word[1]); + temp++; for (i = 0; temp[i]; i++) { if (strchr (VALID_ECHO_OPTIONS, temp[i]) == 0) - goto just_echo; + break; } - if (!*temp) - goto just_echo; + /* echo - and echo - both mean to just echo the arguments. */ + if (*temp == 0 || temp[i]) + break; /* All of the options in TEMP are valid options to ECHO. Handle them. */ - while (*temp) + while (i = *temp++) { - if (*temp == 'n') - display_return = 0; + switch (i) + { + case 'n': + display_return = 0; + break; #if defined (V9_ECHO) - else if (*temp == 'e') - do_v9 = 1; - else if (*temp == 'E') - do_v9 = 0; + case 'e': + do_v9 = 1; + break; + case 'E': + do_v9 = 0; + break; #endif /* V9_ECHO */ - else - goto just_echo; - - temp++; + default: + goto just_echo; /* XXX */ + } } - list = list->next; } just_echo: - if (list) + while (list) { -#if defined (V9_ECHO) - if (do_v9) + i = 0; + temp = do_v9 ? ansicstr (list->word->word, STRLEN (list->word->word), &i) + : list->word->word; + if (temp) { - while (list) - { - register char *s = list->word->word; - register int c; - - while (c = *s++) - { - if (c == '\\' && *s) - { - switch (c = *s++) - { - case 'a': c = '\007'; break; - case 'b': c = '\b'; break; - case 'c': display_return = 0; continue; - case 'f': c = '\f'; break; - case 'n': c = '\n'; break; - case 'r': c = '\r'; break; - case 't': c = '\t'; break; - case 'v': c = (int) 0x0B; break; - case '0': case '1': case '2': case '3': - case '4': case '5': case '6': case '7': - c -= '0'; - if (*s >= '0' && *s <= '7') - c = c * 8 + (*s++ - '0'); - if (*s >= '0' && *s <= '7') - c = c * 8 + (*s++ - '0'); - break; - case '\\': break; - default: putchar ('\\'); break; - } - } - putchar(c); - } - list = list->next; - if (list) - putchar(' '); - } + printf ("%s", temp); + fflush (stdout); /* Fix for bug in SunOS 5.5 printf(3) */ } - else -#endif /* V9_ECHO */ - print_word_list (list, " "); + if (do_v9 && temp) + free (temp); + list = list->next; + if (i) + { + display_return = 0; + break; + } + if (list) + putchar(' '); } + if (display_return) - printf ("\n"); + putchar ('\n'); fflush (stdout); return (EXECUTION_SUCCESS); } diff --git a/builtins/enable.def b/builtins/enable.def index 2aeae39..37c4f2b 100644 --- a/builtins/enable.def +++ b/builtins/enable.def @@ -23,20 +23,54 @@ $PRODUCES enable.c $BUILTIN enable $FUNCTION enable_builtin -$SHORT_DOC enable [-n] [name ...] +$SHORT_DOC enable [-pnds] [-a] [-f filename] [name ...] Enable and disable builtin shell commands. This allows you to use a disk command which has the same name as a shell -builtin. If -n is used, the NAMEs become disabled. Otherwise +builtin. If -n is used, the NAMEs become disabled; otherwise NAMEs are enabled. For example, to use the `test' found on your -path instead of the shell builtin version, you type `enable -n test'. +path instead of the shell builtin version, type `enable -n test'. +On systems supporting dynamic loading, the -f option may be used +to load new builtins from the shared object FILENAME. The -d +option will delete a builtin previously loaded with -f. If no +non-option names are given, or the -p option is supplied, a list +of builtins is printed. The -a option means to print every builtin +with an indication of whether or not it is enabled. The -s option +restricts the output to the Posix.2 `special' builtins. The -n +option displays a list of all disabled builtins. $END +#include + +#if defined (HAVE_UNISTD_H) +# include +#endif + +#include +#include "../bashansi.h" #include "../shell.h" #include "../builtins.h" +#include "../flags.h" #include "common.h" +#include "bashgetopt.h" + +#if defined (HAVE_DLOPEN) && defined (HAVE_DLSYM) +static int dyn_load_builtin (); +#endif + +#if defined (HAVE_DLCLOSE) +static int dyn_unload_builtin (); +#endif #define ENABLED 1 #define DISABLED 2 +#define SPECIAL 4 + +#define AFLAG 0x01 +#define DFLAG 0x02 +#define FFLAG 0x04 +#define NFLAG 0x08 +#define PFLAG 0x10 +#define SFLAG 0x20 static int enable_shell_command (); static void list_some_builtins (); @@ -44,61 +78,117 @@ static void list_some_builtins (); /* Enable/disable shell commands present in LIST. If list is not specified, then print out a list of shell commands showing which are enabled and which are disabled. */ +int enable_builtin (list) WORD_LIST *list; { - int result = 0, any_failed = 0; - int disable_p, all_p; + int result, flags; + int opt, filter; +#if defined (HAVE_DLOPEN) && defined (HAVE_DLSYM) + char *filename; +#endif - disable_p = all_p = 0; + result = EXECUTION_SUCCESS; + flags = 0; - while (list && list->word->word && list->word->word[0] == '-') + reset_internal_getopt (); + while ((opt = internal_getopt (list, "adnpsf:")) != -1) { - char *arg = list->word->word; - - list = list->next; - - if (ISOPTION (arg, 'n')) - disable_p = 1; - else if (arg[1] == 'a' && (arg[2] == 0 || strcmp (arg + 2, "ll") == 0)) - all_p = 1; - else if (ISOPTION (arg, '-')) - break; - else + switch (opt) { - bad_option (arg); - return (EXECUTION_FAILURE); + case 'a': + flags |= AFLAG; + break; + case 'n': + flags |= NFLAG; + break; + case 'p': + flags |= PFLAG; + break; + case 's': + flags |= SFLAG; + break; + case 'f': +#if defined (HAVE_DLOPEN) && defined (HAVE_DLSYM) + flags |= FFLAG; + filename = list_optarg; + break; +#else + builtin_error ("dynamic loading not available"); + return (EX_USAGE); +#endif +#if defined (HAVE_DLCLOSE) + case 'd': + flags |= DFLAG; + break; +#else + builtin_error ("dynamic loading not available"); + return (EX_USAGE); +#endif /* HAVE_DLCLOSE */ + default: + builtin_usage (); + return (EX_USAGE); } } - if (!list) + list = loptend; + +#if defined (RESTRICTED_SHELL) + /* Restricted shells cannot load new builtins. */ + if (restricted && (flags & (FFLAG|DFLAG))) { - int filter; + builtin_error ("restricted"); + return (EXECUTION_FAILURE); + } +#endif - if (all_p) - filter = ENABLED | DISABLED; - else if (disable_p) - filter = DISABLED; - else - filter = ENABLED; + if (list == 0 || (flags & PFLAG)) + { + filter = (flags & AFLAG) ? (ENABLED | DISABLED) + : (flags & NFLAG) ? DISABLED : ENABLED; + + if (flags & SFLAG) + filter |= SPECIAL; list_some_builtins (filter); } +#if defined (HAVE_DLOPEN) && defined (HAVE_DLSYM) + else if (flags & FFLAG) + { + filter = (flags & NFLAG) ? DISABLED : ENABLED; + if (flags & SFLAG) + filter |= SPECIAL; + + result = dyn_load_builtin (list, filter, filename); + } +#endif +#if defined (HAVE_DLCLOSE) + else if (flags & DFLAG) + { + while (list) + { + opt = dyn_unload_builtin (list->word->word); + if (opt == EXECUTION_FAILURE) + result = EXECUTION_FAILURE; + list = list->next; + } + } +#endif else { while (list) { - result = enable_shell_command (list->word->word, disable_p); + opt = enable_shell_command (list->word->word, flags & NFLAG); - if (!result) + if (opt == EXECUTION_FAILURE) { builtin_error ("%s: not a shell builtin", list->word->word); - any_failed++; + result = EXECUTION_FAILURE; } list = list->next; } } - return (any_failed ? EXECUTION_FAILURE : EXECUTION_SUCCESS); + return (result); } /* List some builtins. @@ -111,19 +201,18 @@ list_some_builtins (filter) for (i = 0; i < num_shell_builtins; i++) { - if (!shell_builtins[i].function) + if (shell_builtins[i].function == 0 || (shell_builtins[i].flags & BUILTIN_DELETED)) continue; - if ((filter & ENABLED) && - (shell_builtins[i].flags & BUILTIN_ENABLED)) - { - printf ("enable %s\n", shell_builtins[i].name); - } + if ((filter & SPECIAL) && + (shell_builtins[i].flags & SPECIAL_BUILTIN) == 0) + continue; + + if ((filter & ENABLED) && (shell_builtins[i].flags & BUILTIN_ENABLED)) + printf ("enable %s\n", shell_builtins[i].name); else if ((filter & DISABLED) && ((shell_builtins[i].flags & BUILTIN_ENABLED) == 0)) - { - printf ("enable -n %s\n", shell_builtins[i].name); - } + printf ("enable -n %s\n", shell_builtins[i].name); } } @@ -134,23 +223,202 @@ enable_shell_command (name, disable_p) char *name; int disable_p; { - register int i; - int found = 0; + struct builtin *b; - for (i = 0; i < num_shell_builtins; i++) + b = builtin_address_internal (name, 1); + if (b == 0) + return (EXECUTION_FAILURE); + + if (disable_p) + b->flags &= ~BUILTIN_ENABLED; + else + b->flags |= BUILTIN_ENABLED; + + return (EXECUTION_SUCCESS); +} + +#if defined (HAVE_DLOPEN) && defined (HAVE_DLSYM) +#include + +static int +dyn_load_builtin (list, flags, filename) + WORD_LIST *list; + int flags; + char *filename; +{ + WORD_LIST *l; + void *handle; + + int total, size, new, replaced; + char *struct_name, *name; + struct builtin **new_builtins, *b, *new_shell_builtins, *old_builtin; + + if (list == 0) + return (EXECUTION_FAILURE); + +#ifndef RTLD_LAZY +#define RTLD_LAZY 1 +#endif + +#if defined (_AIX) + handle = dlopen (filename, RTLD_NOW|RTLD_GLOBAL); +#else + handle = dlopen (filename, RTLD_LAZY); +#endif /* !_AIX */ + + if (handle == 0) { - if (!shell_builtins[i].function) - continue; + builtin_error ("cannot open shared object %s: %s", filename, dlerror ()); + return (EXECUTION_FAILURE); + } - if (STREQ (name, shell_builtins[i].name)) - { - found++; + for (new = 0, l = list; l; l = l->next, new++) + ; + new_builtins = (struct builtin **)xmalloc (new * sizeof (struct builtin *)); - if (disable_p) - shell_builtins[i].flags &= ~BUILTIN_ENABLED; - else - shell_builtins[i].flags |= BUILTIN_ENABLED; + /* For each new builtin in the shared object, find it and its describing + structure. If this is overwriting an existing builtin, do so, otherwise + save the loaded struct for creating the new list of builtins. */ + for (replaced = new = 0; list; list = list->next) + { + name = list->word->word; + + size = strlen (name); + struct_name = xmalloc (size + 8); + strcpy (struct_name, name); + strcpy (struct_name + size, "_struct"); + + b = (struct builtin *)dlsym (handle, struct_name); + if (b == 0) + { + builtin_error ("cannot find %s in shared object %s: %s", struct_name, + filename, dlerror ()); + free (struct_name); + continue; } + + free (struct_name); + + b->flags &= ~STATIC_BUILTIN; + if (flags & SPECIAL) + b->flags |= SPECIAL_BUILTIN; + b->handle = handle; + + if (old_builtin = builtin_address_internal (name, 1)) + { + replaced++; + FASTCOPY ((char *)b, (char *)old_builtin, sizeof (struct builtin)); + } + else + new_builtins[new++] = b; + } + + if (replaced == 0 && new == 0) + { + free (new_builtins); + dlclose (handle); + return (EXECUTION_FAILURE); } - return (found); + + if (new) + { + total = num_shell_builtins + new; + size = (total + 1) * sizeof (struct builtin); + + new_shell_builtins = (struct builtin *)xmalloc (size); + FASTCOPY ((char *)shell_builtins, (char *)new_shell_builtins, + num_shell_builtins * sizeof (struct builtin)); + for (replaced = 0; replaced < new; replaced++) + FASTCOPY ((char *)new_builtins[replaced], + (char *)&new_shell_builtins[num_shell_builtins + replaced], + sizeof (struct builtin)); + + new_shell_builtins[total].name = (char *)0; + new_shell_builtins[total].function = (Function *)0; + new_shell_builtins[total].flags = 0; + + if (shell_builtins != static_shell_builtins) + free (shell_builtins); + + shell_builtins = new_shell_builtins; + num_shell_builtins = total; + initialize_shell_builtins (); + } + + free (new_builtins); + return (EXECUTION_SUCCESS); +} +#endif + +#if defined (HAVE_DLCLOSE) +static void +delete_builtin (b) + struct builtin *b; +{ + int ind, size; + struct builtin *new_shell_builtins; + + /* XXX - funky pointer arithmetic - XXX */ + ind = ((int)b - (int)shell_builtins) / sizeof (struct builtin); + size = num_shell_builtins * sizeof (struct builtin); + new_shell_builtins = (struct builtin *)xmalloc (size); + + /* Copy shell_builtins[0]...shell_builtins[ind - 1] to new_shell_builtins */ + if (ind) + FASTCOPY ((char *)shell_builtins, (char *)new_shell_builtins, + ind * sizeof (struct builtin)); + /* Copy shell_builtins[ind+1]...shell_builtins[num_shell_builtins to + new_shell_builtins, starting at ind. */ + FASTCOPY ((char *)(&shell_builtins[ind+1]), + (char *)(&new_shell_builtins[ind]), + (num_shell_builtins - ind) * sizeof (struct builtin)); + + if (shell_builtins != static_shell_builtins) + free (shell_builtins); + + /* The result is still sorted. */ + num_shell_builtins--; + shell_builtins = new_shell_builtins; +} + +static int +dyn_unload_builtin (name) + char *name; +{ + struct builtin *b; + void *handle; + int ref, i; + + b = builtin_address_internal (name, 1); + if (b == 0) + { + builtin_error ("%s: not a shell builtin", name); + return (EXECUTION_FAILURE); + } + if (b->flags & STATIC_BUILTIN) + { + builtin_error ("%s: not dynamically loaded", name); + return (EXECUTION_FAILURE); + } + + handle = (void *)b->handle; + for (ref = i = 0; i < num_shell_builtins; i++) + { + if (shell_builtins[i].handle == b->handle) + ref++; + } + + /* Don't remove the shared object unless the reference count of builtins + using it drops to zero. */ + if (ref == 1 && dlclose (handle) != 0) + { + builtin_error ("cannot delete %s: %s", name, dlerror ()); + return (EXECUTION_FAILURE); + } + + /* Now remove this entry from the builtin table and reinitialize. */ + delete_builtin (b); + + return (EXECUTION_SUCCESS); } +#endif diff --git a/builtins/eval.def b/builtins/eval.def index 5c3eda8..a394896 100644 --- a/builtins/eval.def +++ b/builtins/eval.def @@ -27,19 +27,24 @@ $SHORT_DOC eval [arg ...] Read ARGs as input to the shell and execute the resulting command(s). $END +#include +#if defined (HAVE_UNISTD_H) +#include +#endif + #include "../shell.h" +#include "bashgetopt.h" + +extern int parse_and_execute (); /* Parse the string that these words make, and execute the command found. */ int eval_builtin (list) WORD_LIST *list; { - int result; + if (no_options (list)) + return (EX_USAGE); /* Note that parse_and_execute () frees the string it is passed. */ - if (list) - result = parse_and_execute (string_list (list), "eval", -1); - else - result = EXECUTION_SUCCESS; - return (result); + return (list ? parse_and_execute (string_list (list), "eval", -1) : EXECUTION_SUCCESS); } diff --git a/builtins/evalfile.c b/builtins/evalfile.c new file mode 100644 index 0000000..14fbc4d --- /dev/null +++ b/builtins/evalfile.c @@ -0,0 +1,211 @@ +/* Copyright (C) 1996 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 1, 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, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include + +#if defined (HAVE_UNISTD_H) +# include +#endif + +#include +#include "../posixstat.h" +#include "../filecntl.h" + +#include +#include +#include + +#include "../bashansi.h" + +#include "../shell.h" +#include "../jobs.h" +#include "../builtins.h" +#include "../flags.h" +#include "../input.h" +#include "../execute_cmd.h" + +#if defined (HISTORY) +# include "../bashhist.h" +#endif + +#include "common.h" + +#if !defined (errno) +extern int errno; +#endif + +/* Flags for _evalfile() */ +#define FEVAL_ENOENTOK 0x001 +#define FEVAL_BUILTIN 0x002 +#define FEVAL_UNWINDPROT 0x004 +#define FEVAL_NONINT 0x008 +#define FEVAL_LONGJMP 0x010 + +extern int interactive, interactive_shell, posixly_correct; +extern int indirection_level, startup_state, subshell_environment; +extern int return_catch_flag, return_catch_value; +extern int last_command_exit_value; + +/* How many `levels' of sourced files we have. */ +int sourcelevel = 0; + +static int +_evalfile (filename, flags) + char *filename; + int flags; +{ + volatile int old_interactive; + procenv_t old_return_catch; + int return_val, fd, result; + char *string; + struct stat finfo; + VFunction *errfunc; + + fd = open (filename, O_RDONLY); + + if (fd < 0 || (fstat (fd, &finfo) == -1)) + { +file_error_and_exit: + if (((flags & FEVAL_ENOENTOK) == 0) || errno != ENOENT) + file_error (filename); + + if (flags & FEVAL_LONGJMP) + { + last_command_exit_value = 1; + jump_to_top_level (EXITPROG); + } + + return ((flags & FEVAL_BUILTIN) ? EXECUTION_FAILURE + : ((errno == ENOENT) ? 0 : -1)); + } + + errfunc = (VFunction *)((flags & FEVAL_BUILTIN) ? builtin_error : internal_error); + + if (S_ISDIR (finfo.st_mode)) + { + (*errfunc) ("%s: is a directory", filename); + return ((flags & FEVAL_BUILTIN) ? EXECUTION_FAILURE : -1); + } + else if (S_ISREG (finfo.st_mode) == 0) + { + (*errfunc) ("%s: not a regular file", filename); + return ((flags & FEVAL_BUILTIN) ? EXECUTION_FAILURE : -1); + } + + string = xmalloc (1 + (int)finfo.st_size); + result = read (fd, string, finfo.st_size); + string[result] = '\0'; + + return_val = errno; + close (fd); + errno = return_val; + + if (result != (int)finfo.st_size) + { + free (string); + goto file_error_and_exit; + } + + if (check_binary_file ((unsigned char *)string, (result > 80) ? 80 : result)) + { + free (string); + (*errfunc) ("%s: cannot execute binary file", filename); + return ((flags & FEVAL_BUILTIN) ? EX_BINARY_FILE : -1); + } + + if (flags & FEVAL_UNWINDPROT) + { + begin_unwind_frame ("_evalfile"); + + unwind_protect_int (return_catch_flag); + unwind_protect_jmp_buf (return_catch); + if (flags & FEVAL_NONINT) + unwind_protect_int (interactive); + unwind_protect_int (sourcelevel); + } + else + { + COPY_PROCENV (return_catch, old_return_catch); + if (flags & FEVAL_NONINT) + old_interactive = interactive; + } + + if (flags & FEVAL_NONINT) + interactive = 0; + + return_catch_flag++; + sourcelevel++; + + if (flags & FEVAL_BUILTIN) + result = EXECUTION_SUCCESS; + + return_val = setjmp (return_catch); + + /* If `return' was seen outside of a function, but in the script, then + force parse_and_execute () to clean up. */ + if (return_val) + { + parse_and_execute_cleanup (); + result = return_catch_value; + } + else + result = parse_and_execute (string, filename, -1); + + if (flags & FEVAL_UNWINDPROT) + run_unwind_frame ("_evalfile"); + else + { + if (flags & FEVAL_NONINT) + interactive = old_interactive; + return_catch_flag--; + sourcelevel--; + COPY_PROCENV (old_return_catch, return_catch); + } + + return ((flags & FEVAL_BUILTIN) ? result : 1); +} + +int +maybe_execute_file (fname, force_noninteractive) + char *fname; + int force_noninteractive; +{ + char *filename; + int result, flags; + + filename = bash_tilde_expand (fname); + flags = FEVAL_ENOENTOK; + if (force_noninteractive) + flags |= FEVAL_NONINT; + result = _evalfile (filename, flags); + free (filename); + return result; +} + +int +source_file (filename) + char *filename; +{ + int flags; + + flags = FEVAL_BUILTIN|FEVAL_UNWINDPROT|FEVAL_NONINT; + /* POSIX shells exit if non-interactive and file error. */ + if (posixly_correct && !interactive_shell) + flags |= FEVAL_LONGJMP; + return (_evalfile (filename, flags)); +} diff --git a/builtins/evalstring.c b/builtins/evalstring.c new file mode 100644 index 0000000..2e84068 --- /dev/null +++ b/builtins/evalstring.c @@ -0,0 +1,228 @@ +/* Copyright (C) 1996 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 1, 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, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include + +#if defined (HAVE_UNISTD_H) +# include +#endif + +#include +#include + +#include "../bashansi.h" + +#include "../shell.h" +#include "../jobs.h" +#include "../builtins.h" +#include "../flags.h" +#include "../input.h" +#include "../execute_cmd.h" + +#if defined (HISTORY) +# include "../bashhist.h" +#endif + +#include "common.h" + +extern int interactive, interactive_shell; +extern int indirection_level, startup_state, subshell_environment; +extern int line_number; +extern int last_command_exit_value; +extern int running_trap; +extern COMMAND *global_command; + +int parse_and_execute_level = 0; + +/* How to force parse_and_execute () to clean up after itself. */ +void +parse_and_execute_cleanup () +{ + if (running_trap) + { + run_trap_cleanup (running_trap - 1); + unfreeze_jobs_list (); + } + run_unwind_frame ("parse_and_execute_top"); +} + +/* Parse and execute the commands in STRING. Returns whatever + execute_command () returns. This frees STRING. INTERACT is + the new value for `interactive' while the commands are being + executed. A value of -1 means don't change it. */ +int +parse_and_execute (string, from_file, interact) + char *string; + char *from_file; + int interact; +{ + int code; + volatile int should_jump_to_top_level, last_result; + char *orig_string; + COMMAND *volatile command; + + orig_string = string; + /* Unwind protect this invocation of parse_and_execute (). */ + begin_unwind_frame ("parse_and_execute_top"); + unwind_protect_int (parse_and_execute_level); + unwind_protect_jmp_buf (top_level); + unwind_protect_int (indirection_level); + unwind_protect_int (line_number); + if (interact != -1 && interactive != interact) + unwind_protect_int (interactive); + +#if defined (HISTORY) + if (interactive_shell) + { + unwind_protect_int (remember_on_history); +# if defined (BANG_HISTORY) + unwind_protect_int (history_expansion_inhibited); +# endif /* BANG_HISTORY */ + } +#endif /* HISTORY */ + + add_unwind_protect (pop_stream, (char *)NULL); + if (orig_string) + add_unwind_protect (xfree, orig_string); + end_unwind_frame (); + + parse_and_execute_level++; + push_stream (1); /* reset the line number */ + indirection_level++; + if (interact != -1) + interactive = interact; + +#if defined (HISTORY) + bash_history_disable (); +#endif /* HISTORY */ + + code = should_jump_to_top_level = 0; + last_result = EXECUTION_SUCCESS; + command = (COMMAND *)NULL; + + with_input_from_string (string, from_file); + while (*(bash_input.location.string)) + { + if (interrupt_state) + { + last_result = EXECUTION_FAILURE; + break; + } + + /* Provide a location for functions which `longjmp (top_level)' to + jump to. This prevents errors in substitution from restarting + the reader loop directly, for example. */ + code = setjmp (top_level); + + if (code) + { + should_jump_to_top_level = 0; + switch (code) + { + case FORCE_EOF: + case EXITPROG: + run_unwind_frame ("pe_dispose"); + /* Remember to call longjmp (top_level) after the old + value for it is restored. */ + should_jump_to_top_level = 1; + goto out; + + case DISCARD: + run_unwind_frame ("pe_dispose"); + last_command_exit_value = 1; /* XXX */ + if (subshell_environment) + { + should_jump_to_top_level = 1; + goto out; + } + else + { + dispose_command (command); /* XXX */ + continue; + } + + default: + programming_error ("parse_and_execute: bad jump: code %d", code); + break; + } + } + + if (parse_command () == 0) + { + if (interactive_shell == 0 && read_but_dont_execute) + { + last_result = EXECUTION_SUCCESS; + dispose_command (global_command); + global_command = (COMMAND *)NULL; + } + else if (command = global_command) + { + struct fd_bitmap *bitmap; + + bitmap = new_fd_bitmap (FD_BITMAP_SIZE); + begin_unwind_frame ("pe_dispose"); + add_unwind_protect (dispose_fd_bitmap, bitmap); + + global_command = (COMMAND *)NULL; + +#if defined (ONESHOT) + if (startup_state == 2 && *bash_input.location.string == '\0' && + command->type == cm_simple && !command->redirects && + !command->value.Simple->redirects) + { + command->flags |= CMD_NO_FORK; + command->value.Simple->flags |= CMD_NO_FORK; + } +#endif /* ONESHOT */ + + last_result = execute_command_internal + (command, 0, NO_PIPE, NO_PIPE, bitmap); + + dispose_command (command); + dispose_fd_bitmap (bitmap); + discard_unwind_frame ("pe_dispose"); + } + } + else + { + last_result = EXECUTION_FAILURE; + + /* Since we are shell compatible, syntax errors in a script + abort the execution of the script. Right? */ + break; + } + } + + out: + + run_unwind_frame ("parse_and_execute_top"); + + if (interrupt_state && parse_and_execute_level == 0) + { + /* An interrupt during non-interactive execution in an + interactive shell (e.g. via $PROMPT_COMMAND) should + not cause the shell to exit. */ + interactive = interactive_shell; + throw_to_top_level (); + } + + if (should_jump_to_top_level) + jump_to_top_level (code); + + return (last_result); +} diff --git a/builtins/exec.def b/builtins/exec.def index f950afc..c14af75 100644 --- a/builtins/exec.def +++ b/builtins/exec.def @@ -23,141 +23,190 @@ $PRODUCES exec.c $BUILTIN exec $FUNCTION exec_builtin -$SHORT_DOC exec [ [-] file [redirection ...]] +$SHORT_DOC exec [-cl] [-a name] file [redirection ...] Exec FILE, replacing this shell with the specified program. If FILE is not specified, the redirections take effect in this -shell. If the first argument is `-', then place a dash in the -zeroth arg passed to FILE. If the file cannot be exec'ed and -the shell is not interactive, then the shell exits, unless the -shell variable "no_exit_on_failed_exec" exists. +shell. If the first argument is `-l', then place a dash in the +zeroth arg passed to FILE, as login does. If the `-c' option +is supplied, FILE is executed with a null environment. The `-a' +option means to make set argv[0] of the executed process to NAME. +If the file cannot be executed and the shell is not interactive, +then the shell exits, unless the shell option `execfail' is set. $END -#include "../shell.h" +#include + #include #include "../posixstat.h" #include #include +#if defined (HAVE_UNISTD_H) +# include +#endif + +#include "../bashansi.h" + +#include "../shell.h" #include "../execute_cmd.h" -#include "common.h" +#if defined (JOB_CONTROL) +# include "../jobs.h" +#endif #include "../flags.h" +#include "../trap.h" +#if defined (HISTORY) +# include "../bashhist.h" +#endif +#include "common.h" +#include "bashgetopt.h" /* Not all systems declare ERRNO in errno.h... and some systems #define it! */ #if !defined (errno) extern int errno; #endif /* !errno */ + extern int interactive, subshell_environment; extern REDIRECT *redirection_undo_list; +int no_exit_on_failed_exec; + +/* If the user wants this to look like a login shell, then + prepend a `-' onto NAME and return the new name. */ +static char * +mkdashname (name) + char *name; +{ + char *ret; + + ret = xmalloc (2 + strlen (name)); + ret[0] = '-'; + strcpy (ret + 1, name); + return ret; +} + int exec_builtin (list) WORD_LIST *list; { int exit_value = EXECUTION_FAILURE; + int cleanenv, login, opt; + char *argv0, *command, **args, **env, *newname; - maybe_make_export_env (); + cleanenv = login = 0; + argv0 = (char *)NULL; + + reset_internal_getopt (); + while ((opt = internal_getopt (list, "cla:")) != -1) + { + switch (opt) + { + case 'c': + cleanenv = 1; + break; + case 'l': + login = 1; + break; + case 'a': + argv0 = list_optarg; + break; + default: + builtin_usage (); + return (EX_USAGE); + } + } + list = loptend; /* First, let the redirections remain. */ dispose_redirects (redirection_undo_list); redirection_undo_list = (REDIRECT *)NULL; - if (!list) + if (list == 0) return (EXECUTION_SUCCESS); - else + +#if defined (RESTRICTED_SHELL) + if (restricted) { - /* Otherwise, execve the new command with args. */ - char *command, **args; - int dash_name = 0; + builtin_error ("restricted"); + return (EXECUTION_FAILURE); + } +#endif /* RESTRICTED_SHELL */ - if (list->word->word[0] == '-' && !list->word->word[1]) - { - /* The user would like to exec this command as if it was a - login command. Do so. */ - list = list->next; - dash_name++; - } + args = word_list_to_argv (list, 1, 0, (int *)NULL); - if (!list) - return (EXECUTION_SUCCESS); + /* A command with a slash anywhere in its name is not looked up in $PATH. */ + command = absolute_program (args[0]) ? args[0] : search_for_command (args[0]); -#if defined (RESTRICTED_SHELL) - if (restricted) - { - builtin_error ("restricted"); - return (EXECUTION_FAILURE); - } -#endif /* RESTRICTED_SHELL */ + if (command == 0) + { + builtin_error ("%s: not found", args[0]); + exit_value = EX_NOTFOUND; /* As per Posix.2, 3.14.6 */ + goto failed_exec; + } - args = make_word_array (list); + command = full_pathname (command); - /* A command with a slash anywhere in its name is not looked up in - the search path. */ - if (absolute_program (args[0])) - command = args[0]; - else - command = find_user_command (args[0]); - if (!command) - { - builtin_error ("%s: not found", args[0]); - exit_value = EX_NOTFOUND; /* As per Posix.2, 3.14.6 */ - goto failed_exec; - } + if (argv0) + { + free (args[0]); + args[0] = login ? mkdashname (argv0) : savestring (argv0); + } + else if (login) + { + newname = mkdashname (args[0]); + free (args[0]); + args[0] = newname; + } - command = full_pathname (command); - /* If the user wants this to look like a login shell, then - prepend a `-' onto the first argument (argv[0]). */ - if (dash_name) - { - char *new_name = xmalloc (2 + strlen (args[0])); - new_name[0] = '-'; - strcpy (new_name + 1, args[0]); - free (args[0]); - args[0] = new_name; - } + /* Decrement SHLVL by 1 so a new shell started here has the same value, + preserving the appearance. After we do that, we need to change the + exported environment to include the new value. */ + if (cleanenv == 0) + adjust_shell_level (-1); - /* Decrement SHLVL by 1 so a new shell started here has the same value, - preserving the appearance. After we do that, we need to change the - exported environment to include the new value. */ - adjust_shell_level (-1); + if (cleanenv) + env = (char **)NULL; + else + { maybe_make_export_env (); + env = export_env; + } #if defined (HISTORY) - maybe_save_shell_history (); + maybe_save_shell_history (); #endif /* HISTORY */ - restore_original_signals (); + + restore_original_signals (); #if defined (JOB_CONTROL) - if (subshell_environment == 0) - end_job_control (); + if (subshell_environment == 0) + end_job_control (); #endif /* JOB_CONTROL */ - shell_execve (command, args, export_env); - - adjust_shell_level (1); + shell_execve (command, args, env); + if (cleanenv == 0) + adjust_shell_level (1); - if (!executable_file (command)) - { - builtin_error ("%s: cannot execute: %s", command, strerror (errno)); - exit_value = EX_NOEXEC; /* As per Posix.2, 3.14.6 */ - } - else - file_error (command); + if (executable_file (command) == 0) + { + builtin_error ("%s: cannot execute: %s", command, strerror (errno)); + exit_value = EX_NOEXEC; /* As per Posix.2, 3.14.6 */ + } + else + file_error (command); - failed_exec: - if (command) - free (command); +failed_exec: + if (command) + free (command); - if (subshell_environment || - (!interactive && !find_variable ("no_exit_on_failed_exec"))) - exit (exit_value); + if (subshell_environment || (interactive == 0 && no_exit_on_failed_exec == 0)) + exit_shell (exit_value); - initialize_traps (); - reinitialize_signals (); + initialize_traps (); + reinitialize_signals (); #if defined (JOB_CONTROL) - restart_job_control (); + restart_job_control (); #endif /* JOB_CONTROL */ - return (exit_value); - } + return (exit_value); } diff --git a/builtins/exit.def b/builtins/exit.def index 25a3b63..23a89ca 100644 --- a/builtins/exit.def +++ b/builtins/exit.def @@ -1,5 +1,5 @@ This file is exit.def, from which is created exit.c. -It implements the builtins "exit" and "logout" in Bash. +It implements the builtins "exit", and "logout" in Bash. Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc. @@ -28,18 +28,26 @@ Exit the shell with a status of N. If N is omitted, the exit status is that of the last command executed. $END -#include +#include + #include +#include + +#if defined (HAVE_UNISTD_H) +# include +#endif + #include "../shell.h" #include "../jobs.h" +#include "common.h" #include "builtext.h" /* for jobs_builtin */ extern int interactive, login_shell; extern int last_command_exit_value; static int exit_or_logout (); -static int sourced_logout = 0; +static int sourced_logout; int exit_builtin (list) @@ -65,9 +73,9 @@ int logout_builtin (list) WORD_LIST *list; { - if (!login_shell && interactive) + if (login_shell == 0 && interactive) { - builtin_error ("Not login shell: use `exit'"); + builtin_error ("not login shell: use `exit'"); return (EXECUTION_FAILURE); } else @@ -87,7 +95,7 @@ exit_or_logout (list) #if defined (JOB_CONTROL) int exit_immediate_okay; - exit_immediate_okay = (!interactive || + exit_immediate_okay = (interactive == 0 || last_shell_builtin == exit_builtin || last_shell_builtin == logout_builtin || last_shell_builtin == jobs_builtin); @@ -97,7 +105,7 @@ exit_or_logout (list) { register int i; for (i = 0; i < job_slots; i++) - if (jobs[i] && (jobs[i]->state == JSTOPPED)) + if (jobs[i] && STOPPED (i)) { fprintf (stderr, "There are stopped jobs.\n"); @@ -113,17 +121,20 @@ exit_or_logout (list) /* Get return value if present. This means that you can type `logout 5' to a shell, and it returns 5. */ - if (list) - exit_value = get_numeric_arg (list); - else - exit_value = last_command_exit_value; + exit_value = list ? get_numeric_arg (list) : last_command_exit_value; /* Run our `~/.bash_logout' file if it exists, and this is a login shell. */ if (login_shell && sourced_logout++ == 0) - maybe_execute_file ("~/.bash_logout", 1); + { + maybe_execute_file ("~/.bash_logout", 1); +#ifdef SYS_BASH_LOGOUT + maybe_execute_file (SYS_BASH_LOGOUT, 1); +#endif + } last_command_exit_value = exit_value; /* Exit the program. */ - longjmp (top_level, EXITPROG); + jump_to_top_level (EXITPROG); + /*NOTREACHED*/ } diff --git a/builtins/fc.def b/builtins/fc.def index 1f6db68..16eb8d2 100644 --- a/builtins/fc.def +++ b/builtins/fc.def @@ -46,23 +46,32 @@ runs the last command beginning with `cc' and typing `r' re-executes the last command. $END -#include -#include "../bashansi.h" -#include "../shell.h" +#include + #if defined (HISTORY) #include -#include -#include +#include "bashtypes.h" +#include "posixstat.h" #include + +#if defined (HAVE_UNISTD_H) +# include +#endif + +#include + +#include "../bashansi.h" #include + +#include "../shell.h" #include "../builtins.h" #include "../flags.h" #include "../maxpath.h" #include "../bashhist.h" #include #include "bashgetopt.h" +#include "common.h" -/* Not all systems declare ERRNO in errno.h... and some systems #define it! */ #if !defined (errno) extern int errno; #endif /* !errno */ @@ -100,8 +109,8 @@ extern int unlink (); Equivalent to !command:sg/pat/rep execpt there can be multiple PAT=REP's. */ -static char *fc_dosubs (), *fc_replace (), *fc_gethist (), *fc_readline (); -static int fc_gethnum (); +static char *fc_dosubs (), *fc_gethist (), *fc_readline (); +static int fc_gethnum (), fc_number (); static void fc_replhist (), fc_addhist (); /* Data structure describing a list of global replacements to perform. */ @@ -111,8 +120,6 @@ typedef struct repl { char *rep; } REPL; -#define USAGE "usage: fc [-e ename] [-nlr] [first] [last] or fc -s [pat=rep] [command]" - /* Accessors for HIST_ENTRY lists that are called HLIST. */ #define histline(i) (hlist[(i)]->line) #define histdata(i) (hlist[(i)]->data) @@ -143,61 +150,51 @@ fc_builtin (list) int numbering, reverse, listing, execute; int histbeg, histend, last_hist, retval, first, opt; FILE *stream; - REPL *rlist = (REPL *) NULL, *rl; - char *ename = NULL, *command, *newcom, *line; + REPL *rlist, *rl; + char *ename, *command, *newcom, *line; HIST_ENTRY **hlist; - char fn[MAXPATHLEN]; + char fn[64]; numbering = 1; reverse = listing = execute = 0; + ename = (char *)NULL; /* Parse out the options and set which of the two forms we're in. */ - - while (list && *list->word->word == '-') + reset_internal_getopt (); + lcurrent = list; /* XXX */ + while (fc_number (loptend = lcurrent) == 0 && + (opt = internal_getopt (list, ":e:lnrs")) != -1) { - register char *s = &((list->word->word)[1]); + switch (opt) + { + case 'n': + numbering = 0; + break; - if (!isletter (*s)) - break; + case 'l': + listing = 1; + break; - while (opt = *s++) - { - switch (opt) - { - case 'n': - numbering = 0; - break; - - case 'l': - listing = 1; - break; - - case 'r': - reverse = 1; - break; - - case 's': - execute = 1; - break; - - case 'e': - list = list->next; - if (list == NULL) - { - builtin_error (USAGE); - return (EX_USAGE); - } - ename = list->word->word; - break; - - default: - builtin_error (USAGE); - return (EX_USAGE); - } + case 'r': + reverse = 1; + break; + + case 's': + execute = 1; + break; + + case 'e': + ename = list_optarg; + break; + + default: + builtin_usage (); + return (EX_USAGE); } - list = list->next; } + list = loptend; + if (ename && (*ename == '-') && (ename[1] == '\0')) execute = 1; @@ -205,6 +202,7 @@ fc_builtin (list) substitutions). */ if (execute) { + rlist = (REPL *)NULL; while (list && ((sep = (char *)strchr (list->word->word, '=')) != NULL)) { *sep++ = '\0'; @@ -227,16 +225,13 @@ fc_builtin (list) to get the replacements in the proper order. */ if (rlist && rlist->next) - rlist = (REPL *) reverse_list ((GENERIC_LIST *) rlist); + rlist = (REPL *)reverse_list ((GENERIC_LIST *) rlist); hlist = history_list (); /* If we still have something in list, it is a command spec. Otherwise, we use the most recent command in time. */ - if (list) - command = fc_gethist (list->word->word, hlist); - else - command = fc_gethist ((char *) NULL, hlist); + command = fc_gethist (list ? list->word->word : (char *)NULL, hlist); if (command == NULL) { @@ -255,8 +250,8 @@ fc_builtin (list) command = newcom; } - printf ("%s\n", command); - fc_replhist (command); /* replace `fc -e -' with command */ + fprintf (stderr, "%s\n", command); + fc_replhist (command); /* replace `fc -s' with command */ return (parse_and_execute (command, "fc", -1)); } @@ -283,12 +278,7 @@ fc_builtin (list) if (list) histend = fc_gethnum (list->word->word, hlist); else - { - if (listing) - histend = last_hist; - else - histend = histbeg; - } + histend = listing ? last_hist : histbeg; } else { @@ -301,10 +291,8 @@ fc_builtin (list) histbeg = 0; } else - { - /* For editing, it is the last history command. */ - histbeg = histend = last_hist; - } + /* For editing, it is the last history command. */ + histbeg = histend = last_hist; } /* We print error messages for line specifications out of range. */ @@ -317,10 +305,10 @@ fc_builtin (list) if (histend < histbeg) { - int t = histend; - + i = histend; histend = histbeg; - histbeg = t; + histbeg = i; + reverse = 1; } @@ -329,40 +317,25 @@ fc_builtin (list) else { numbering = 0; - sprintf (fn, "/tmp/bash%d", (int)time ((long *) 0) + (int)getpid ()); + sprintf (fn, "/tmp/bash%d", (int)time ((time_t *) 0) + (int)getpid ()); stream = fopen (fn, "w"); - if (!stream) + if (stream == 0) { builtin_error ("cannot open temp file %s", fn); return (EXECUTION_FAILURE); } } - if (!reverse) + for (i = reverse ? histend : histbeg; reverse ? i >= histbeg : i <= histend; reverse ? i-- : i++) { - for (i = histbeg; i <= histend; i++) - { - QUIT; - if (numbering) - fprintf (stream, "%d", i + history_base); - if (listing) - fprintf (stream, "\t%c", histdata (i) ? '*' : ' '); - fprintf (stream, "%s\n", histline (i)); - } - } - else - { - for (i = histend; i >= histbeg; i--) - { - QUIT; - if (numbering) - fprintf (stream, "%d", i + history_base); - if (listing) - fprintf (stream, "\t%c", histdata (i) ? '*' : ' '); - fprintf (stream, "%s\n", histline (i)); - } + QUIT; + if (numbering) + fprintf (stream, "%d", i + history_base); + if (listing) + fprintf (stream, "\t%c", histdata (i) ? '*' : ' '); + fprintf (stream, "%s\n", histline (i)); } if (listing) @@ -381,7 +354,12 @@ fc_builtin (list) command = (char *)xmalloc (3 + strlen (FC_EDIT_COMMAND) + strlen (fn)); sprintf (command, "%s %s", FC_EDIT_COMMAND, fn); } - parse_and_execute (command, "fc", -1); + retval = parse_and_execute (command, "fc", -1); + if (retval != EXECUTION_SUCCESS) + { + unlink (fn); + return (EXECUTION_FAILURE); + } /* Now reopen the file and execute the edited commands. */ @@ -435,6 +413,21 @@ fc_builtin (list) return (retval); } +/* Return 1 if LIST->word->word is a legal number for fc's use. */ +static int +fc_number (list) + WORD_LIST *list; +{ + char *s; + + if (list == 0) + return 0; + s = list->word->word; + if (*s == '-') + s++; + return (legal_number (s, (long *)NULL)); +} + /* Return an absolute index into HLIST which corresponds to COMMAND. If COMMAND is a number, then it was specified in relative terms. If it is a string, then it is the start of a command line present in HLIST. */ @@ -572,58 +565,18 @@ fc_dosubs (command, subs) char *command; REPL *subs; { - register char *new = savestring (command); + register char *new, *t; register REPL *r; - for (r = subs; r; r = r->next) + for (new = savestring (command), r = subs; r; r = r->next) { - register char *t; - - t = fc_replace (r->pat, r->rep, new); + t = strsub (new, r->pat, r->rep, 1); free (new); new = t; } return (new); } -/* Replace the occurrences of PAT with REP in COMMAND. - This returns a new string; the caller should free it. */ -static char * -fc_replace (pat, rep, command) - char *pat, *rep, *command; -{ - register int i; - int patlen, replen, templen; - char *new, *temp; - - patlen = strlen (pat); - replen = strlen (rep); - - temp = savestring (command); - templen = strlen (temp); - i = 0; - - for (; (i + patlen) <= templen; i++) - { - if (STREQN (temp + i, pat, patlen)) - { - new = (char *) xmalloc (1 + (replen - patlen) + templen); - - strncpy (new, temp, i); - strncpy (new + i, rep, replen); - strncpy (new + i + replen, - temp + i + patlen, templen - (i + patlen)); - new[templen + (replen - patlen)] = '\0'; /* just in case */ - - free (temp); - temp = new; - i += replen; - templen = strlen (temp); - } - } - return (temp); -} - /* Use `command' to replace the last entry in the history list, which, by this time, is `fc blah...'. The intent is that the new command become the history entry, and that `fc' should never appear in the @@ -634,10 +587,9 @@ fc_replhist (command) { register int i; HIST_ENTRY **hlist, *histent, *discard; - char *data; int n; - if (!command || !*command) + if (command == 0 || *command == '\0') return; hlist = history_list (); @@ -665,8 +617,7 @@ fc_replhist (command) discard = remove_history (i); if (discard) { - if (discard->line) - free (discard->line); + FREE (discard->line); free ((char *) discard); } maybe_add_history (command); /* Obeys HISTCONTROL setting. */ diff --git a/builtins/fg_bg.def b/builtins/fg_bg.def index e48af38..49d0200 100644 --- a/builtins/fg_bg.def +++ b/builtins/fg_bg.def @@ -30,10 +30,18 @@ JOB_SPEC is not present, the shell's notion of the current job is used. $END +#include + #include #include + +#if defined (HAVE_UNISTD_H) +# include +#endif + #include "../shell.h" #include "../jobs.h" +#include "common.h" #if defined (JOB_CONTROL) extern char *this_command_name; @@ -45,23 +53,23 @@ int fg_builtin (list) WORD_LIST *list; { - int fg_bit = 1; - register WORD_LIST *t = list; + int fg_bit; + register WORD_LIST *t; - if (!job_control) + if (job_control == 0) { builtin_error ("no job control"); return (EXECUTION_FAILURE); } + if (no_options (list)) + return (EX_USAGE); + /* If the last arg on the line is '&', then start this job in the background. Else, fg the job. */ - - while (t && t->next) - t = t->next; - - if (t && t->word->word[0] == '&' && !t->word->word[1]) - fg_bit = 0; + for (t = list; t && t->next; t = t->next) + ; + fg_bit = (t && t->word->word[0] == '&' && t->word->word[1] == '\0') == 0; return (fg_bg (list, fg_bit)); } @@ -82,12 +90,15 @@ int bg_builtin (list) WORD_LIST *list; { - if (!job_control) + if (job_control == 0) { builtin_error ("no job control"); return (EXECUTION_FAILURE); } + if (no_options (list)) + return (EX_USAGE); + return (fg_bg (list, 0)); } @@ -98,27 +109,27 @@ fg_bg (list, foreground) int foreground; { sigset_t set, oset; - int job, status = EXECUTION_SUCCESS, old_async_pid; + int job, status, old_async_pid; BLOCK_CHILD (set, oset); job = get_job_spec (list); - if (job < 0 || job >= job_slots || !jobs[job]) + if (job < 0 || job >= job_slots || jobs[job] == 0) { if (job != DUP_JOB) - builtin_error ("No such job %s", list ? list->word->word : ""); + builtin_error ("%s: no such job", list ? list->word->word : "current"); goto failure; } /* Or if jobs[job]->pgrp == shell_pgrp. */ - if (!(jobs[job]->flags & J_JOBCONTROL)) + if (IS_JOBCONTROL (job) == 0) { builtin_error ("job %%%d started without job control", job + 1); goto failure; } - if (!foreground) + if (foreground == 0) { old_async_pid = last_asynchronous_pid; last_asynchronous_pid = jobs[job]->pgrp; /* As per Posix.2 5.4.2 */ @@ -134,7 +145,7 @@ fg_bg (list, foreground) } else { - if (!foreground) + if (foreground == 0) last_asynchronous_pid = old_async_pid; failure: diff --git a/builtins/getopt.c b/builtins/getopt.c index 7603430..bc69489 100644 --- a/builtins/getopt.c +++ b/builtins/getopt.c @@ -17,6 +17,12 @@ along with this program; if not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include + +#if defined (HAVE_UNISTD_H) +# include +#endif + #include #include "../memalloc.h" #include "../shell.h" @@ -66,6 +72,9 @@ int sh_opterr = 1; int sh_optopt = '?'; +/* Set to 1 when we see an illegal option; public so getopts can reset it. */ +int sh_badopt = 0; + /* Scan elements of ARGV (whose length is ARGC) for option characters given in OPTSTRING. @@ -102,7 +111,6 @@ sh_getopt (argc, argv, optstring) char *const *argv; const char *optstring; { - int option_index; char c, *temp; sh_optarg = 0; @@ -124,10 +132,18 @@ sh_getopt (argc, argv, optstring) nextchar = (char *)NULL; } + /* Do the increment of `sh_optind' we deferred because the last option + was illegal. */ + if (sh_badopt && (nextchar == 0 || *nextchar == '\0')) + { + sh_badopt = 0; + sh_optind++; + nextchar = (char *)NULL; + } + if (nextchar == 0 || *nextchar == '\0') { - /* If we have done all the ARGV-elements, stop the scan - and back over any non-options that we skipped and permuted. */ + /* If we have done all the ARGV-elements, stop the scan. */ if (sh_optind == argc) return EOF; @@ -158,16 +174,11 @@ sh_getopt (argc, argv, optstring) c = *nextchar++; sh_charindex++; temp = strchr (optstring, c); - /* Increment `sh_optind' when we start to process its last character. */ - if (nextchar == 0 || *nextchar == '\0') - { - sh_optind++; - nextchar = (char *)NULL; - } - sh_optopt = c; - if (temp == NULL || c == ':') + /* If the option is illegal, return an error, but defer updating sh_optind + until the next call so $OPTIND is correct. */ + if (sh_badopt = (temp == NULL || c == ':')) { if (sh_opterr) BADOPT (c); @@ -175,6 +186,13 @@ sh_getopt (argc, argv, optstring) return '?'; } + /* Increment `sh_optind' when we start to process its last character. */ + if (nextchar == 0 || *nextchar == '\0') + { + sh_optind++; + nextchar = (char *)NULL; + } + if (temp[1] == ':') { if (nextchar && *nextchar) @@ -191,6 +209,7 @@ sh_getopt (argc, argv, optstring) NEEDARG (c); sh_optopt = c; + sh_optarg = ""; /* Needed by getopts. */ c = (optstring[0] == ':') ? ':' : '?'; } else diff --git a/builtins/getopt.h b/builtins/getopt.h index fa9878c..7086bb7 100644 --- a/builtins/getopt.h +++ b/builtins/getopt.h @@ -51,6 +51,9 @@ extern int sh_opterr; extern int sh_optopt; +/* Set to 1 when an unrecognized option is encountered. */ +extern int sh_badopt; + extern int sh_getopt (); extern void sh_getopt_restore_state (); diff --git a/builtins/getopts.def b/builtins/getopts.def index 0f2b82f..f3d9aee 100644 --- a/builtins/getopts.def +++ b/builtins/getopts.def @@ -22,7 +22,6 @@ Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. $PRODUCES getopts.c $BUILTIN getopts -$DEPENDS_ON GETOPTS_BUILTIN $FUNCTION getopts_builtin $SHORT_DOC getopts optstring name [arg] Getopts is used by shell procedures to parse positional parameters. @@ -57,22 +56,24 @@ Getopts normally parses the positional parameters ($0 - $9), but if more arguments are given, they are parsed instead. $END +#include + #include -#if defined (HAVE_STRING_H) -# include -#else /* !HAVE_STRING_H */ -# include -#endif /* !HAVE_STRING_H */ +#if defined (HAVE_UNISTD_H) +# include +#endif -#include "../shell.h" +#include "../bashansi.h" -#if defined (GETOPTS_BUILTIN) +#include "../shell.h" +#include "common.h" +#include "bashgetopt.h" #include "getopt.h" -#define G_EOF (-1) -#define G_ILLEGAL_OPT (-2) -#define G_ARG_MISSING (-3) +#define G_EOF -1 +#define G_ILLEGAL_OPT -2 +#define G_ARG_MISSING -3 extern char *this_command_name; extern WORD_LIST *rest_of_args; @@ -84,6 +85,25 @@ getopts_reset (newind) int newind; { sh_optind = newind; + sh_badopt = 0; +} + +static int +getopts_bind_variable (name, value) + char *name, *value; +{ + SHELL_VAR *v; + + if (legal_identifier (name)) + { + v = bind_variable (name, value); + return (v && (readonly_p (v) == 0)) ? EXECUTION_SUCCESS : EXECUTION_FAILURE; + } + else + { + builtin_error ("`%s': not a valid identifier", name); + return (EXECUTION_FAILURE); + } } /* Error handling is now performed as specified by Posix.2, draft 11 @@ -118,7 +138,7 @@ dogetopts (argc, argv) int argc; char **argv; { - int ret, special_error, old_opterr = 0, i, n; + int ret, special_error, old_opterr, i, n; char strval[2], numval[16]; char *optstr; /* list of options */ char *name; /* variable to get flag val */ @@ -126,7 +146,7 @@ dogetopts (argc, argv) if (argc < 3) { - builtin_error("usage: getopts optstring name [arg]"); + builtin_usage (); return (EX_USAGE); } @@ -156,19 +176,19 @@ dogetopts (argc, argv) } else if (rest_of_args == (WORD_LIST *)NULL) { - register int i; - - for (i = 0; i < 10 && dollar_vars[i]; i++); + for (i = 0; i < 10 && dollar_vars[i]; i++) + ; ret = sh_getopt (i, dollar_vars, optstr); } else { - register int i; register WORD_LIST *words; char **v; - for (i = 0; i < 10 && dollar_vars[i]; i++); - for (words = rest_of_args; words; words = words->next, i++); + for (i = 0; i < 10 && dollar_vars[i]; i++) + ; + for (words = rest_of_args; words; words = words->next, i++) + ; v = (char **)xmalloc ((i + 1) * sizeof (char *)); for (i = 0; i < 10 && dollar_vars[i]; i++) v[i] = dollar_vars[i]; @@ -203,9 +223,9 @@ dogetopts (argc, argv) /* If an error occurred, decide which one it is and set the return code appropriately. In all cases, the option character in error - is in SH_OPTOPT. If an illegal option was encountered, OPTARG is + is in OPTOPT. If an illegal option was encountered, OPTARG is NULL. If a required option argument was missing, OPTARG points - to a NULL string (that is, optarg[0] == 0). */ + to a NULL string (that is, sh_optarg[0] == 0). */ if (ret == '?') { if (sh_optarg == NULL) @@ -216,26 +236,25 @@ dogetopts (argc, argv) if (ret == G_EOF) { - bind_variable (name, "?"); + getopts_bind_variable (name, "?"); return (EXECUTION_FAILURE); } if (ret == G_ILLEGAL_OPT) { /* Illegal option encountered. */ - strval[0] = '?'; - strval[1] = '\0'; - bind_variable (name, strval); + ret = getopts_bind_variable (name, "?"); if (special_error) { - strval[0] = (char) sh_optopt; + strval[0] = (char)sh_optopt; strval[1] = '\0'; bind_variable ("OPTARG", strval); } else makunbound ("OPTARG", shell_variables); - return (EXECUTION_SUCCESS); + + return (ret); } if (ret == G_ARG_MISSING) @@ -243,31 +262,25 @@ dogetopts (argc, argv) /* Required argument missing. */ if (special_error) { - strval[0] = ':'; - strval[1] = '\0'; - bind_variable (name, strval); + ret = getopts_bind_variable (name, ":"); - strval[0] = (char) sh_optopt; + strval[0] = (char)sh_optopt; strval[1] = '\0'; bind_variable ("OPTARG", strval); } else { - strval[0] = '?'; - strval[1] = '\0'; - bind_variable (name, strval); + ret = getopts_bind_variable (name, "?"); makunbound ("OPTARG", shell_variables); } - return (EXECUTION_SUCCESS); + return (ret); } bind_variable ("OPTARG", sh_optarg); strval[0] = (char) ret; strval[1] = '\0'; - bind_variable (name, strval); - - return (EXECUTION_SUCCESS); + return (getopts_bind_variable (name, strval)); } /* The getopts builtin. Build an argv, and call dogetopts with it. */ @@ -275,26 +288,27 @@ int getopts_builtin (list) WORD_LIST *list; { - register int i; char **av; int ac, ret; - WORD_LIST *t; if (list == 0) return EXECUTION_FAILURE; - for (t = list, ac = 0; t; t = t->next, ac++); - - ac++; - av = (char **)xmalloc ((1 + ac) * sizeof (char *)); - av[ac] = (char *) NULL; - av[0] = this_command_name; - - for (t = list, i = 1; t; t = t->next, i++) - av[i] = t->word->word; + reset_internal_getopt (); + while ((ret = internal_getopt (list, "")) != -1) + { + switch (ret) + { + default: + builtin_usage (); + return (EX_USAGE); + } + } + list = loptend; + av = make_builtin_argv (list, &ac); ret = dogetopts (ac, av); free ((char *)av); + return (ret); } -#endif /* GETOPTS_BUILTIN */ diff --git a/builtins/hash.def b/builtins/hash.def index f4d319b..2f69f65 100644 --- a/builtins/hash.def +++ b/builtins/hash.def @@ -23,182 +23,167 @@ $PRODUCES hash.c $BUILTIN hash $FUNCTION hash_builtin -$SHORT_DOC hash [-r] [name ...] +$SHORT_DOC hash [-r] [-p pathname] [name ...] For each NAME, the full pathname of the command is determined and -remembered. The -r option causes the shell to forget all remembered -locations. If no arguments are given, information about remembered -commands is presented. +remembered. If the -p option is supplied, PATHNAME is used as the +full pathname of NAME, and no path search is performed. The -r +option causes the shell to forget all remembered locations. If no +arguments are given, information about remembered commands is displayed. $END +#include + #include #include "../posixstat.h" #include -#if defined (HAVE_STRING_H) -# include -#else /* !HAVE_STRING_H */ -# include -#endif /* !HAVE_STRING_H */ +#if defined (HAVE_UNISTD_H) +# include +#endif + +#include "../bashansi.h" #include "../shell.h" #include "../builtins.h" #include "../flags.h" +#include "../execute_cmd.h" #include "hashcom.h" #include "common.h" -#include "../execute_cmd.h" +#include "bashgetopt.h" extern int dot_found_in_search; +extern char *this_command_name; + +static int add_hashed_command (); +static int print_hashed_commands (); + +static int hashing_initialized = 0; + +HASH_TABLE *hashed_filenames; void initialize_filename_hashing () { - hashed_filenames = make_hash_table (FILENAME_HASH_BUCKETS); + if (hashing_initialized == 0) + { + hashed_filenames = make_hash_table (FILENAME_HASH_BUCKETS); + hashing_initialized = 1; + } +} + +static void +free_filename_data (data) + char *data; +{ + free (((PATH_DATA *)data)->path); + free (data); +} + +void +flush_hashed_filenames () +{ + flush_hash_table (hashed_filenames, free_filename_data); +} + +/* Remove FILENAME from the table of hashed commands. */ +void +remove_hashed_filename (filename) + char *filename; +{ + register BUCKET_CONTENTS *item; + + if (hashing_enabled == 0) + return; + + item = remove_hash_item (filename, hashed_filenames); + if (item) + { + if (item->data) + free_filename_data (item->data); + free (item->key); + free (item); + } } /* Print statistics on the current state of hashed commands. If LIST is not empty, then rehash (or hash in the first place) the specified commands. */ +int hash_builtin (list) WORD_LIST *list; { - int expunge_hash_table = 0; - int any_failed = 0; + int expunge_hash_table, opt; + char *word, *pathname; - if (hashing_disabled) + if (hashing_enabled == 0) { builtin_error ("hashing disabled"); return (EXECUTION_FAILURE); } - while (list) + expunge_hash_table = 0; + pathname = (char *)NULL; + reset_internal_getopt (); + while ((opt = internal_getopt (list, "rp:")) != -1) { - char *arg = list->word->word; - - if (ISOPTION (arg, 'r')) + switch (opt) { + case 'r': expunge_hash_table = 1; - list = list->next; - } - else if (ISOPTION (arg, '-')) - { - list = list->next; break; - } - else if (*arg == '-') - { - bad_option (list->word->word); - builtin_error ("usage: hash [-r] [command ...]"); + case 'p': + pathname = list_optarg; + break; + default: + builtin_usage (); return (EX_USAGE); } - else - break; } + list = loptend; /* We want hash -r to be silent, but hash -- to print hashing info. That - is the reason for the !expunge_hash_table. */ - if (!list && !expunge_hash_table) + is the reason for the test of expunge_hash_table. */ + if (list == 0 && expunge_hash_table == 0) { - /* Print information about current hashed info. */ - int any_printed = 0; - int bucket = 0; - register BUCKET_CONTENTS *item_list; - - while (bucket < hashed_filenames->nbuckets) - { - item_list = get_hash_bucket (bucket, hashed_filenames); - if (item_list) - { - if (!any_printed) - { - printf ("hits\tcommand\n"); - any_printed++; - } - while (item_list) - { - printf ("%4d\t%s\n", - item_list->times_found, pathdata(item_list)->path); - item_list = item_list->next; - } - } - bucket++; - } - - if (!any_printed) - printf ("No commands in hash table.\n"); + if (print_hashed_commands () == 0) + printf ("%s: hash table empty\n", this_command_name); return (EXECUTION_SUCCESS); } if (expunge_hash_table) - { - int bucket = 0; - register BUCKET_CONTENTS *item_list, *prev; + flush_hashed_filenames (); - while (bucket < hashed_filenames->nbuckets) - { - item_list = get_hash_bucket (bucket, hashed_filenames); - if (item_list) - { - while (item_list) - { - prev = item_list; - free (item_list->key); - free (pathdata(item_list)->path); - free (item_list->data); - item_list = item_list->next; - free (prev); - } - hashed_filenames->bucket_array[bucket] = (BUCKET_CONTENTS *)NULL; - } - bucket++; - } - } - - while (list) + for (opt = EXECUTION_SUCCESS; list; list = list->next) { /* Add or rehash the specified commands. */ - char *word; - char *full_path; - SHELL_VAR *var; - word = list->word->word; - if (absolute_program (word)) - { - list = list->next; - continue; - } - full_path = find_user_command (word); - var = find_function (word); - - if (!find_shell_builtin (word) && (!var)) + if (pathname) + remember_filename (word, pathname, 0, 0); + else { - if (full_path && executable_file (full_path)) - remember_filename (word, full_path, dot_found_in_search, 0); - else + if (absolute_program (word)) { - builtin_error ("%s: not found", word); - any_failed++; + list = list->next; + continue; } - } - if (full_path) - free (full_path); - list = list->next; + if (add_hashed_command (word)) + opt = EXECUTION_FAILURE; + } } fflush (stdout); - if (any_failed) - return (EXECUTION_FAILURE); - else - return (EXECUTION_SUCCESS); + return (opt); } /* Place FILENAME (key) and FULL_PATHNAME (data->path) into the hash table. CHECK_DOT if non-null is for future calls to - find_hashed_filename (). FOUND is the initial value for - times_found. */ + find_hashed_filename (); it means that this file was found + in a directory in $PATH that is not an absolute pathname. + FOUND is the initial value for times_found. */ void remember_filename (filename, full_pathname, check_dot, found) char *filename, *full_pathname; @@ -206,17 +191,74 @@ remember_filename (filename, full_pathname, check_dot, found) { register BUCKET_CONTENTS *item; - if (hashing_disabled) + if (hashing_enabled == 0) return; + item = add_hash_item (filename, hashed_filenames); if (item->data) free (pathdata(item)->path); else { item->key = savestring (filename); - item->data = (char *)xmalloc (sizeof (PATH_DATA)); + item->data = xmalloc (sizeof (PATH_DATA)); } pathdata(item)->path = savestring (full_pathname); - pathdata(item)->check_dot = check_dot; + pathdata(item)->flags = 0; + if (check_dot) + pathdata(item)->flags |= HASH_CHKDOT; + if (*full_pathname != '/') + pathdata(item)->flags |= HASH_RELPATH; item->times_found = found; } + +static int +add_hashed_command (word, quiet) + char *word; + int quiet; +{ + int rv; + char *full_path; + + rv = 0; + if (find_function (word) == 0 && find_shell_builtin (word) == 0) + { + full_path = find_user_command (word); + if (full_path && executable_file (full_path)) + remember_filename (word, full_path, dot_found_in_search, 0); + else + { + if (quiet == 0) + builtin_error ("%s: not found", word); + rv++; + } + if (full_path) + free (full_path); + } + return (rv); +} + +/* Print information about current hashed info. */ +static int +print_hashed_commands () +{ + BUCKET_CONTENTS *item_list; + int bucket, any_printed; + + for (bucket = any_printed = 0; bucket < hashed_filenames->nbuckets; bucket++) + { + item_list = get_hash_bucket (bucket, hashed_filenames); + if (item_list == 0) + continue; + + if (any_printed == 0) + { + printf ("hits\tcommand\n"); + any_printed++; + } + + for ( ; item_list; item_list = item_list->next) + printf ("%4d\t%s\n", item_list->times_found, pathdata(item_list)->path); + + } + return (any_printed); +} diff --git a/builtins/hashcom.h b/builtins/hashcom.h index defe2fc..5943b5b 100644 --- a/builtins/hashcom.h +++ b/builtins/hashcom.h @@ -18,7 +18,7 @@ with Bash; see the file COPYING. If not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include "../hash.h" +#include "../hashlib.h" #define FILENAME_HASH_BUCKETS 631 @@ -26,7 +26,10 @@ extern HASH_TABLE *hashed_filenames; typedef struct { char *path; /* The full pathname of the file. */ - int check_dot; /* Whether `.' appeared before this one in $PATH. */ + int flags; } PATH_DATA; +#define HASH_RELPATH 0x01 /* this filename is a relative pathname. */ +#define HASH_CHKDOT 0x02 /* check `.' since it was earlier in $PATH */ + #define pathdata(x) ((PATH_DATA *)(x)->data) diff --git a/builtins/help.def b/builtins/help.def index c9f1db8..e5e82d5 100644 --- a/builtins/help.def +++ b/builtins/help.def @@ -23,112 +23,131 @@ $PRODUCES help.c $BUILTIN help $FUNCTION help_builtin +$DEPENDS_ON HELP_BUILTIN $SHORT_DOC help [pattern ...] Display helpful information about builtin commands. If PATTERN is specified, gives detailed help on all commands matching PATTERN, otherwise a list of the builtins is printed. $END +#include + +#if defined (HELP_BUILTIN) #include + +#if defined (HAVE_UNISTD_H) +# include +#endif + #include "../shell.h" #include "../builtins.h" +#include "bashgetopt.h" + +#include +#include -#if defined (USE_GLOB_LIBRARY) -# include -#else -# define FNM_NOMATCH 1 -#endif /* USE_GLOB_LIBRARY */ +static void show_builtin_command_help (); /* Print out a list of the known functions in the shell, and what they do. If LIST is supplied, print out the list which matches for each pattern specified. */ +int help_builtin (list) WORD_LIST *list; { - if (!list) - { - register int i, j; - char blurb[256]; + register int i, j; + char *pattern, *name; + int plen, match_found; - show_shell_version (); - printf ( -"Shell commands that 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\ -\n\ -A star (*) next to a name means that the command is disabled.\n\ -\n"); + if (list == 0) + { + show_shell_version (0); + show_builtin_command_help (); + return (EXECUTION_SUCCESS); + } - for (i = 0; i < num_shell_builtins; i++) + /* Placeholder for future options. */ + reset_internal_getopt (); + while ((i = internal_getopt (list, "")) != -1) + { + switch (i) { - QUIT; - sprintf (blurb, "%c%s", - (shell_builtins[i].flags & BUILTIN_ENABLED) ? ' ' : '*', - shell_builtins[i].short_doc); - - blurb[35] = '\0'; - printf ("%s", blurb); - - if (i % 2) - printf ("\n"); - else - for (j = strlen (blurb); j < 35; j++) - putc (' ', stdout); - + default: + builtin_usage (); + return (EX_USAGE); } - if (i % 2) - printf ("\n"); } - else - { - int match_found = 0; - char *pattern = ""; + list = loptend; - if (glob_pattern_p (list->word->word)) - { - printf ("Shell commands matching keyword%s `", - list->next ? "s" : ""); - print_word_list (list, ", "); - printf ("'\n\n"); - } + /* We should consider making `help bash' do something. */ - while (list) - { - register int i = 0, plen; - char *name; + if (glob_pattern_p (list->word->word)) + { + printf ("Shell commands matching keyword%s `", list->next ? "s" : ""); + print_word_list (list, ", "); + printf ("'\n\n"); + } - pattern = list->word->word; - plen = strlen (pattern); + for (match_found = 0, pattern = ""; list; list = list->next) + { + pattern = list->word->word; + plen = strlen (pattern); - while (name = shell_builtins[i].name) + for (i = 0; name = shell_builtins[i].name; i++) + { + QUIT; + if ((strncmp (pattern, name, plen) == 0) || + (fnmatch (pattern, name, 0) != FNM_NOMATCH)) { - int doc_index; + printf ("%s: %s\n", name, shell_builtins[i].short_doc); - QUIT; - if ((strncmp (pattern, name, plen) == 0) || - (fnmatch (pattern, name, 0) != FNM_NOMATCH)) - { - printf ("%s: %s\n", name, shell_builtins[i].short_doc); + for (j = 0; shell_builtins[i].long_doc[j]; j++) + printf (" %s\n", shell_builtins[i].long_doc[j]); - for (doc_index = 0; - shell_builtins[i].long_doc[doc_index]; doc_index++) - printf (" %s\n", shell_builtins[i].long_doc[doc_index]); - - match_found++; - } - i++; + match_found++; } - list = list->next; } + } - if (!match_found) - { - fprintf (stderr, "No help topics match `%s'. Try `help help'.\n", - pattern); - fflush (stderr); - return (EXECUTION_FAILURE); - } + if (match_found == 0) + { + builtin_error ("no help topics match `%s'. Try `help help'.", pattern); + return (EXECUTION_FAILURE); } + fflush (stdout); return (EXECUTION_SUCCESS); } + +static void +show_builtin_command_help () +{ + int i, j; + char blurb[36]; + + printf ( +"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\ +\n\ +A star (*) next to a name means that the command is disabled.\n\ +\n"); + + for (i = 0; i < num_shell_builtins; i++) + { + QUIT; + blurb[0] = (shell_builtins[i].flags & BUILTIN_ENABLED) ? ' ' : '*'; + strncpy (blurb + 1, shell_builtins[i].short_doc, 34); + blurb[35] = '\0'; + printf ("%s", blurb); + + if (i % 2) + printf ("\n"); + else + for (j = strlen (blurb); j < 35; j++) + putc (' ', stdout); + } + if (i % 2) + printf ("\n"); +} +#endif /* HELP_BUILTIN */ diff --git a/builtins/history.def b/builtins/history.def index 814e705..939eb25 100644 --- a/builtins/history.def +++ b/builtins/history.def @@ -24,156 +24,277 @@ $PRODUCES history.c $BUILTIN history $FUNCTION history_builtin $DEPENDS_ON HISTORY -$SHORT_DOC history [n] [ [-awrn] [filename]] +$SHORT_DOC history [-c] [n] or history -awrn [filename] or history -ps arg [arg...] Display the history list with line numbers. Lines listed with with a `*' have been modified. Argument of N says to list only -the last N lines. Argument `-w' means to write out the current -history file; `-r' means to read it instead. Argument `-a' means +the last N lines. The -c option causes the history list to be +cleared by deleting all of the entries. The `-w' option writes out the +current history to the history file; `-r' means to read the file and +append the contents to the history list instead. `-a' means to append history lines from this session to the history file. Argument `-n' means to read all history lines not already read -from the history file. If FILENAME is given, then use that file, -else if $HISTFILE has a value, use that, else use ~/.bash_history. +from the history file and append them to the history list. If +FILENAME is given, then that is used as the history file else +if $HISTFILE has a value, that is used, else ~/.bash_history. +If the -s option is supplied, the non-option ARGs are appended to +the history list as a single entry. The -p option means to perform +history expansion on each ARG and display the result, without storing +anything in the history list. $END -#include "../shell.h" +#include + #if defined (HISTORY) #include #include -#include "../filecntl.h" #include "../posixstat.h" +#include "../filecntl.h" +#include +#include +#if defined (HAVE_UNISTD_H) +# include +#endif + +#include "../bashansi.h" + +#include "../shell.h" #include "../bashhist.h" #include +#include "bashgetopt.h" +#include "common.h" + +#if !defined (errno) +extern int errno; +#endif -/* History. Arg of -w FILENAME means write file, arg of -r FILENAME - means read file. Arg of N means only display that many items. */ +static void display_history (); +static void push_history (); +static int expand_and_print_history (); +#define AFLAG 0x01 +#define RFLAG 0x02 +#define WFLAG 0x04 +#define NFLAG 0x08 +#define SFLAG 0x10 +#define PFLAG 0x20 +#define CFLAG 0x40 + +int history_builtin (list) WORD_LIST *list; { - register int i; - int limited = 0, limit = 0; - HIST_ENTRY **hlist; + int flags, opt, result; + char *filename; - while (list) + flags = 0; + reset_internal_getopt (); + while ((opt = internal_getopt (list, "acnpsrw")) != -1) { - char *arg = list->word->word; - - if ((arg[0] == '-') && - (strlen (arg) == 2) && - (member (arg[1], "rwan"))) - { - char *file; - int result = EXECUTION_SUCCESS; - - if (list->next) - file = list->next->word->word; - else - file = get_string_value ("HISTFILE"); - - switch (arg[1]) - { - case 'a': /* Append `new' lines to file. */ - { - if (history_lines_this_session) - { - void using_history (); - - if (history_lines_this_session < where_history ()) - { - /* If the filename was supplied, then create it - if it doesn't already exist. */ - if (file) - { - struct stat buf; - - if (stat (file, &buf) == -1) - { - int tem; - - tem = open (file, O_CREAT, 0666); - close (tem); - } - } - - result = - append_history (history_lines_this_session, file); - history_lines_in_file += history_lines_this_session; - history_lines_this_session = 0; - } - } - break; - } - - case 'w': /* Write entire history. */ - { - result = write_history (file); - break; - } - - case 'r': /* Read entire file. */ - { - result = read_history (file); - break; - } - - case 'n': /* Read `new' history from file. */ - { - /* Read all of the lines in the file that we haven't - already read. */ - using_history (); - result = read_history_range (file, history_lines_in_file, -1); - using_history (); - history_lines_in_file = where_history (); - - break; - } - } - return (result ? EXECUTION_FAILURE : EXECUTION_SUCCESS); - } - else if (strcmp (list->word->word, "--") == 0) + switch (opt) { - list = list->next; + case 'a': + flags |= AFLAG; break; - } - else if (*list->word->word == '-') - { - bad_option (list->word->word); - builtin_error ("usage: history [n] [-rwan [filename]]"); + case 'c': + flags |= CFLAG; + break; + case 'n': + flags |= NFLAG; + break; + case 'r': + flags |= RFLAG; + break; + case 'w': + flags |= WFLAG; + break; + case 's': + flags |= SFLAG; + break; + case 'p': +#if defined (BANG_HISTORY) + flags |= PFLAG; +#endif + break; + default: + builtin_usage (); return (EX_USAGE); } - else - break; + } + list = loptend; + + opt = flags & (AFLAG|RFLAG|WFLAG|NFLAG); + if (opt && opt != AFLAG && opt != RFLAG && opt != WFLAG && opt != NFLAG) + { + builtin_error ("cannot use more than one of -anrw"); + return (EXECUTION_FAILURE); + } + + /* clear the history, but allow other arguments to add to it again. */ + if (flags & CFLAG) + { + clear_history (); + if (list == 0) + return (EXECUTION_SUCCESS); } + if (flags & SFLAG) + { + if (list) + push_history (list); + return (EXECUTION_SUCCESS); + } +#if defined (BANG_HISTORY) + else if (flags & PFLAG) + { + if (list) + return (expand_and_print_history (list)); + return (EXECUTION_SUCCESS); + } +#endif + else if ((flags & (AFLAG|RFLAG|NFLAG|WFLAG|CFLAG)) == 0) + { + display_history (list); + return (EXECUTION_SUCCESS); + } + + filename = list ? list->word->word : get_string_value ("HISTFILE"); + result = EXECUTION_SUCCESS; + + if (flags & AFLAG) /* Append session's history to file. */ + result = maybe_append_history (filename); + else if (flags & WFLAG) /* Write entire history. */ + result = write_history (filename); + else if (flags & RFLAG) /* Read entire file. */ + result = read_history (filename); + else if (flags & NFLAG) /* Read `new' history from file. */ + { + /* Read all of the lines in the file that we haven't already read. */ + using_history (); + result = read_history_range (filename, history_lines_in_file, -1); + using_history (); + history_lines_in_file = where_history (); + } + + return (result ? EXECUTION_FAILURE : EXECUTION_SUCCESS); +} + +/* Accessors for HIST_ENTRY lists that are called HLIST. */ +#define histline(i) (hlist[(i)]->line) +#define histdata(i) (hlist[(i)]->data) + +static void +display_history (list) + WORD_LIST *list; +{ + register int i; + int limited, limit; + HIST_ENTRY **hlist; + if (list) { limited = 1; limit = get_numeric_arg (list); } + else + limited = limit = 0; hlist = history_list (); if (hlist) { - for (i = 0; hlist[i]; i++); + for (i = 0; hlist[i]; i++) + ; if (limit < 0) limit = -limit; - if (!limited) + if ((limited == 0) || ((i -= limit) < 0)) i = 0; - else - if ((i -= limit) < 0) - i = 0; while (hlist[i]) { QUIT; printf ("%5d%c %s\n", i + history_base, - hlist[i]->data ? '*' : ' ', hlist[i]->line); + histdata(i) ? '*' : ' ', + histline(i)); i++; } } - return (EXECUTION_SUCCESS); } + +static int +delete_last_history () +{ + register int i; + HIST_ENTRY **hlist, *histent, *discard; + + hlist = history_list (); + if (hlist == NULL) + return 0; + + for (i = 0; hlist[i]; i++) + ; + i--; + + /* History_get () takes a parameter that must be offset by history_base. */ + histent = history_get (history_base + i); /* Don't free this */ + if (histent == NULL) + return 0; + + discard = remove_history (i); + if (discard) + { + if (discard->line) + free (discard->line); + free ((char *) discard); + } + return (1); +} + +/* Remove the last entry in the history list and add each argument in + LIST to the history. */ +static void +push_history (list) + WORD_LIST *list; +{ + char *s; + + if (delete_last_history () == 0) + return; + s = string_list (list); + maybe_add_history (s); /* Obeys HISTCONTROL setting. */ + free (s); +} + +#if defined (BANG_HISTORY) +static int +expand_and_print_history (list) + WORD_LIST *list; +{ + char *s; + int r, result; + + if (delete_last_history () == 0) + return EXECUTION_FAILURE; + result = EXECUTION_SUCCESS; + while (list) + { + r = history_expand (list->word->word, &s); + if (r < 0) + { + builtin_error ("%s: history expansion failed", list->word->word); + result = EXECUTION_FAILURE; + } + else + { + fputs (s, stdout); + putchar ('\n'); + } + FREE (s); + list = list->next; + } + fflush (stdout); + return result; +} +#endif /* BANG_HISTORY */ #endif /* HISTORY */ diff --git a/builtins/inlib.def b/builtins/inlib.def index 023945b..291eea1 100644 --- a/builtins/inlib.def +++ b/builtins/inlib.def @@ -20,6 +20,8 @@ with Bash; see the file COPYING. If not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. $PRODUCES inlib.c +#include + #include #include "../shell.h" diff --git a/builtins/jobs.def b/builtins/jobs.def index 8a293da..2896a76 100644 --- a/builtins/jobs.def +++ b/builtins/jobs.def @@ -1,5 +1,5 @@ This file is jobs.def, from which is created jobs.c. -It implements the builtin "jobs" in Bash. +It implements the builtins "jobs" and "disown" in Bash. Copyright (C) 1987, 1989, 1991, 1992 Free Software Foundation, Inc. @@ -24,24 +24,38 @@ $PRODUCES jobs.c $BUILTIN jobs $FUNCTION jobs_builtin $DEPENDS_ON JOB_CONTROL -$SHORT_DOC jobs [-lnp] [jobspec ...] | jobs -x command [args] +$SHORT_DOC jobs [-lnprs] [jobspec ...] or jobs -x command [args] Lists the active jobs. The -l option lists process id's in addition to the normal information; the -p option lists process id's only. If -n is given, only processes that have changed status since the last -notification are printed. JOBSPEC restricts output to that job. -If -x is given, COMMAND is run after all job specifications that appear -in ARGS have been replaced with the process ID of that job's process group -leader. +notification are printed. JOBSPEC restricts output to that job. The +-r and -s options restrict output to running and stopped jobs only, +respectively. Without options, the status of all active jobs is +printed. If -x is given, COMMAND is run after all job specifications +that appear in ARGS have been replaced with the process ID of that job's +process group leader. $END -#include "../shell.h" +#include #if defined (JOB_CONTROL) -#include +#include "../bashtypes.h" #include -#include "../jobs.h" +#if defined (HAVE_UNISTD_H) +# include +#endif + +#include "../bashansi.h" +#include "../shell.h" +#include "../jobs.h" +#include "../execute_cmd.h" #include "bashgetopt.h" +#include "common.h" + +#define JSTATE_ANY 0x0 +#define JSTATE_RUNNING 0x1 +#define JSTATE_STOPPED 0x2 extern int job_control, interactive_shell; static int execute_list_with_replacements (); @@ -52,20 +66,24 @@ static int execute_list_with_replacements (); pid only. If `-n' is given, only processes that have changed status since the last notification are printed. If -x is given, replace all job specs with the pid of the appropriate process - group leader and execute the command. */ + group leader and execute the command. The -r and -s options mean + to print info about running and stopped jobs only, respectively. */ int jobs_builtin (list) WORD_LIST *list; { - int form = JLIST_STANDARD, execute = 0; - int opt; - int any_failed = 0; + int form, execute, state, opt, any_failed, job; + sigset_t set, oset; - if (!job_control && !interactive_shell) + if (job_control == 0 && interactive_shell == 0) return (EXECUTION_SUCCESS); + execute = any_failed = 0; + form = JLIST_STANDARD; + state = JSTATE_ANY; + reset_internal_getopt (); - while ((opt = internal_getopt (list, "lpnx")) != -1) + while ((opt = internal_getopt (list, "lpnxrs")) != -1) { switch (opt) { @@ -86,9 +104,15 @@ jobs_builtin (list) } execute++; break; + case 'r': + state = JSTATE_RUNNING; + break; + case 's': + state = JSTATE_STOPPED; + break; default: - builtin_error ("usage: jobs [-lpn [jobspec]] [-x command [args]]"); + builtin_usage (); return (EX_USAGE); } } @@ -100,21 +124,29 @@ jobs_builtin (list) if (!list) { - list_jobs (form); + switch (state) + { + case JSTATE_ANY: + list_all_jobs (form); + break; + case JSTATE_RUNNING: + list_running_jobs (form); + break; + case JSTATE_STOPPED: + list_stopped_jobs (form); + break; + } return (EXECUTION_SUCCESS); } while (list) { - int job; - sigset_t set, oset; - BLOCK_CHILD (set, oset); job = get_job_spec (list); if ((job == NO_JOB) || !jobs || !jobs[job]) { - builtin_error ("No such job %s", list->word->word); + builtin_error ("no such job %s", list->word->word); any_failed++; } else if (job != DUP_JOB) @@ -169,3 +201,62 @@ execute_list_with_replacements (list) return (result); } #endif /* JOB_CONTROL */ + +$BUILTIN disown +$FUNCTION disown_builtin +$DEPENDS_ON JOB_CONTROL +$SHORT_DOC disown [-h] [jobspec ...] +By default, removes each JOBSPEC argument from the table of active jobs. +If the -h option is given, the job is not removed from the table, but is +marked so that SIGHUP is not sent to the job if the shell receives a +SIGHUP. +$END + +#if defined (JOB_CONTROL) +int +disown_builtin (list) + WORD_LIST *list; +{ + int opt, job, retval, nohup_only; + sigset_t set, oset; + + nohup_only = 0; + reset_internal_getopt (); + while ((opt = internal_getopt (list, "h")) != -1) + { + switch (opt) + { + case 'h': + nohup_only = 1; + break; + default: + builtin_usage (); + return (EX_USAGE); + } + } + list = loptend; + retval = EXECUTION_SUCCESS; + + do + { + BLOCK_CHILD (set, oset); + job = get_job_spec (list); + + if (job == NO_JOB || jobs == 0 || jobs[job] == 0) + { + builtin_error ("no such job %s", list->word->word); + retval = EXECUTION_FAILURE; + } + else if (nohup_only) + nohup_job (job); + else + delete_job (job); + UNBLOCK_CHILD (oset); + + if (list) + list = list->next; + } + while (list); + return (retval); +} +#endif /* JOB_CONTROL */ diff --git a/builtins/kill.def b/builtins/kill.def index 53d5c8f..ba779bf 100644 --- a/builtins/kill.def +++ b/builtins/kill.def @@ -24,7 +24,7 @@ $PRODUCES kill.c $BUILTIN kill $FUNCTION kill_builtin $DEPENDS_ON JOB_CONTROL -$SHORT_DOC kill [-s sigspec | -sigspec] [pid | job]... | -l [signum] +$SHORT_DOC kill [-s sigspec | -n signum | -sigspec] [pid | job]... or kill -l [sigspec] Send the processes named by PID (or JOB) the signal SIGSPEC. If SIGSPEC is not present, then SIGTERM is assumed. An argument of `-l' lists the signal names; if arguments follow `-l' they are assumed to @@ -34,17 +34,25 @@ process IDs, and, if you have reached the limit on processes that you can create, you don't have to start a process to kill another one. $END -/* Not all systems declare ERRNO in errno.h... and some systems #define it! */ -#if !defined (errno) -extern int errno; -#endif /* !errno */ +#include + +#include +#include +#if defined (HAVE_UNISTD_H) +# include +#endif + +#include "../bashansi.h" -#include "../bashtypes.h" #include "../shell.h" #include "../trap.h" #include "../jobs.h" #include "common.h" -#include + +/* Not all systems declare ERRNO in errno.h... and some systems #define it! */ +#if !defined (errno) +extern int errno; +#endif /* !errno */ #if defined (JOB_CONTROL) extern int interactive; @@ -63,14 +71,17 @@ int kill_builtin (list) WORD_LIST *list; { - int signal = SIGTERM; - int any_succeeded = 0, listing = 0, saw_signal = 0; - char *sigspec = "TERM", *word; + int signal, any_succeeded, listing, saw_signal; + char *sigspec, *word; pid_t pid; - if (!list) + if (list == 0) return (EXECUTION_SUCCESS); + any_succeeded = listing = saw_signal = 0; + signal = SIGTERM; + sigspec = "TERM"; + /* Process options. */ while (list) { @@ -81,13 +92,13 @@ kill_builtin (list) listing++; list = list->next; } - else if (ISOPTION (word, 's')) + else if (ISOPTION (word, 's') || ISOPTION (word, 'n')) { list = list->next; if (list) { sigspec = list->word->word; - if (sigspec[0] == '0' && !sigspec[1]) + if (sigspec[0] == '0' && sigspec[1] == '\0') signal = 0; else signal = decode_signal (sigspec); @@ -95,7 +106,7 @@ kill_builtin (list) } else { - builtin_error ("-s requires an argument"); + builtin_error ("%s requires an argument", word); return (EXECUTION_FAILURE); } } @@ -104,6 +115,11 @@ kill_builtin (list) list = list->next; break; } + else if (ISOPTION (word, '?')) + { + builtin_usage (); + return (EXECUTION_SUCCESS); + } /* If this is a signal specification then process it. We only process the first one seen; other arguments may signify process groups (e.g, -num == process group num). */ @@ -119,75 +135,7 @@ kill_builtin (list) } if (listing) - { - if (!list) - { - register int i; - register int column = 0; - char *name; - - for (i = 1; i < NSIG; i++) - { - name = signal_name (i); - if (STREQN (name, "SIGJUNK", 7) || STREQN (name, "Unknown", 7)) - continue; - - if (posixly_correct) - printf ("%s%s", name, (i == NSIG - 1) ? "" : " "); - else - { - printf ("%2d) %s", i, name); - - if (++column < 4) - printf ("\t"); - else - { - printf ("\n"); - column = 0; - } - } - } - - if (posixly_correct || column != 0) - printf ("\n"); - } - else - { - /* List individual signal names. */ - while (list) - { - int signum; - char *name; - - if ((sscanf (list->word->word, "%d", &signum) != 1) || - (signum <= 0)) - { - list_error: - builtin_error ("bad signal number: %s", list->word->word); - list = list->next; - continue; - } - - /* This is specified by Posix.2 so that exit statuses can be - mapped into signal numbers. */ - if (signum > 128) - signum -= 128; - - if (signum >= NSIG) - goto list_error; - - name = signal_name (signum); - if (STREQN (name, "SIGJUNK", 7) || STREQN (name, "Unknown", 7)) - { - list = list->next; - continue; - } - printf ("%s\n", name); - list = list->next; - } - } - return (EXECUTION_SUCCESS); - } + return (display_signal_list (list, 0)); /* OK, we are killing processes. */ if (signal == NO_SIG) @@ -215,15 +163,11 @@ kill_builtin (list) } else if (*list->word->word != '%') { - builtin_error ("No such pid %s", list->word->word); + builtin_error ("%s: no such pid", list->word->word); CONTINUE_OR_FAIL; } -#if 1 else if (interactive) /* Posix.2 says you can kill without job control active (4.32.4) */ -#else - else if (job_control) /* can't kill jobs if not using job control */ -#endif { /* Must be a job spec. Check it out. */ int job; sigset_t set, oset; @@ -234,7 +178,7 @@ kill_builtin (list) if (job < 0 || job >= job_slots || !jobs[job]) { if (job != DUP_JOB) - builtin_error ("No such job %s", list->word->word); + builtin_error ("%s: no such job", list->word->word); UNBLOCK_CHILD (oset); CONTINUE_OR_FAIL; } @@ -243,10 +187,7 @@ kill_builtin (list) without job control, then its pgrp == shell_pgrp, so we have to be careful. We take the pid of the first job in the pipeline in that case. */ - if (jobs[job]->flags & J_JOBCONTROL) - pid = jobs[job]->pgrp; - else - pid = jobs[job]->pipe->pid; + pid = IS_JOBCONTROL (job) ? jobs[job]->pgrp : jobs[job]->pipe->pid; UNBLOCK_CHILD (oset); @@ -266,16 +207,13 @@ kill_builtin (list) } else { - builtin_error ("bad process specification `%s'", list->word->word); + builtin_error ("`%s' is not a pid or valid job spec", list->word->word); CONTINUE_OR_FAIL; } continue_killing: list = list->next; } - if (any_succeeded) - return (EXECUTION_SUCCESS); - else - return (EXECUTION_FAILURE); + return (any_succeeded ? EXECUTION_SUCCESS : EXECUTION_FAILURE); } #endif /* JOB_CONTROL */ diff --git a/builtins/let.def b/builtins/let.def index fdb3a6f..60b6675 100644 --- a/builtins/let.def +++ b/builtins/let.def @@ -29,13 +29,23 @@ by 0 is trapped and flagged as an error. The following list of operators is grouped into levels of equal-precedence operators. The levels are listed in order of decreasing precedence. - - unary minus - ! logical NOT - * / % multiplication, division, remainder - + - addition, subtraction - <= >= < > comparison - == != equality inequality - = assignment + -, + unary minus, plus + !, ~ logical and bitwise negation + *, /, % multiplication, division, remainder + +, - addition, subtraction + <<, >> left and right bitwise shifts + <=, >=, <, > comparison + ==, != equality, inequality + & bitwise AND + ^ bitwise XOR + | bitwise OR + && logical AND + || logical OR + expr ? expr : expr + conditional expression + =, *=, /=, %=, + +=, -=, <<=, >>=, + &=, ^=, |= assignment Shell variables are allowed as operands. The name of the variable is replaced by its value (coerced to a long integer) within @@ -50,28 +60,49 @@ If the last ARG evaluates to 0, let returns 1; 0 is returned otherwise. $END +#include + +#if defined (HAVE_UNISTD_H) +# include +#endif + #include "../shell.h" +#include "common.h" /* Arithmetic LET function. */ +int let_builtin (list) WORD_LIST *list; { - long ret = 0L; + long ret; - if (!list) + if (list == 0) { - builtin_error ("argument (expression) expected"); + builtin_error ("expression expected"); return (EXECUTION_FAILURE); } - while (list) + for (; list; list = list->next) + ret = evalexp (list->word->word); + + return ((ret == 0L) ? EXECUTION_FAILURE : EXECUTION_SUCCESS); +} + +int +exp_builtin (list) + WORD_LIST *list; +{ + char *exp; + int ret; + + if (list == 0) { - ret = evalexp (list->word->word); - list = list->next; + builtin_error ("expression expected"); + return (EXECUTION_FAILURE); } - if (ret == 0L) - return (EXECUTION_FAILURE); - else - return (EXECUTION_SUCCESS); + exp = string_list (list); + ret = evalexp (exp); + free (exp); + return ((ret == 0L) ? EXECUTION_FAILURE : EXECUTION_SUCCESS); } diff --git a/builtins/mkbuiltins.c b/builtins/mkbuiltins.c index 572d01e..ae93bd4 100644 --- a/builtins/mkbuiltins.c +++ b/builtins/mkbuiltins.c @@ -19,6 +19,12 @@ 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, 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include + +#if defined (HAVE_UNISTD_H) +# include +#endif + #include "../bashansi.h" #include "../config.h" #include @@ -50,6 +56,7 @@ extern char *strcpy (); /* Flag values that builtins can have. */ #define BUILTIN_FLAG_SPECIAL 0x01 +#define BUILTIN_FLAG_ASSIGNMENT 0x02 /* If this stream descriptor is non-zero, then write texinfo documentation to it. */ @@ -115,12 +122,41 @@ char *special_builtins[] = "export", "readonly", "return", "set", "shift", "trap", "unset", (char *)NULL }; + +/* The builtin commands that take assignment statements as arguments. */ +char *assignment_builtins[] = +{ + "alias", "declare", "export", "local", "readonly", "typeset", + (char *)NULL +}; + +/* Forward declarations. */ static int is_special_builtin (); +static int is_assignment_builtin (); + +void extract_info (); + +void file_error (); +void line_error (); + +void write_file_headers (); +void write_file_footers (); +void write_ifdefs (); +void write_endifs (); +void write_documentation (); +void write_longdocs (); +void write_builtins (); +void free_defs (); +void add_documentation (); + +void must_be_building (); +void remove_trailing_whitespace (); /* For each file mentioned on the command line, process it and write the information to STRUCTFILE and EXTERNFILE, while creating the production file if neccessary. */ +int main (argc, argv) int argc; char **argv; @@ -305,6 +341,7 @@ copy_string_array (array) } /* Add ELEMENT to ARRAY, growing the array if neccessary. */ +void array_add (element, array) char *element; ARRAY *array; @@ -324,6 +361,7 @@ array_add (element, array) } /* Free an allocated array and data pointer. */ +void array_free (array) ARRAY *array; { @@ -397,6 +435,7 @@ int output_cpp_line_info = 0; target. After the file has been processed, write out the names of builtins found in each $BUILTIN. Plain text found before the $PRODUCES is ignored, as is "$$ comment text". */ +void extract_info (filename, structfile, externfile) char *filename; FILE *structfile, *externfile; @@ -548,6 +587,7 @@ free_builtin (builtin) } /* Free all of the memory allocated to a DEF_FILE. */ +void free_defs (defs) DEF_FILE *defs; { @@ -592,6 +632,7 @@ strip_whitespace (string) } /* Remove only the trailing whitespace from STRING. */ +void remove_trailing_whitespace (string) char *string; { @@ -625,6 +666,7 @@ get_arg (for_whom, defs, string) } /* Error if not building a builtin. */ +void must_be_building (directive, defs) char *directive; DEF_FILE *defs; @@ -645,6 +687,7 @@ current_builtin (directive, defs) /* Add LINE to the long documentation for the current builtin. Ignore blank lines until the first non-blank line has been seen. */ +void add_documentation (defs, line) DEF_FILE *defs; char *line; @@ -670,38 +713,42 @@ builtin_handler (self, defs, arg) char *self, *arg; DEF_FILE *defs; { + BUILTIN_DESC *new; + char *name; + /* If we are already building a builtin, we cannot start a new one. */ if (building_builtin) - return (line_error (defs, "%s found before $END", self)); + { + line_error (defs, "%s found before $END", self); + return (-1); + } output_cpp_line_info++; /* Get the name of this builtin, and stick it in the array. */ - { - BUILTIN_DESC *new; - char *name; - - name = get_arg (self, defs, arg); - - /* If this is the first builtin, create the array to hold them. */ - if (!defs->builtins) - defs->builtins = array_create (sizeof (BUILTIN_DESC *)); - - new = (BUILTIN_DESC *)xmalloc (sizeof (BUILTIN_DESC)); - new->name = name; - new->function = (char *)NULL; - new->shortdoc = (char *)NULL; - new->docname = (char *)NULL; - new->longdoc = (ARRAY *)NULL; - new->dependencies = (ARRAY *)NULL; - new->flags = 0; - - if (is_special_builtin (name)) - new->flags |= BUILTIN_FLAG_SPECIAL; - - array_add ((char *)new, defs->builtins); - building_builtin = 1; - } + name = get_arg (self, defs, arg); + + /* If this is the first builtin, create the array to hold them. */ + if (!defs->builtins) + defs->builtins = array_create (sizeof (BUILTIN_DESC *)); + + new = (BUILTIN_DESC *)xmalloc (sizeof (BUILTIN_DESC)); + new->name = name; + new->function = (char *)NULL; + new->shortdoc = (char *)NULL; + new->docname = (char *)NULL; + new->longdoc = (ARRAY *)NULL; + new->dependencies = (ARRAY *)NULL; + new->flags = 0; + + if (is_special_builtin (name)) + new->flags |= BUILTIN_FLAG_SPECIAL; + if (is_assignment_builtin (name)) + new->flags |= BUILTIN_FLAG_ASSIGNMENT; + + array_add ((char *)new, defs->builtins); + building_builtin = 1; + return (0); } @@ -744,6 +791,7 @@ docname_handler (self, defs, arg) } /* How to handle the $SHORT_DOC directive. */ +int short_doc_handler (self, defs, arg) char *self, *arg; DEF_FILE *defs; @@ -762,13 +810,16 @@ short_doc_handler (self, defs, arg) } /* How to handle the $COMMENT directive. */ +int comment_handler (self, defs) char *self; DEF_FILE *defs; { + return (0); } /* How to handle the $DEPENDS_ON directive. */ +int depends_on_handler (self, defs, arg) char *self, *arg; DEF_FILE *defs; @@ -788,6 +839,7 @@ depends_on_handler (self, defs, arg) } /* How to handle the $PRODUCES directive. */ +int produces_handler (self, defs, arg) char *self, *arg; DEF_FILE *defs; @@ -820,12 +872,14 @@ produces_handler (self, defs, arg) } /* How to handle the $END directive. */ +int end_handler (self, defs, arg) char *self, *arg; DEF_FILE *defs; { must_be_building (self, defs); building_builtin = 0; + return (0); } /* **************************************************************** */ @@ -835,6 +889,7 @@ end_handler (self, defs, arg) /* **************************************************************** */ /* Produce an error for DEFS with FORMAT and ARGS. */ +void line_error (defs, format, arg1, arg2) DEF_FILE *defs; char *format, *arg1, *arg2; @@ -848,6 +903,7 @@ line_error (defs, format, arg1, arg2) } /* Print error message for FILENAME. */ +void file_error (filename) char *filename; { @@ -895,7 +951,7 @@ xrealloc (pointer, bytes) static void memory_error_and_abort () { - fprintf (stderr, "mkbuiltins: Out of virtual memory!\n"); + fprintf (stderr, "mkbuiltins: out of virtual memory\n"); abort (); } @@ -929,6 +985,7 @@ copy_builtin (builtin) } /* How to save away a builtin. */ +void save_builtin (builtin) BUILTIN_DESC *builtin; { @@ -972,7 +1029,7 @@ char *structfile_header[] = { " along with Bash; see the file COPYING. If not, write to the Free", " Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */", "", - "/* The list of shell builtins. Each element is name, function, enabled-p,", + "/* The list of shell builtins. Each element is name, function, flags,", " long-doc, short-doc. The long-doc field contains a pointer to an array", " of help lines. The function takes a WORD_LIST *; the first word in the", " list is the first arg to the command. The list has already had word", @@ -992,13 +1049,17 @@ char *structfile_footer[] = { " { (char *)0x0, (Function *)0x0, 0, (char **)0x0, (char *)0x0 }", "};", "", + "struct builtin *shell_builtins = static_shell_builtins;", + "struct builtin *current_builtin;", + "", "int num_shell_builtins =", - "\tsizeof (shell_builtins) / sizeof (struct builtin) - 1;", + "\tsizeof (static_shell_builtins) / sizeof (struct builtin) - 1;", (char *)NULL }; /* Write out any neccessary opening information for STRUCTFILE and EXTERNFILE. */ +void write_file_headers (structfile, externfile) FILE *structfile, *externfile; { @@ -1011,7 +1072,7 @@ write_file_headers (structfile, externfile) fprintf (structfile, "#include \"%s\"\n", extern_filename ? extern_filename : "builtext.h"); - fprintf (structfile, "\nstruct builtin shell_builtins[] = {\n"); + fprintf (structfile, "\nstruct builtin static_shell_builtins[] = {\n"); } if (externfile) @@ -1022,6 +1083,7 @@ write_file_headers (structfile, externfile) /* Write out any necessary closing information for STRUCTFILE and EXTERNFILE. */ +void write_file_footers (structfile, externfile) FILE *structfile, *externfile; { @@ -1037,6 +1099,7 @@ write_file_footers (structfile, externfile) /* Write out the information accumulated in DEFS to STRUCTFILE and EXTERNFILE. */ +void write_builtins (defs, structfile, externfile) DEF_FILE *defs; FILE *structfile, *externfile; @@ -1057,8 +1120,7 @@ write_builtins (defs, structfile, externfile) { if (builtin->dependencies) { - if (builtin->function) - write_ifdefs (externfile, builtin->dependencies->array); + write_ifdefs (externfile, builtin->dependencies->array); write_ifdefs (structfile, builtin->dependencies->array); } @@ -1083,20 +1145,14 @@ write_builtins (defs, structfile, externfile) else fprintf (structfile, "(Function *)0x0, "); -#define SPECIAL_FLAG_STRING "BUILTIN_ENABLED | STATIC_BUILTIN | SPECIAL_BUILTIN" -#define NORMAL_FLAG_STRING "BUILTIN_ENABLED | STATIC_BUILTIN" - - fprintf (structfile, "%s, %s_doc,\n", - (builtin->flags & BUILTIN_FLAG_SPECIAL) ? - SPECIAL_FLAG_STRING : - NORMAL_FLAG_STRING, + fprintf (structfile, "%s%s%s, %s_doc,\n", + "BUILTIN_ENABLED | STATIC_BUILTIN", + (builtin->flags & BUILTIN_FLAG_SPECIAL) ? " | SPECIAL_BUILTIN" : "", + (builtin->flags & BUILTIN_FLAG_ASSIGNMENT) ? " | ASSIGNMENT_BUILTIN" : "", builtin->docname ? builtin->docname : builtin->name); -#undef SPECIAL_FLAG_STRING -#undef NORMAL_FLAG_STRING - fprintf - (structfile, " \"%s\" },\n", + (structfile, " \"%s\", (char *)NULL },\n", builtin->shortdoc ? builtin->shortdoc : builtin->name); /* Save away this builtin for later writing of the @@ -1126,6 +1182,7 @@ write_builtins (defs, structfile, externfile) } /* Write out the long documentation strings in BUILTINS to STREAM. */ +void write_longdocs (stream, builtins) FILE *stream; ARRAY *builtins; @@ -1157,6 +1214,7 @@ write_longdocs (stream, builtins) DEFINES is a null terminated array of define names. If a define is preceded by an `!', then the sense of the test is reversed. */ +void write_ifdefs (stream, defines) FILE *stream; char **defines; @@ -1187,6 +1245,7 @@ write_ifdefs (stream, defines) of the immediately preceding code. STREAM is the stream to write the information to. DEFINES is a null terminated array of define names. */ +void write_endifs (stream, defines) FILE *stream; char **defines; @@ -1211,6 +1270,7 @@ write_endifs (stream, defines) /* Write DOCUMENTAION to STREAM, perhaps surrounding it with double-quotes and quoting special characters in the string. */ +void write_documentation (stream, documentation, indentation, flags) FILE *stream; char **documentation; @@ -1218,14 +1278,14 @@ write_documentation (stream, documentation, indentation, flags) { register int i, j; register char *line; - int string_array = (flags & STRING_ARRAY); /* Mutually exclusive. */ - int texinfo = (flags & TEXINFO); + int string_array, texinfo; if (!stream) return; + string_array = flags & STRING_ARRAY; if (string_array) - fprintf (stream, " {\n"); + fprintf (stream, " {\n#if defined (HELP_BUILTIN)\n"); #if !defined (OLDCODE) /* XXX -- clean me up; for experiment only */ @@ -1233,7 +1293,7 @@ write_documentation (stream, documentation, indentation, flags) goto end_of_document; #endif /* !OLDCODE */ - for (i = 0; line = documentation[i]; i++) + for (i = 0, texinfo = (flags & TEXINFO); line = documentation[i]; i++) { /* Allow #ifdef's to be written out verbatim. */ if (*line == '#') @@ -1295,17 +1355,31 @@ end_of_document: #endif /* !OLDCODE */ if (string_array) - fprintf (stream, " (char *)NULL\n};\n"); + fprintf (stream, "#endif /* HELP_BUILTIN */\n (char *)NULL\n};\n"); } static int -is_special_builtin (name) - char *name; +_find_in_table (name, name_table) + char *name, *name_table[]; { register int i; - for (i = 0; special_builtins[i]; i++) - if (strcmp (name, special_builtins[i]) == 0) + for (i = 0; name_table[i]; i++) + if (strcmp (name, name_table[i]) == 0) return 1; return 0; } + +static int +is_special_builtin (name) + char *name; +{ + return (_find_in_table (name, special_builtins)); +} + +static int +is_assignment_builtin (name) + char *name; +{ + return (_find_in_table (name, assignment_builtins)); +} diff --git a/builtins/psize.c b/builtins/psize.c index 03a4f6e..0ba1c51 100644 --- a/builtins/psize.c +++ b/builtins/psize.c @@ -21,6 +21,11 @@ /* Write output in 128-byte chunks until we get a sigpipe or write gets an EPIPE. Then report how many bytes we wrote. We assume that this is the pipe size. */ +#include + +#if defined (HAVE_UNISTD_H) +# include +#endif #include #include @@ -29,6 +34,7 @@ #include "../command.h" #include "../general.h" +#include "../sig.h" extern int errno; int nw; diff --git a/builtins/pushd.def b/builtins/pushd.def new file mode 100644 index 0000000..3eadae0 --- /dev/null +++ b/builtins/pushd.def @@ -0,0 +1,604 @@ +This file is pushd.def, from which is created pushd.c. It implements the +builtins "pushd", "popd", and "dirs" in Bash. + +Copyright (C) 1987, 1989, 1991 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 1, 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, 675 Mass Ave, Cambridge, MA 02139, USA. + +$PRODUCES pushd.c + +$BUILTIN pushd +$FUNCTION pushd_builtin +$DEPENDS_ON PUSHD_AND_POPD +$SHORT_DOC pushd [dir | +N | -N] [-n] +Adds a directory to the top of the directory stack, or rotates +the stack, making the new top of the stack the current working +directory. With no arguments, exchanges the top two directories. + ++N Rotates the stack so that the Nth directory (counting + from the left of the list shown by `dirs') is at the top. + +-N Rotates the stack so that the Nth directory (counting + from the right) is at the top. + +-n suppress the normal change of directory when adding directories + to the stack, so only the stack is manipulated. + +dir adds DIR to the directory stack at the top, making it the + new current working directory. + +You can see the directory stack with the `dirs' command. +$END + +$BUILTIN popd +$FUNCTION popd_builtin +$DEPENDS_ON PUSHD_AND_POPD +$SHORT_DOC popd [+N | -N] [-n] +Removes entries from the directory stack. With no arguments, +removes the top directory from the stack, and cd's to the new +top directory. + ++N removes the Nth entry counting from the left of the list + shown by `dirs', starting with zero. For example: `popd +0' + removes the first directory, `popd +1' the second. + +-N removes the Nth entry counting from the right of the list + shown by `dirs', starting with zero. For example: `popd -0' + removes the last directory, `popd -1' the next to last. + +-n suppress the normal change of directory when removing directories + from the stack, so only the stack is manipulated. + +You can see the directory stack with the `dirs' command. +$END + +$BUILTIN dirs +$FUNCTION dirs_builtin +$DEPENDS_ON PUSHD_AND_POPD +$SHORT_DOC dirs [-clpv] [+N] [-N] +Display the list of currently remembered directories. Directories +find their way onto the list with the `pushd' command; you can get +back up through the list with the `popd' command. + +The -l flag specifies that `dirs' should not print shorthand versions +of directories which are relative to your home directory. This means +that `~/bin' might be displayed as `/homes/bfox/bin'. The -v flag +causes `dirs' to print the directory stack with one entry per line, +prepending the directory name with its position in the stack. The -p +flag does the same thing, but the stack position is not prepended. +The -c flag clears the directory stack by deleting all of the elements. + ++N displays the Nth entry counting from the left of the list shown by + dirs when invoked without options, starting with zero. + +-N displays the Nth entry counting from the right of the list shown by + dirs when invoked without options, starting with zero. +$END + +#include + +#if defined (PUSHD_AND_POPD) +#include +#include + +#if defined (HAVE_UNISTD_H) +# include +#endif + +#include "../bashansi.h" + +#include + +#include + +#include "../shell.h" +#include "../maxpath.h" +#include "common.h" +#include "builtext.h" + +#if !defined (errno) +extern int errno; +#endif /* !errno */ + +static char *m_badarg = "%s: bad argument"; + +/* The list of remembered directories. */ +static char **pushd_directory_list = (char **)NULL; + +/* Number of existing slots in this list. */ +static int directory_list_size; + +/* Offset to the end of the list. */ +static int directory_list_offset; + +static void pushd_error (); +static void clear_directory_stack (); +static int cd_to_string (); +static int change_to_temp (); +static int get_dirstack_index (); +static void add_dirstack_element (); + +#define NOCD 0x01 +#define ROTATE 0x02 +#define LONGFORM 0x04 +#define CLEARSTAK 0x08 + +int +pushd_builtin (list) + WORD_LIST *list; +{ + char *temp, *current_directory, *top; + int j, flags; + long num; + char direction; + + /* If there is no argument list then switch current and + top of list. */ + if (list == 0) + { + if (directory_list_offset == 0) + { + builtin_error ("no other directory"); + return (EXECUTION_FAILURE); + } + + current_directory = get_working_directory ("pushd"); + if (current_directory == 0) + return (EXECUTION_FAILURE); + + j = directory_list_offset - 1; + temp = pushd_directory_list[j]; + pushd_directory_list[j] = current_directory; + j = change_to_temp (temp); + free (temp); + return j; + } + + for (flags = 0; list; list = list->next) + { + if (ISOPTION (list->word->word, 'n')) + { + flags |= NOCD; + } + else if (ISOPTION (list->word->word, '-')) + { + list = list->next; + break; + } + else if (list->word->word[0] == '-' && list->word->word[1] == '\0') + /* Let `pushd -' work like it used to. */ + break; + else if (((direction = list->word->word[0]) == '+') || direction == '-') + { + if (legal_number (list->word->word + 1, &num) == 0) + { + builtin_error (m_badarg, list->word->word); + builtin_usage (); + return (EXECUTION_FAILURE); + } + + if (direction == '-') + num = directory_list_offset - num; + + if (num > directory_list_offset || num < 0) + { + pushd_error (directory_list_offset, list->word->word); + return (EXECUTION_FAILURE); + } + flags |= ROTATE; + } + else if (*list->word->word == '-') + { + bad_option (list->word->word); + builtin_usage (); + return (EXECUTION_FAILURE); + } + else + break; + } + + if (flags & ROTATE) + { + /* Rotate the stack num times. Remember, the current + directory acts like it is part of the stack. */ + temp = get_working_directory ("pushd"); + + if (num == 0) + { + j = ((flags & NOCD) == 0) ? change_to_temp (temp) : EXECUTION_SUCCESS; + free (temp); + return j; + } + + do + { + top = pushd_directory_list[directory_list_offset - 1]; + + for (j = directory_list_offset - 2; j > -1; j--) + pushd_directory_list[j + 1] = pushd_directory_list[j]; + + pushd_directory_list[j + 1] = temp; + + temp = top; + num--; + } + while (num); + + j = ((flags & NOCD) == 0) ? change_to_temp (temp) : EXECUTION_SUCCESS; + free (temp); + return j; + } + + if (list == 0) + return (EXECUTION_SUCCESS); + + /* Change to the directory in list->word->word. Save the current + directory on the top of the stack. */ + current_directory = get_working_directory ("pushd"); + if (current_directory == 0) + return (EXECUTION_FAILURE); + + j = ((flags & NOCD) == 0) ? cd_builtin (list) : EXECUTION_SUCCESS; + if (j == EXECUTION_SUCCESS) + { + add_dirstack_element ((flags & NOCD) ? savestring (list->word->word) : current_directory); + dirs_builtin ((WORD_LIST *)NULL); + return (EXECUTION_SUCCESS); + } + else + { + free (current_directory); + return (EXECUTION_FAILURE); + } +} + +/* Pop the directory stack, and then change to the new top of the stack. + If LIST is non-null it should consist of a word +N or -N, which says + what element to delete from the stack. The default is the top one. */ +int +popd_builtin (list) + WORD_LIST *list; +{ + register int i; + long which; + int flags; + char direction; + + for (flags = 0, which = 0L, direction = '+'; list; list = list->next) + { + if (ISOPTION (list->word->word, 'n')) + { + flags |= NOCD; + } + else if (ISOPTION (list->word->word, '-')) + { + list = list->next; + break; + } + else if (((direction = list->word->word[0]) == '+') || direction == '-') + { + if (legal_number (list->word->word + 1, &which) == 0) + { + builtin_error (m_badarg, list->word->word); + builtin_usage (); + return (EXECUTION_FAILURE); + } + } + else if (*list->word->word == '-') + { + bad_option (list->word->word); + builtin_usage (); + return (EXECUTION_FAILURE); + } + else + break; + } + + if (which > directory_list_offset || (directory_list_offset == 0 && which == 0)) + { + pushd_error (directory_list_offset, list ? list->word->word : ""); + return (EXECUTION_FAILURE); + } + + /* Handle case of no specification, or top of stack specification. */ + if ((direction == '+' && which == 0) || + (direction == '-' && which == directory_list_offset)) + { + i = ((flags & NOCD) == 0) ? cd_to_string (pushd_directory_list[directory_list_offset - 1]) + : EXECUTION_SUCCESS; + if (i != EXECUTION_SUCCESS) + return (i); + free (pushd_directory_list[--directory_list_offset]); + } + else + { + /* Since an offset other than the top directory was specified, + remove that directory from the list and shift the remainder + of the list into place. */ + i = (direction == '+') ? directory_list_offset - which : which; + free (pushd_directory_list[i]); + directory_list_offset--; + + /* Shift the remainder of the list into place. */ + for (; i < directory_list_offset; i++) + pushd_directory_list[i] = pushd_directory_list[i + 1]; + } + + dirs_builtin ((WORD_LIST *)NULL); + return (EXECUTION_SUCCESS); +} + +/* Print the current list of directories on the directory stack. */ +int +dirs_builtin (list) + WORD_LIST *list; +{ + int flags, desired_index, index_flag, vflag; + long i; + char *temp, *w; + + for (flags = vflag = index_flag = 0, desired_index = -1, w = ""; list; list = list->next) + { + if (ISOPTION (list->word->word, 'l')) + { + flags |= LONGFORM; + } + else if (ISOPTION (list->word->word, 'c')) + { + flags |= CLEARSTAK; + } + else if (ISOPTION (list->word->word, 'v')) + { + vflag |= 2; + } + else if (ISOPTION (list->word->word, 'p')) + { + vflag |= 1; + } + else if (ISOPTION (list->word->word, '-')) + { + list = list->next; + break; + } + else if (*list->word->word == '+' || *list->word->word == '-') + { + int sign; + if (legal_number (w = list->word->word + 1, &i) == 0) + { + builtin_error (m_badarg, list->word->word); + builtin_usage (); + return (EXECUTION_FAILURE); + } + sign = (*list->word->word == '+') ? 1 : -1; + desired_index = get_dirstack_index (i, sign, &index_flag); + } + else + { + bad_option (list->word->word); + builtin_usage (); + return (EXECUTION_FAILURE); + } + } + + if (flags & CLEARSTAK) + { + clear_directory_stack (); + return (EXECUTION_SUCCESS); + } + + if (index_flag && (desired_index < 0 || desired_index > directory_list_offset)) + { + pushd_error (directory_list_offset, w); + return (EXECUTION_FAILURE); + } + +#define DIRSTACK_FORMAT(temp) \ + (flags & LONGFORM) ? temp : polite_directory_format (temp) + + /* The first directory printed is always the current working directory. */ + if (index_flag == 0 || (index_flag == 1 && desired_index == 0)) + { + temp = get_working_directory ("dirs"); + if (temp == 0) + temp = savestring (""); + if (vflag & 2) + printf ("%2d %s", 0, DIRSTACK_FORMAT (temp)); + else + printf ("%s", DIRSTACK_FORMAT (temp)); + free (temp); + if (index_flag) + { + putchar ('\n'); + return EXECUTION_SUCCESS; + } + } + +#define DIRSTACK_ENTRY(i) \ + (flags & LONGFORM) ? pushd_directory_list[i] \ + : polite_directory_format (pushd_directory_list[i]) + + /* Now print the requested directory stack entries. */ + if (index_flag) + { + if (vflag & 2) + printf ("%2d %s", directory_list_offset - desired_index, + DIRSTACK_ENTRY (desired_index)); + else + printf ("%s", DIRSTACK_ENTRY (desired_index)); + } + else + for (i = directory_list_offset - 1; i >= 0; i--) + if (vflag >= 2) + printf ("\n%2d %s", directory_list_offset - (int)i, DIRSTACK_ENTRY (i)); + else + printf ("%s%s", (vflag & 1) ? "\n" : " ", DIRSTACK_ENTRY (i)); + + putchar ('\n'); + fflush (stdout); + return (EXECUTION_SUCCESS); +} + +static void +pushd_error (offset, arg) + int offset; + char *arg; +{ + if (offset == 0) + builtin_error ("directory stack empty"); + else if (arg) + builtin_error ("%s: bad directory stack index", arg); + else + builtin_error ("bad directory stack index"); +} + +static void +clear_directory_stack () +{ + register int i; + + for (i = 0; i < directory_list_offset; i++) + free (pushd_directory_list[i]); + directory_list_offset = 0; +} + +/* Switch to the directory in NAME. This uses the cd_builtin to do the work, + so if the result is EXECUTION_FAILURE then an error message has already + been printed. */ +static int +cd_to_string (name) + char *name; +{ + WORD_LIST *tlist; + int result; + + tlist = make_word_list (make_word (name), NULL); + result = cd_builtin (tlist); + dispose_words (tlist); + return (result); +} + +static int +change_to_temp (temp) + char *temp; +{ + int tt; + + tt = temp ? cd_to_string (temp) : EXECUTION_FAILURE; + + if (tt == EXECUTION_SUCCESS) + dirs_builtin ((WORD_LIST *)NULL); + + return (tt); +} + +static void +add_dirstack_element (dir) + char *dir; +{ + int j; + + if (directory_list_offset == directory_list_size) + { + j = (directory_list_size += 10) * sizeof (char *); + pushd_directory_list = (char **)xrealloc (pushd_directory_list, j); + } + pushd_directory_list[directory_list_offset++] = dir; +} + +static int +get_dirstack_index (ind, sign, indexp) + int ind, sign, *indexp; +{ + if (indexp) + *indexp = sign > 0 ? 1 : 2; + + /* dirs +0 prints the current working directory. */ + /* dirs -0 prints last element in directory stack */ + if (ind == 0 && sign > 0) + return 0; + else if (ind == directory_list_offset) + { + if (indexp) + *indexp = sign > 0 ? 2 : 1; + return 0; + } + else + return (sign > 0 ? directory_list_offset - ind : ind); +} + +char * +get_dirstack_element (ind, sign) + int ind, sign; +{ + int i; + + i = get_dirstack_index (ind, sign, (int *)NULL); + return (i < 0 || i > directory_list_offset) ? (char *)NULL + : pushd_directory_list[i]; +} + +void +set_dirstack_element (ind, sign, value) + int ind, sign; + char *value; +{ + int i; + + i = get_dirstack_index (ind, sign, (int *)NULL); + if (ind == 0 || i < 0 || i > directory_list_offset) + return; + free (pushd_directory_list[i]); + pushd_directory_list[i] = savestring (value); +} + +WORD_LIST * +get_directory_stack () +{ + register int i; + WORD_LIST *ret; + char *d, *t; + + for (ret = (WORD_LIST *)NULL, i = 0; i < directory_list_offset; i++) + { + d = polite_directory_format (pushd_directory_list[i]); + ret = make_word_list (make_word (d), ret); + } + /* Now the current directory. */ + d = get_working_directory ("dirstack"); + i = 0; /* sentinel to decide whether or not to free d */ + if (d == 0) + d = "."; + else + { + t = polite_directory_format (d); + /* polite_directory_format sometimes returns its argument unchanged. + If it does not, we can free d right away. If it does, we need to + mark d to be deleted later. */ + if (t != d) + { + free (d); + d = t; + } + else /* t == d, so d is what we want */ + i = 1; + } + ret = make_word_list (make_word (d), ret); + if (i) + free (d); + return ret; /* was (REVERSE_LIST (ret, (WORD_LIST *)); */ +} +#endif /* PUSHD_AND_POPD */ diff --git a/builtins/read.def b/builtins/read.def index 7b6dfc9..eb04a30 100644 --- a/builtins/read.def +++ b/builtins/read.def @@ -23,101 +23,170 @@ $PRODUCES read.c $BUILTIN read $FUNCTION read_builtin -$SHORT_DOC read [-r] [name ...] +$SHORT_DOC read [-r] [-p prompt] [-a array] [-e] [name ...] One line is read from the standard input, and the first word is -assigned to the first NAME, the second word to the second NAME, etc. -with leftover words assigned to the last NAME. Only the characters +assigned to the first NAME, the second word to the second NAME, and so +on, with leftover words assigned to the last NAME. Only the characters found in $IFS are recognized as word delimiters. The return code is -zero, unless end-of-file is encountered. If the -r option is given, -this signifies `raw' input, and backslash processing is disabled. +zero, unless end-of-file is encountered. If no NAMEs are supplied, the +line read is stored in the REPLY variable. If the -r option is given, +this signifies `raw' input, and backslash escaping is disabled. If +the `-p' option is supplied, the string supplied as an argument is +output without a trailing newline before attempting to read. If -a is +supplied, the words read are assigned to sequential indices of ARRAY, +starting at zero. If -e is supplied and the shell is interactive, +readline is used to obtain the line. $END +#include + #include + +#if defined (HAVE_UNISTD_H) +# include +#endif + #include "../shell.h" #include "common.h" +#include "bashgetopt.h" -#define issep(c) (strchr (ifs_chars, (c)) != (char *)0) +#if defined (READLINE) +#include "../bashline.h" +#include +#endif -static int stream_close (); +#define issep(c) (strchr (ifs_chars, (c))) extern int interrupt_immediately; +#if defined (READLINE) +static char *edit_line (); +#endif +static SHELL_VAR *bind_read_variable (); + /* Read the value of the shell variables whose names follow. The reading is done from the current input stream, whatever that may be. Successive words of the input line are assigned to the variables mentioned in LIST. The last variable in LIST gets the remainder of the words on the line. If no variables - are mentioned in LIST, then the default variable is $REPLY. - - S. R. Bourne's shell complains if you don't name a variable - to receive the stuff that is read. GNU's shell doesn't. This - allows you to let the user type random things. */ + are mentioned in LIST, then the default variable is $REPLY. */ +int read_builtin (list) WORD_LIST *list; { register char *varname; - int size, c, i, fildes, raw_mode, pass_next, saw_escape, retval; - char *input_string, *orig_input_string, *ifs_chars, *t; - FILE *input_stream; + int size, i, raw, pass_next, saw_escape, eof, opt, retval, edit; + char c; + char *input_string, *orig_input_string, *ifs_chars, *prompt, *arrayname; + char *e, *t, *t1; SHELL_VAR *var; +#if defined (ARRAY_VARS) + WORD_LIST *alist; +#endif +#if defined (READLINE) + char *rlbuf; + int rlind; +#endif i = 0; /* Index into the string that we are reading. */ - raw_mode = 0; /* Not reading raw input be default. */ + raw = edit = 0; /* Not reading raw input by default. */ + arrayname = prompt = (char *)NULL; + +#if defined (READLINE) + rlbuf = (char *)0; + rlind = 0; +#endif - while (list) + reset_internal_getopt (); + while ((opt = internal_getopt (list, "erp:a:")) != -1) { - if (ISOPTION (list->word->word, 'r')) - { - raw_mode = 1; - list = list->next; - } - else if (ISOPTION (list->word->word, '-')) - { - list = list->next; + switch (opt) + { + case 'r': + raw = 1; break; - } - else if (*list->word->word == '-') - { - bad_option (list->word->word); - builtin_error ("usage: read [-r] [name ...]"); + case 'p': + prompt = list_optarg; + break; + case 'e': +#if defined (READLINE) + edit = 1; +#endif + break; +#if defined (ARRAY_VARS) + case 'a': + arrayname = list_optarg; + break; +#endif + default: + builtin_usage (); return (EX_USAGE); } - else - break; - } - - /* We need unbuffered input from stdin. So we make a new stream with - the same file descriptor as stdin, then unbuffer it. */ - fildes = dup (fileno (stdin)); - - if (fildes == -1) - return (EXECUTION_FAILURE); - - input_stream = fdopen (fildes, "r"); - - if (!input_stream) - { - close (fildes); - return (EXECUTION_FAILURE); } + list = loptend; + /* IF IFS is unset, we use the default of " \t\n". */ var = find_variable ("IFS"); ifs_chars = var ? value_cell (var) : " \t\n"; - - input_string = xmalloc (size = 128); + if (ifs_chars == 0) /* XXX */ + ifs_chars = ""; /* XXX */ - setbuf (input_stream, (char *)NULL); + input_string = xmalloc (size = 128); begin_unwind_frame ("read_builtin"); add_unwind_protect (xfree, input_string); - add_unwind_protect (stream_close, input_stream); +#if defined (READLINE) + add_unwind_protect (xfree, rlbuf); +#endif interrupt_immediately++; + /* If the -p or -e flags were given, but input is not coming from the + terminal, turn them off. */ + if ((prompt || edit) && (isatty (0) == 0)) + { + prompt = (char *)NULL; + edit = 0; + } + + if (prompt && edit == 0) + { + fprintf (stderr, "%s", prompt); + fflush (stderr); + } + pass_next = 0; /* Non-zero signifies last char was backslash. */ saw_escape = 0; /* Non-zero signifies that we saw an escape char */ - while ((c = getc (input_stream)) != EOF) + for (eof = 0;;) { +#if defined (READLINE) + if (edit) + { + if (rlbuf && rlbuf[rlind] == '\0') + { + free (rlbuf); + rlbuf = (char *)0; + } + if (rlbuf == 0) + { + rlbuf = edit_line (prompt ? prompt : ""); + rlind = 0; + } + if (rlbuf == 0) + { + eof = 1; + break; + } + c = rlbuf[rlind++]; + } + else +#endif + if (read (0, &c, 1) != 1) + { + eof = 1; + break; + } + if (i + 2 >= size) input_string = xrealloc (input_string, size += 128); @@ -133,7 +202,7 @@ read_builtin (list) continue; } - if (c == '\\' && !raw_mode) + if (c == '\\' && raw == 0) { pass_next++; saw_escape++; @@ -157,15 +226,31 @@ read_builtin (list) interrupt_immediately--; discard_unwind_frame ("read_builtin"); - fclose (input_stream); + retval = eof ? EXECUTION_FAILURE : EXECUTION_SUCCESS; - if (c == EOF) +#if defined (ARRAY_VARS) + /* If -a was given, take the string read, break it into a list of words, + an assign them to `arrayname' in turn. */ + if (arrayname) { - retval = EXECUTION_FAILURE; - /* input_string[0] = '\0'; */ + var = find_variable (arrayname); + if (var == 0) + var = make_new_array_variable (arrayname); + else if (array_p (var) == 0) + var = convert_var_to_array (var); + + empty_array (array_cell (var)); + + alist = list_string (input_string, ifs_chars, 0); + if (alist) + { + assign_array_var_from_word_list (var, alist); + dispose_words (alist); + } + free (input_string); + return (retval); } - else - retval = EXECUTION_SUCCESS; +#endif /* ARRAY_VARS */ if (!list) { @@ -179,98 +264,140 @@ read_builtin (list) var = bind_variable ("REPLY", input_string); var->attributes &= ~att_invisible; free (input_string); + return (retval); } - else + + /* This code implements the Posix.2 spec for splitting the words + read and assigning them to variables. */ + orig_input_string = input_string; + + /* Remove IFS white space at the beginning of the input string. If + $IFS is null, no field splitting is performed. */ + for (t = input_string; ifs_chars && *ifs_chars && spctabnl(*t) && issep(*t); t++) + ; + input_string = t; + + for (; list->next; list = list->next) { - /* This code implements the Posix.2 spec for splitting the words - read and assigning them to variables. If $IFS is unset, we - use the default value of " \t\n". */ - orig_input_string = input_string; - - /* Remove IFS white space at the beginning of the input string. If - $IFS is null, no field splitting is performed. */ - for (t = input_string; *ifs_chars && spctabnl (*t) && issep (*t); t++) - ; - input_string = t; - - for (; list->next; list = list->next) + varname = list->word->word; +#if defined (ARRAY_VARS) + if (legal_identifier (varname) == 0 && valid_array_reference (varname) == 0) +#else + if (legal_identifier (varname) == 0) +#endif { - char *e, *t1; - - varname = list->word->word; - if (legal_identifier (varname) == 0) - { - builtin_error ("%s: not a legal variable name", varname); - free (orig_input_string); - return (EXECUTION_FAILURE); - } + builtin_error ("`%s': not a valid identifier", varname); + free (orig_input_string); + return (EXECUTION_FAILURE); + } - /* If there are more variables than words read from the input, - the remaining variables are set to the empty string. */ - if (*input_string) + /* If there are more variables than words read from the input, + the remaining variables are set to the empty string. */ + if (*input_string) + { + /* This call updates INPUT_STRING. */ + t = get_word_from_string (&input_string, ifs_chars, &e); + if (t) + *e = '\0'; + /* Don't bother to remove the CTLESC unless we added one + somewhere while reading the string. */ + if (t && saw_escape) { - /* This call updates INPUT_STRING. */ - t = get_word_from_string (&input_string, ifs_chars, &e); - if (t) - *e = '\0'; - /* Don't bother to remove the CTLESC unless we added one - somewhere while reading the string. */ - if (t && saw_escape) - { - t1 = dequote_string (t); - var = bind_variable (varname, t1); - free (t1); - } - else - var = bind_variable (varname, t); + t1 = dequote_string (t); + var = bind_read_variable (varname, t1); + free (t1); } else - { - t = (char *)0; - var = bind_variable (varname, ""); - } - - stupidly_hack_special_variables (varname); - var->attributes &= ~att_invisible; - - if (t) - free (t); + var = bind_read_variable (varname, t); + } + else + { + t = (char *)0; + var = bind_read_variable (varname, ""); } - if (legal_identifier (list->word->word) == 0) + FREE (t); + if (var == 0) { - builtin_error ("%s: not a legal variable name", list->word->word); free (orig_input_string); return (EXECUTION_FAILURE); } - /* This has to be done this way rather than using string_list - and list_string because Posix.2 says that the last variable gets the - remaining words and their intervening separators. */ - input_string = strip_trailing_ifs_whitespace (input_string, ifs_chars, - saw_escape); - - if (saw_escape) - { - t = dequote_string (input_string); - var = bind_variable (list->word->word, t); - free (t); - } - else - var = bind_variable (list->word->word, input_string); - stupidly_hack_special_variables (list->word->word); + stupidly_hack_special_variables (varname); var->attributes &= ~att_invisible; + } + + /* Now assign the rest of the line to the last variable argument. */ +#if defined (ARRAY_VARS) + if (legal_identifier (list->word->word) == 0 && valid_array_reference (list->word->word) == 0) +#else + if (legal_identifier (list->word->word) == 0) +#endif + { + builtin_error ("`%s': not a valid identifier", list->word->word); free (orig_input_string); + return (EXECUTION_FAILURE); } + /* This has to be done this way rather than using string_list + and list_string because Posix.2 says that the last variable gets the + remaining words and their intervening separators. */ + input_string = strip_trailing_ifs_whitespace (input_string, ifs_chars, saw_escape); + + if (saw_escape) + { + t = dequote_string (input_string); + var = bind_read_variable (list->word->word, t); + free (t); + } + else + var = bind_read_variable (list->word->word, input_string); + stupidly_hack_special_variables (list->word->word); + if (var) + var->attributes &= ~att_invisible; + free (orig_input_string); + return (retval); } -/* This way I don't have to know whether fclose () is a - function or a macro. */ -static int -stream_close (file) - FILE *file; +static SHELL_VAR * +bind_read_variable (name, value) + char *name, *value; +{ +#if defined (ARRAY_VARS) + if (valid_array_reference (name) == 0) + { + if (legal_identifier (name) == 0) + { + builtin_error ("`%s': not a valid identifier", name); + return ((SHELL_VAR *)NULL); + } + return (bind_variable (name, value)); + } + else + return (do_array_element_assignment (name, value)); +#else + return bind_variable (name, value); +#endif +} + +#if defined (READLINE) +static char * +edit_line (p) + char *p; { - return (fclose (file)); + char *ret; + int len; + + if (!bash_readline_initialized) + initialize_readline (); + ret = readline (p); + if (ret == 0) + return ret; + len = strlen (ret); + ret = xrealloc (ret, len + 2); + ret[len++] = '\n'; + ret[len] = '\0'; + return ret; } +#endif diff --git a/builtins/reserved.def b/builtins/reserved.def index 4074ae0..da59050 100644 --- a/builtins/reserved.def +++ b/builtins/reserved.def @@ -43,6 +43,15 @@ in the variable REPLY. COMMANDS are executed after each selection until a break or return command is executed. $END +$BUILTIN time +$SHORT_DOC time [-p] PIPELINE +Execute PIPELINE and print a summary of the real time, user CPU time, +and system CPU time spent executing PIPELINE when it terminates. +The return status is the return status of PIPELINE. The `-p' option +prints the timing summary in a slightly different format. This uses +the value of the TIMEFORMAT variable as the output format. +$END + $BUILTIN case $SHORT_DOC case WORD in [PATTERN [| PATTERN]...) COMMANDS ;;]... esac Selectively execute COMMANDS based upon WORD matching PATTERN. The @@ -97,10 +106,12 @@ $END $BUILTIN variables $DOCNAME variable_help $SHORT_DOC variables - Some variable names and meanings -BASH_VERSION The version numbers of this Bash. +BASH_VERSION Version information for this Bash. CDPATH A colon separated list of directories to search when the argument to `cd' is not found in the current directory. +GLOBIGNORE A colon-separated list of patterns describing filenames to + be ignored by pathname expansion. #if defined (HISTORY) HISTFILE The name of the file where your command history is stored. HISTFILESIZE The maximum number of lines this file can contain. @@ -108,22 +119,29 @@ HISTSIZE The maximum number of history lines that a running shell can access. #endif /* HISTORY */ HOME The complete pathname to your login directory. +HOSTNAME The name of the current host. HOSTTYPE The type of CPU this version of Bash is running under. IGNOREEOF Controls the action of the shell on receipt of an EOF character as the sole input. If set, then the value of it is the number of EOF characters that can be seen in a row on an empty line before the shell will exit (default 10). When unset, EOF signifies the end of input. +MACHTYPE A string describing the current system Bash is running on. MAILCHECK How often, in seconds, Bash checks for new mail. MAILPATH A colon-separated list of filenames which Bash checks for new mail. +OSTYPE The version of Unix this version of Bash is running on. PATH A colon-separated list of directories to search when looking for commands. PROMPT_COMMAND A command to be executed before the printing of each primary prompt. PS1 The primary prompt string. PS2 The secondary prompt string. +PWD The full pathname of the current directory. +SHELLOPTS A colon-separated list of enabled shell options. TERM The name of the current terminal type. +TIMEFORMAT The output format for timing statistics displayed by the + `time' reserved word. auto_resume Non-null means a command word appearing on a line by itself is first looked for in the list of currently stopped jobs. If found there, that job is foregrounded. @@ -133,9 +151,6 @@ auto_resume Non-null means a command word appearing on a line by match a substring of the job. Any other value means that the command must be a prefix of a stopped job. #if defined (HISTORY) -command_oriented_history - Non-null means to save multiple-line commands together on - a single history line. # if defined (BANG_HISTORY) histchars Characters controlling history expansion and quick substitution. The first character is the history @@ -143,12 +158,7 @@ histchars Characters controlling history expansion and quick the `quick substitution' character, usually `^'. The third is the `history comment' character, usually `#'. # endif /* BANG_HISTORY */ -HISTCONTROL Set to a value of `ignorespace', it means don't enter - lines which begin with a space or tab on the history - list. Set to a value of `ignoredups', it means don't - enter lines which match the last entered line. Set to - `ignoreboth' means to combine the two options. Unset, - or set to any other value than those above means to save - all lines on the history list. +HISTIGNORE A colon-separated list of patterns used to decide which + command should be saved on the history list. #endif /* HISTORY */ $END diff --git a/builtins/return.def b/builtins/return.def index 8340a44..2ab01ef 100644 --- a/builtins/return.def +++ b/builtins/return.def @@ -29,11 +29,17 @@ Causes a function to exit with the return value specified by N. If N is omitted, the return status is that of the last command. $END +#include + +#if defined (HAVE_UNISTD_H) +# include +#endif + #include "../shell.h" +#include "common.h" extern int last_command_exit_value; extern int return_catch_flag, return_catch_value; -extern jmp_buf return_catch; /* If we are executing a user-defined function then exit with the value specified as an argument. if no argument is given, then the last @@ -42,16 +48,13 @@ int return_builtin (list) WORD_LIST *list; { - return_catch_value = get_numeric_arg (list); - - if (!list) - return_catch_value = last_command_exit_value; + return_catch_value = list ? get_numeric_arg (list) : last_command_exit_value; if (return_catch_flag) longjmp (return_catch, 1); else { - builtin_error ("Can only `return' from a function"); + builtin_error ("can only `return' from a function or sourced script"); return (EXECUTION_FAILURE); } } diff --git a/builtins/set.def b/builtins/set.def index a97168c..d31e77e 100644 --- a/builtins/set.def +++ b/builtins/set.def @@ -21,62 +21,79 @@ Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. $PRODUCES set.c +#include + +#if defined (HAVE_UNISTD_H) +# include +#endif + #include + +#include "../bashansi.h" + #include "../shell.h" #include "../flags.h" - +#include "common.h" #include "bashgetopt.h" +#if defined (READLINE) +# include "../input.h" +# include "../bashline.h" +# include +#endif + +#if defined (HISTORY) +# include "../bashhist.h" +#endif + extern int interactive; -extern int noclobber, no_brace_expansion, posixly_correct; +extern int noclobber, posixly_correct, ignoreeof, eof_encountered_limit; #if defined (READLINE) extern int rl_editing_mode, no_line_editing; #endif /* READLINE */ -#define USAGE_STRING "set [--abefhknotuvxldHCP] [-o option] [arg ...]" - $BUILTIN set $FUNCTION set_builtin -$SHORT_DOC set [--abefhknotuvxldHCP] [-o option] [arg ...] +$SHORT_DOC set [--abefhkmnptuvxBCHP] [-o option] [arg ...] -a Mark variables which are modified or created for export. -b Notify of job termination immediately. -e Exit immediately if a command exits with a non-zero status. -f Disable file name generation (globbing). - -h Locate and remember function commands as functions are - defined. Function commands are normally looked up when - the function is executed. + -h Remember the location of commands as they are looked up. -i Force the shell to be an "interactive" one. Interactive shells always read `~/.bashrc' on startup. - -k All keyword arguments are placed in the environment for a + -k All assignment arguments are placed in the environment for a command, not just those that precede the command name. -m Job control is enabled. -n Read commands but do not execute them. -o option-name Set the variable corresponding to option-name: allexport same as -a - braceexpand the shell will perform brace expansion + braceexpand same as -B #if defined (READLINE) emacs use an emacs-style line editing interface #endif /* READLINE */ errexit same as -e + hashall same as -h #if defined (BANG_HISTORY) histexpand same as -H #endif /* BANG_HISTORY */ ignoreeof the shell will not exit upon reading EOF interactive-comments allow comments to appear in interactive commands + keyword same as -k monitor same as -m - noclobber disallow redirection to existing files + noclobber same as -C noexec same as -n noglob same as -f - nohash same as -d notify save as -b nounset same as -u - physical same as -P - posix change the behavior of bash where the default - operation differs from the 1003.2 standard to - match the standard - privileged same as -p + onecmd same as -t + physical same as -P + posix change the behavior of bash where the default + operation differs from the 1003.2 standard to + match the standard + privileged same as -p verbose same as -v #if defined (READLINE) vi use a vi-style line editing interface @@ -85,15 +102,14 @@ $SHORT_DOC set [--abefhknotuvxldHCP] [-o option] [arg ...] -p Turned on whenever the real and effective user ids do not match. Disables processing of the $ENV file and importing of shell functions. Turning this option off causes the effective uid and - gid to be set to the real uid and gid. + gid to be set to the real uid and gid. -t Exit after reading and executing one command. -u Treat unset variables as an error when substituting. -v Print shell input lines as they are read. -x Print commands and their arguments as they are executed. - -l Save and restore the binding of the NAME in a FOR command. - -d Disable the hashing of commands that are looked up for execution. - Normally, commands are remembered in a hash table, and once - found, do not have to be looked up again. +#if defined (BRACE_EXPANSION) + -B the shell will perform brace expansion +#endif /* BRACE_EXPANSION */ #if defined (BANG_HISTORY) -H Enable ! style history substitution. This flag is on by default. @@ -110,6 +126,20 @@ parameters and are assigned, in order, to $1, $2, .. $n. If no ARGs are given, all shell variables are printed. $END +static int set_ignoreeof (); + +#if defined (READLINE) +static int set_edit_mode (); +static int get_edit_mode (); +#endif + +#if defined (HISTORY) +static int bash_set_history (); +#endif + +static char *on = "on"; +static char *off = "off"; + /* An a-list used to match long options for set -o to the corresponding option letter. */ struct { @@ -117,201 +147,354 @@ struct { int letter; } o_options[] = { { "allexport", 'a' }, +#if defined (BRACE_EXPANSION) + { "braceexpand",'B' }, +#endif { "errexit", 'e' }, + { "hashall", 'h' }, #if defined (BANG_HISTORY) { "histexpand", 'H' }, #endif /* BANG_HISTORY */ + { "keyword", 'k' }, { "monitor", 'm' }, + { "noclobber", 'C' }, { "noexec", 'n' }, { "noglob", 'f' }, - { "nohash", 'd' }, #if defined (JOB_CONTROL) { "notify", 'b' }, #endif /* JOB_CONTROL */ - {"nounset", 'u' }, - {"physical", 'P' }, - {"privileged", 'p' }, - {"verbose", 'v' }, - {"xtrace", 'x' }, - {(char *)NULL, 0}, + { "nounset", 'u' }, + { "onecmd", 't' }, + { "physical", 'P' }, + { "privileged", 'p' }, + { "verbose", 'v' }, + { "xtrace", 'x' }, + {(char *)NULL, 0 }, +}; + +struct { + char *name; + int *variable; + Function *set_func; + Function *get_func; +} binary_o_options[] = { +#if defined (HISTORY) + { "history", &remember_on_history, bash_set_history, (Function *)NULL }, +#endif + { "ignoreeof", &ignoreeof, set_ignoreeof, (Function *)NULL }, + { "interactive-comments", &interactive_comments, (Function *)NULL, (Function *)NULL }, + { "posix", &posixly_correct, (Function *)NULL, (Function *)NULL }, +#if defined (READLINE) + { "emacs", (int *)NULL, set_edit_mode, get_edit_mode }, + { "vi", (int *)NULL, set_edit_mode, get_edit_mode }, +#endif + { (char *)NULL, (int *)NULL } }; +#define GET_BINARY_O_OPTION_VALUE(i, name) \ + ((binary_o_options[i].get_func) ? (*binary_o_options[i].get_func) (name) \ + : (*binary_o_options[i].variable)) + +#define SET_BINARY_O_OPTION_VALUE(i, onoff, name) \ + ((binary_o_options[i].set_func) ? (*binary_o_options[i].set_func) (onoff, name) \ + : (*binary_o_options[i].variable = (onoff == FLAG_ON))) + +int +minus_o_option_value (name) + char *name; +{ + register int i; + int *on_or_off; + + for (i = 0; o_options[i].name; i++) + { + if (STREQ (name, o_options[i].name)) + { + on_or_off = find_flag (o_options[i].letter); + return ((on_or_off == FLAG_UNKNOWN) ? -1 : *on_or_off); + } + } + for (i = 0; binary_o_options[i].name; i++) + { + if (STREQ (name, binary_o_options[i].name)) + return (GET_BINARY_O_OPTION_VALUE (i, name)); + } + + return (-1); +} + #define MINUS_O_FORMAT "%-15s\t%s\n" void -list_minus_o_opts () +list_minus_o_opts (mode) + int mode; { register int i; - char *on = "on", *off = "off"; + int *on_or_off, value; - printf (MINUS_O_FORMAT, "braceexpand", (no_brace_expansion == 0) ? on : off); - printf (MINUS_O_FORMAT, "noclobber", (noclobber == 1) ? on : off); + for (value = i = 0; o_options[i].name; i++) + { + on_or_off = find_flag (o_options[i].letter); + if (on_or_off == FLAG_UNKNOWN) + on_or_off = &value; + if (mode == -1 || mode == *on_or_off) + printf (MINUS_O_FORMAT, o_options[i].name, *on_or_off ? on : off); + } + for (i = 0; binary_o_options[i].name; i++) + { + value = GET_BINARY_O_OPTION_VALUE (i, binary_o_options[i].name); + if (mode == -1 || mode == value) + printf (MINUS_O_FORMAT, binary_o_options[i].name, value ? on : off); + } +} - if (find_variable ("ignoreeof") || find_variable ("IGNOREEOF")) - printf (MINUS_O_FORMAT, "ignoreeof", on); - else - printf (MINUS_O_FORMAT, "ignoreeof", off); +static void +minus_o_option_commands () +{ + register int i; + int *on_or_off, value; - printf (MINUS_O_FORMAT, "interactive-comments", - interactive_comments ? on : off); + for (value = i = 0; o_options[i].name; i++) + { + on_or_off = find_flag (o_options[i].letter); + if (on_or_off == FLAG_UNKNOWN) + on_or_off = &value; + printf ("set %co %s\n", *on_or_off ? '-' : '+', o_options[i].name); + } + for (i = 0; binary_o_options[i].name; i++) + { + value = GET_BINARY_O_OPTION_VALUE (i, binary_o_options[i].name); + printf ("set %co %s\n", value ? '-' : '+', binary_o_options[i].name); + } +} - printf (MINUS_O_FORMAT, "posix", posixly_correct ? on : off); +static int +set_ignoreeof (on_or_off, option_name) + int on_or_off; + char *option_name; +{ + ignoreeof = on_or_off == FLAG_ON; + unbind_variable ("ignoreeof"); + if (ignoreeof) + bind_variable ("IGNOREEOF", "10"); + else + unbind_variable ("IGNOREEOF"); + sv_ignoreeof ("IGNOREEOF"); + return 0; +} #if defined (READLINE) - if (no_line_editing) +/* Magic. This code `knows' how readline handles rl_editing_mode. */ +static int +set_edit_mode (on_or_off, option_name) + int on_or_off; + char *option_name; +{ + int isemacs; + + if (on_or_off == FLAG_ON) { - printf (MINUS_O_FORMAT, "emacs", off); - printf (MINUS_O_FORMAT, "vi", off); + rl_variable_bind ("editing-mode", option_name); + + if (interactive) + with_input_from_stdin (); + no_line_editing = 0; } else { - /* Magic. This code `knows' how readline handles rl_editing_mode. */ - printf (MINUS_O_FORMAT, "emacs", (rl_editing_mode == 1) ? on : off); - printf (MINUS_O_FORMAT, "vi", (rl_editing_mode == 0) ? on : off); + isemacs = rl_editing_mode == 1; + if ((isemacs && *option_name == 'e') || (!isemacs && *option_name == 'v')) + { + if (interactive) + with_input_from_stream (stdin, "stdin"); + no_line_editing = 1; + } } + return 1-no_line_editing; +} + +static int +get_edit_mode (name) + char *name; +{ + return (*name == 'e' ? no_line_editing == 0 && rl_editing_mode == 1 + : no_line_editing == 0 && rl_editing_mode == 0); +} #endif /* READLINE */ - for (i = 0; o_options[i].name; i++) +#if defined (HISTORY) +static int +bash_set_history (on_or_off, option_name) + int on_or_off; + char *option_name; +{ + if (on_or_off == FLAG_ON) { - int *on_or_off, zero = 0; - - on_or_off = find_flag (o_options[i].letter); - if (on_or_off == FLAG_UNKNOWN) - on_or_off = &zero; - printf (MINUS_O_FORMAT, o_options[i].name, (*on_or_off == 1) ? on : off); + bash_history_enable (); + if (history_lines_this_session == 0) + load_history (); } + else + bash_history_disable (); + return (1 - remember_on_history); } +#endif +int set_minus_o_option (on_or_off, option_name) int on_or_off; char *option_name; { - int option_char = -1; + int option_char; + VFunction *set_func; + register int i; - if (STREQ (option_name, "braceexpand")) + for (i = 0; binary_o_options[i].name; i++) { - if (on_or_off == FLAG_ON) - no_brace_expansion = 0; - else - no_brace_expansion = 1; + if (STREQ (option_name, binary_o_options[i].name)) + { + SET_BINARY_O_OPTION_VALUE (i, on_or_off, option_name); + return (EXECUTION_SUCCESS); + } } - else if (STREQ (option_name, "noclobber")) + + for (i = 0, option_char = -1, set_func = 0; o_options[i].name; i++) { - if (on_or_off == FLAG_ON) - bind_variable ("noclobber", ""); - else - unbind_variable ("noclobber"); - stupidly_hack_special_variables ("noclobber"); + if (STREQ (option_name, o_options[i].name)) + { + option_char = o_options[i].letter; + break; + } } - else if (STREQ (option_name, "ignoreeof")) + if (option_char == -1) { - unbind_variable ("ignoreeof"); - unbind_variable ("IGNOREEOF"); - if (on_or_off == FLAG_ON) - bind_variable ("IGNOREEOF", "10"); - stupidly_hack_special_variables ("IGNOREEOF"); + builtin_error ("%s: unknown option name", option_name); + return (EXECUTION_FAILURE); } - -#if defined (READLINE) - else if ((STREQ (option_name, "emacs")) || (STREQ (option_name, "vi"))) + if (change_flag (option_char, on_or_off) == FLAG_ERROR) { - if (on_or_off == FLAG_ON) - { - rl_variable_bind ("editing-mode", option_name); + bad_option (option_name); + return (EXECUTION_FAILURE); + } + return (EXECUTION_SUCCESS); +} - if (interactive) - with_input_from_stdin (); - no_line_editing = 0; - } - else - { - int isemacs = (rl_editing_mode == 1); - if ((isemacs && STREQ (option_name, "emacs")) || - (!isemacs && STREQ (option_name, "vi"))) - { - if (interactive) - with_input_from_stream (stdin, "stdin"); - no_line_editing = 1; - } - else - builtin_error ("not in %s editing mode", option_name); - } +static void +print_all_shell_variables () +{ + SHELL_VAR **vars; + + vars = all_shell_variables (); + if (vars) + { + print_var_list (vars); + free (vars); } -#endif /* READLINE */ - else if (STREQ (option_name, "interactive-comments")) - interactive_comments = (on_or_off == FLAG_ON); - else if (STREQ (option_name, "posix")) + + vars = all_shell_functions (); + if (vars) { - posixly_correct = (on_or_off == FLAG_ON); - unbind_variable ("POSIXLY_CORRECT"); - unbind_variable ("POSIX_PEDANTIC"); - if (on_or_off == FLAG_ON) - { - bind_variable ("POSIXLY_CORRECT", ""); - stupidly_hack_special_variables ("POSIXLY_CORRECT"); - } + print_var_list (vars); + free (vars); } - else +} + +void +set_shellopts () +{ + char *value; + int vsize, i, vptr, *ip; + SHELL_VAR *v; + + for (vsize = i = 0; o_options[i].name; i++) { - register int i; - for (i = 0; o_options[i].name; i++) - { - if (STREQ (option_name, o_options[i].name)) - { - option_char = o_options[i].letter; - break; - } - } - if (option_char == -1) - { - builtin_error ("%s: unknown option name", option_name); - return (EXECUTION_FAILURE); - } - if (change_flag (option_char, on_or_off) == FLAG_ERROR) + ip = find_flag (o_options[i].letter); + if (ip && *ip) + vsize += strlen (o_options[i].name) + 1; + } + for (i = 0; binary_o_options[i].name; i++) + if (GET_BINARY_O_OPTION_VALUE (i, binary_o_options[i].name)) + vsize += strlen (binary_o_options[i].name) + 1; + + value = xmalloc (vsize + 1); + + for (i = vptr = 0; o_options[i].name; i++) + { + ip = find_flag (o_options[i].letter); + if (ip && *ip) { - bad_option (option_name); - return (EXECUTION_FAILURE); + strcpy (value + vptr, o_options[i].name); + vptr += strlen (o_options[i].name); + value[vptr++] = ':'; } } - return (EXECUTION_SUCCESS); + for (i = 0; binary_o_options[i].name; i++) + if (GET_BINARY_O_OPTION_VALUE (i, binary_o_options[i].name)) + { + strcpy (value + vptr, binary_o_options[i].name); + vptr += strlen (binary_o_options[i].name); + value[vptr++] = ':'; + } + value[--vptr] = '\0'; /* cut off trailing colon */ + + v = find_variable ("SHELLOPTS"); + if (v) + v->attributes &= ~att_readonly; + v = bind_variable ("SHELLOPTS", value); + v->attributes |= att_readonly; + + free (value); +} + +void +parse_shellopts (value) + char *value; +{ + char *vname; + int vptr; + + vptr = 0; + while (vname = extract_colon_unit (value, &vptr)) + { + set_minus_o_option (FLAG_ON, vname); + free (vname); + } +} + +void +initialize_shell_options () +{ + char *temp; + + /* set up any shell options we may have inherited. */ + if (temp = get_string_value ("SHELLOPTS")) + parse_shellopts (temp); + + /* Set up the $SHELLOPTS variable. */ + set_shellopts (); } /* Set some flags from the word values in the input list. If LIST is empty, then print out the values of the variables instead. If LIST contains non-flags, then set $1 - $9 to the successive words of LIST. */ +int set_builtin (list) WORD_LIST *list; { - int on_or_off, flag_name, force_assignment = 0; + int on_or_off, flag_name, force_assignment, opts_changed; + WORD_LIST *l; + register char *arg; - if (!list) + if (list == 0) { - SHELL_VAR **vars; - - vars = all_shell_variables (); - if (vars) - { - print_var_list (vars); - free (vars); - } - - vars = all_shell_functions (); - if (vars) - { - print_var_list (vars); - free (vars); - } - + print_all_shell_variables (); return (EXECUTION_SUCCESS); } /* Check validity of flag arguments. */ if (*list->word->word == '-' || *list->word->word == '+') { - register char *arg; - WORD_LIST *save_list = list; - - while (list && (arg = list->word->word)) + for (l = list; l && (arg = l->word->word); l = l->next) { char c; @@ -319,8 +502,7 @@ set_builtin (list) break; /* `-' or `--' signifies end of flag arguments. */ - if (arg[0] == '-' && - (!arg[1] || (arg[1] == '-' && !arg[2]))) + if (arg[0] == '-' && (!arg[1] || (arg[1] == '-' && !arg[2]))) break; while (c = *++arg) @@ -331,30 +513,28 @@ set_builtin (list) s[0] = c; s[1] = '\0'; bad_option (s); if (c == '?') - printf ("usage: %s\n", USAGE_STRING); + builtin_usage (); return (c == '?' ? EXECUTION_SUCCESS : EXECUTION_FAILURE); } } - list = list->next; } - list = save_list; } /* Do the set command. While the list consists of words starting with '-' or '+' treat them as flags, otherwise, start assigning them to $1 ... $n. */ - while (list) + for (force_assignment = opts_changed = 0; list; ) { - char *string = list->word->word; + arg = list->word->word; /* If the argument is `--' or `-' then signal the end of the list and remember the remaining arguments. */ - if (string[0] == '-' && (!string[1] || (string[1] == '-' && !string[2]))) + if (arg[0] == '-' && (!arg[1] || (arg[1] == '-' && !arg[2]))) { list = list->next; /* `set --' unsets the positional parameters. */ - if (string[1] == '-') + if (arg[1] == '-') force_assignment = 1; /* Until told differently, the old shell behaviour of @@ -364,20 +544,19 @@ set_builtin (list) { change_flag ('x', '+'); change_flag ('v', '+'); + opts_changed = 1; } break; } - if ((on_or_off = *string) && - (on_or_off == '-' || on_or_off == '+')) + if ((on_or_off = *arg) && (on_or_off == '-' || on_or_off == '+')) { - int i = 1; - while (flag_name = string[i++]) + while (flag_name = *++arg) { if (flag_name == '?') { - printf ("usage: %s\n", USAGE_STRING); + builtin_usage (); return (EXECUTION_SUCCESS); } else if (flag_name == 'o') /* -+o option-name */ @@ -387,36 +566,47 @@ set_builtin (list) opt = list->next; - if (!opt) + if (opt == 0) { - list_minus_o_opts (); + if (on_or_off == '-') + list_minus_o_opts (-1); + else + minus_o_option_commands (); continue; } option_name = opt->word->word; - if (!option_name || !*option_name || (*option_name == '-')) + if (option_name == 0 || *option_name == '\0' || + *option_name == '-' || *option_name == '+') { - list_minus_o_opts (); + if (on_or_off == '-') + list_minus_o_opts (-1); + else + minus_o_option_commands (); continue; } list = list->next; /* Skip over option name. */ + opts_changed = 1; if (set_minus_o_option (on_or_off, option_name) != EXECUTION_SUCCESS) - return (EXECUTION_FAILURE); - } - else - { - if (change_flag (flag_name, on_or_off) == FLAG_ERROR) { - char opt[3]; - opt[0] = on_or_off; - opt[1] = flag_name; - opt[2] = '\0'; - bad_option (opt); + set_shellopts (); return (EXECUTION_FAILURE); } } + else if (change_flag (flag_name, on_or_off) == FLAG_ERROR) + { + char opt[3]; + opt[0] = on_or_off; + opt[1] = flag_name; + opt[2] = '\0'; + bad_option (opt); + builtin_usage (); + set_shellopts (); + return (EXECUTION_FAILURE); + } + opts_changed = 1; } } else @@ -429,6 +619,9 @@ set_builtin (list) /* Assigning $1 ... $n */ if (list || force_assignment) remember_args (list, 1); + /* Set up new value of $SHELLOPTS */ + if (opts_changed) + set_shellopts (); return (EXECUTION_SUCCESS); } @@ -443,13 +636,17 @@ function. Some variables (such as PATH and IFS) cannot be unset; also see readonly. $END +#define NEXT_VARIABLE() any_failed++; list = list->next; continue; + +int unset_builtin (list) WORD_LIST *list; { - int unset_function = 0, unset_variable = 0, opt; - int any_failed = 0; + int unset_function, unset_variable, unset_array, opt, any_failed; char *name; + unset_function = unset_variable = unset_array = any_failed = 0; + reset_internal_getopt (); while ((opt = internal_getopt (list, "fv")) != -1) { @@ -462,7 +659,8 @@ unset_builtin (list) unset_variable = 1; break; default: - return (EXECUTION_FAILURE); + builtin_usage (); + return (EX_USAGE); } } @@ -476,53 +674,69 @@ unset_builtin (list) while (list) { + SHELL_VAR *var; + int tem; +#if defined (ARRAY_VARS) + char *t; +#endif + name = list->word->word; - if (!unset_function && - find_name_in_list (name, non_unsettable_vars) > -1) +#if defined (ARRAY_VARS) + if (!unset_function && valid_array_reference (name)) { - builtin_error ("%s: cannot unset", name); - any_failed++; + t = strchr (name, '['); + *t++ = '\0'; + unset_array++; } - else +#endif + + var = unset_function ? find_function (name) : find_variable (name); + + if (var && !unset_function && non_unsettable_p (var)) { - SHELL_VAR *var; - int tem; + builtin_error ("%s: cannot unset", name); + NEXT_VARIABLE (); + } - var = unset_function ? find_function (name) : find_variable (name); + /* Posix.2 says that unsetting readonly variables is an error. */ + if (var && readonly_p (var)) + { + builtin_error ("%s: cannot unset: readonly %s", + name, unset_function ? "function" : "variable"); + NEXT_VARIABLE (); + } - /* Posix.2 says that unsetting readonly variables is an error. */ - if (var && readonly_p (var)) + /* Unless the -f option is supplied, the name refers to a variable. */ +#if defined (ARRAY_VARS) + if (var && unset_array) + { + if (array_p (var) == 0) { - builtin_error ("%s: cannot unset: readonly %s", - name, unset_function ? "function" : "variable"); - any_failed++; - list = list->next; - continue; + builtin_error ("%s: not an array variable", name); + NEXT_VARIABLE (); } - - /* Unless the -f option is supplied, the name refers to a - variable. */ - tem = makunbound - (name, unset_function ? shell_functions : shell_variables); - - /* This is what Posix.2 draft 11+ says. ``If neither -f nor -v - is specified, the name refers to a variable; if a variable by - that name does not exist, a function by that name, if any, - shall be unset.'' */ - if ((tem == -1) && !unset_function && !unset_variable) - tem = makunbound (name, shell_functions); - - if (tem == -1) - any_failed++; - else if (!unset_function) - stupidly_hack_special_variables (name); + else + tem = unbind_array_element (var, t); } + else +#endif /* ARRAY_VARS */ + tem = makunbound (name, unset_function ? shell_functions : shell_variables); + + /* This is what Posix.2 draft 11+ says. ``If neither -f nor -v + is specified, the name refers to a variable; if a variable by + that name does not exist, a function by that name, if any, + shall be unset.'' */ + if (tem == -1 && !unset_function && !unset_variable) + tem = makunbound (name, shell_functions); + + if (tem == -1) + any_failed++; + else if (!unset_function) + stupidly_hack_special_variables (name); + list = list->next; } - if (any_failed) - return (EXECUTION_FAILURE); - else - return (EXECUTION_SUCCESS); + return (any_failed ? EXECUTION_FAILURE : EXECUTION_SUCCESS); } diff --git a/builtins/setattr.def b/builtins/setattr.def index 2340e1a..a83f348 100644 --- a/builtins/setattr.def +++ b/builtins/setattr.def @@ -21,6 +21,15 @@ Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. $PRODUCES setattr.c +#include + +#if defined (HAVE_UNISTD_H) +# include +#endif + +#include +#include "../bashansi.h" + #include "../shell.h" #include "common.h" #include "bashgetopt.h" @@ -30,7 +39,7 @@ extern char *this_command_name; $BUILTIN export $FUNCTION export_builtin -$SHORT_DOC export [-n] [-f] [name ...] or export -p +$SHORT_DOC export [-nf] [name ...] or export -p NAMEs are marked for automatic export to the environment of subsequently executed commands. If the -f option is given, the NAMEs refer to functions. If no NAMEs are given, or if `-p' @@ -45,46 +54,51 @@ $END print all such variables. An argument of `-n' says to remove the exported attribute from variables named in LIST. An argument of -f indicates that the names present in LIST refer to functions. */ +int export_builtin (list) register WORD_LIST *list; { - return (set_or_show_attributes (list, att_exported)); + return (set_or_show_attributes (list, att_exported, 0)); } $BUILTIN readonly $FUNCTION readonly_builtin -$SHORT_DOC readonly [-n] [-f] [name ...] or readonly -p +$SHORT_DOC readonly [-anf] [name ...] or readonly -p The given NAMEs are marked readonly and the values of these NAMEs may not be changed by subsequent assignment. If the -f option is given, then functions corresponding to the NAMEs are so marked. If no arguments are given, or if `-p' is given, a list of all readonly names is printed. An argument of `-n' says to remove the readonly property -from subsequent NAMEs. An argument of `--' disables further option +from subsequent NAMEs. The `-a' option means to treat each NAME as +an array variable. An argument of `--' disables further option processing. $END /* For each variable name in LIST, make that variable readonly. Given an empty LIST, print out all existing readonly variables. */ +int readonly_builtin (list) register WORD_LIST *list; { - return (set_or_show_attributes (list, att_readonly)); + return (set_or_show_attributes (list, att_readonly, 0)); } /* For each variable name in LIST, make that variable have the specified ATTRIBUTE. An arg of `-n' says to remove the attribute from the the remaining names in LIST. */ int -set_or_show_attributes (list, attribute) +set_or_show_attributes (list, attribute, nodefs) register WORD_LIST *list; - int attribute; + int attribute, nodefs; { register SHELL_VAR *var; - int assign, undo = 0, functions_only = 0, any_failed = 0, opt; + int assign, undo, functions_only, arrays_only, any_failed, assign_error, opt; + char *name; + undo = functions_only = arrays_only = any_failed = assign_error = 0; /* Read arguments from the front of the list. */ reset_internal_getopt (); - while ((opt = internal_getopt (list, "nfp")) != -1) + while ((opt = internal_getopt (list, "anfp")) != -1) { switch (opt) { @@ -94,10 +108,15 @@ set_or_show_attributes (list, attribute) case 'f': functions_only = 1; break; +#if defined (ARRAY_VARS) + case 'a': + arrays_only = 1; + break; +#endif case 'p': break; default: - builtin_error ("usage: %s [-nfp] [varname]", this_command_name); + builtin_usage (); return (EX_USAGE); } } @@ -108,85 +127,56 @@ set_or_show_attributes (list, attribute) if (attribute & att_exported) array_needs_making = 1; - /* Cannot undo readonly status. */ + /* Cannot undo readonly status, silently disallowed. */ if (undo && (attribute & att_readonly)) attribute &= ~att_readonly; while (list) { - register char *name = list->word->word; + name = list->word->word; - if (functions_only) + if (functions_only) /* xxx -f name */ { var = find_function (name); - if (!var) + if (var == 0) { builtin_error ("%s: not a function", name); any_failed++; } else - { - if (undo) - var->attributes &= ~attribute; - else - var->attributes |= attribute; - } + SETVARATTR (var, attribute, undo); + list = list->next; - if (attribute == att_exported) - array_needs_making++; continue; } + /* xxx [-np] name[=value] */ assign = assignment (name); if (assign) name[assign] = '\0'; + if (legal_identifier (name) == 0) { - builtin_error ("%s: not a legal variable name", name); - any_failed++; + builtin_error ("`%s': not a valid identifier", name); + assign_error++; list = list->next; continue; } - if (assign) + if (assign) /* xxx [-np] name=value */ { name[assign] = '='; /* This word has already been expanded once with command and parameter expansion. Call do_assignment_no_expand (), - which does not do command or parameter substitution. */ - do_assignment_no_expand (name); + which does not do command or parameter substitution. If + the assignment is not performed correctly, flag an error. */ + if (do_assignment_no_expand (name) == 0) + assign_error++; name[assign] = '\0'; } - if (undo) - { - var = find_variable (name); - if (var) - var->attributes &= ~attribute; - } - else - { - SHELL_VAR *find_tempenv_variable (), *tv; - - if (tv = find_tempenv_variable (name)) - { - var = bind_variable (tv->name, tv->value); - dispose_variable (tv); - } - else - var = find_variable (name); - - if (!var) - { - var = bind_variable (name, (char *)NULL); - var->attributes |= att_invisible; - } - - var->attributes |= attribute; - } - - array_needs_making++; /* XXX */ + set_var_attribute (name, attribute, undo); list = list->next; } } @@ -204,50 +194,133 @@ set_or_show_attributes (list, attribute) else variable_list = all_shell_variables (); +#if defined (ARRAY_VARS) + if (attribute & att_array) + { + arrays_only++; + if (attribute != att_array) + attribute &= ~att_array; + } +#endif + if (variable_list) { for (i = 0; var = variable_list[i]; i++) { - if ((var->attributes & attribute) && !invisible_p (var)) - { - char flags[6]; +#if defined (ARRAY_VARS) + if (arrays_only && array_p (var) == 0) + continue; +#endif + if ((var->attributes & attribute) && invisible_p (var) == 0) + show_var_attributes (var, nodefs); + } + free (variable_list); + } + } + + return (assign_error ? EX_BADASSIGN + : ((any_failed == 0) ? EXECUTION_SUCCESS + : EXECUTION_FAILURE)); +} + +int +show_var_attributes (var, nodefs) + SHELL_VAR *var; + int nodefs; +{ + char flags[6], *x; + int i; - flags[0] = '\0'; + i = 0; - if (exported_p (var)) - strcat (flags, "x"); +#if defined (ARRAY_VARS) + if (array_p (var)) + flags[i++] = 'a'; +#endif - if (readonly_p (var)) - strcat (flags, "r"); + if (function_p (var)) + flags[i++] = 'f'; - if (function_p (var)) - strcat (flags, "f"); + if (integer_p (var)) + flags[i++] = 'i'; - if (integer_p (var)) - strcat (flags, "i"); + if (readonly_p (var)) + flags[i++] = 'r'; - if (flags[0]) - { - printf ("declare -%s ", flags); + if (exported_p (var)) + flags[i++] = 'x'; - if (!function_p (var)) - { - char *x = double_quote (value_cell (var)); - printf ("%s=%s\n", var->name, x); - free (x); - } - else - { - char *named_function_string (); + flags[i] = '\0'; - printf ("%s\n", named_function_string - (var->name, function_cell (var), 1)); - } - } - } - } - free (variable_list); + printf ("declare -%s ", i ? flags : "-"); + +#if defined (ARRAY_VARS) + if (array_p (var)) + print_array_assignment (var, 1); + else +#endif + if (nodefs) + printf ("%s\n", var->name); + else if (function_p (var)) + printf ("%s\n", named_function_string (var->name, function_cell (var), 1)); + else + { + x = double_quote (value_cell (var)); + printf ("%s=%s\n", var->name, x); + free (x); + } + return (0); +} + +int +show_name_attributes (name, nodefs) + char *name; + int nodefs; +{ + SHELL_VAR *var; + + var = find_tempenv_variable (name); + if (var == 0) + var = find_variable (name); + + if (var && invisible_p (var) == 0) + { + show_var_attributes (var, nodefs); + return (0); + } + else + return (1); +} + +void +set_var_attribute (name, attribute, undo) + char *name; + int attribute, undo; +{ + SHELL_VAR *var, *tv; + + if (undo) + var = find_variable (name); + else + { + if (tv = find_tempenv_variable (name)) + { + var = bind_variable (tv->name, tv->value); + dispose_variable (tv); + } + else + var = find_variable (name); + + if (var == 0) + { + var = bind_variable (name, (char *)NULL); + var->attributes |= att_invisible; } } - return (any_failed == 0 ? EXECUTION_SUCCESS : EXECUTION_FAILURE); + + if (var) + SETVARATTR (var, attribute, undo); + + if (var && ((var->attributes & att_exported) || (attribute & att_exported))) + array_needs_making++; /* XXX */ } diff --git a/builtins/shift.def b/builtins/shift.def index 4d8fed0..8af4d5d 100644 --- a/builtins/shift.def +++ b/builtins/shift.def @@ -21,13 +21,16 @@ Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. $PRODUCES shift.c -#if defined (HAVE_STRING_H) -# include -#else /* !HAVE_STRING_H */ -# include -#endif /* !HAVE_STRING_H */ +#include + +#if defined (HAVE_UNISTD_H) +# include +#endif + +#include "../bashansi.h" #include "../shell.h" +#include "common.h" $BUILTIN shift $FUNCTION shift_builtin @@ -36,6 +39,8 @@ The positional parameters from $N+1 ... are renamed to $1 ... If N is not given, it is assumed to be 1. $END +int print_shift_error; + /* Shift the arguments ``left''. Shift DOLLAR_VARS down then take one off of REST_OF_ARGS and place it into DOLLAR_VARS[9]. If LIST has anything in it, it is a number which says where to start the @@ -44,34 +49,28 @@ int shift_builtin (list) WORD_LIST *list; { - int times, number; - WORD_LIST *args; + int times; + register int count; + WORD_LIST *temp; times = get_numeric_arg (list); - if (!times) + if (times == 0) return (EXECUTION_SUCCESS); - - if (times < 0) + else if (times < 0) { builtin_error ("shift count must be >= 0"); return (EXECUTION_FAILURE); } - - args = list_rest_of_args (); - number = list_length (args); - dispose_words (args); - - if (times > number) + else if (times > number_of_args ()) { - builtin_error ("shift count must be <= $#"); + if (print_shift_error) + builtin_error ("shift count must be <= $#"); return (EXECUTION_FAILURE); } while (times-- > 0) { - register int count; - if (dollar_vars[1]) free (dollar_vars[1]); @@ -80,8 +79,7 @@ shift_builtin (list) if (rest_of_args) { - WORD_LIST *temp = rest_of_args; - + temp = rest_of_args; dollar_vars[9] = savestring (temp->word->word); rest_of_args = rest_of_args->next; temp->next = (WORD_LIST *)NULL; @@ -90,6 +88,5 @@ shift_builtin (list) else dollar_vars[9] = (char *)NULL; } - return (EXECUTION_SUCCESS); } diff --git a/builtins/shopt.def b/builtins/shopt.def new file mode 100644 index 0000000..5372bbb --- /dev/null +++ b/builtins/shopt.def @@ -0,0 +1,343 @@ +This file is shopt.def, from which is created shopt.c. +It implements the Bash `shopt' builtin. + +Copyright (C) 1994 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 1, 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, 675 Mass Ave, Cambridge, MA 02139, USA. + +$PRODUCES shopt.c + +$BUILTIN shopt +$DOCNAME shopt_builtin +$FUNCTION shopt_builtin +$SHORT_DOC shopt [-pqsu] [-o long-option] optname [optname...] +Toggle the values of variables controlling optional behavior. +The -s flag means to enable (set) each OPTNAME; the -u flag +unsets each OPTNAME. The -q flag suppresses output; the exit +status indicates whether each OPTNAME is set or unset. The -o +option restricts the OPTNAMEs to those defined for use with +`set -o'. With no options, or with the -p option, a list of all +settable options is displayed, with an indication of whether or +not each is set. +$END + +#include + +#if defined (HAVE_UNISTD_H) +# include +#endif + +#include + +#include "../shell.h" +#include "../flags.h" +#include "common.h" +#include "bashgetopt.h" + +#define UNSETOPT 0 +#define SETOPT 1 + +#define OPTFMT "%-15s\t%s\n" + +extern int allow_null_glob_expansion, glob_dot_filenames; +extern int cdable_vars, mail_warning, source_uses_path; +extern int no_exit_on_failed_exec, print_shift_error; +extern int check_hashed_filenames, promptvars, interactive_comments; +extern int cdspelling, expand_aliases; +extern int check_window_size; + +#if defined (HISTORY) +extern int hist_verify, literal_history, command_oriented_history; +extern int force_append_history; +#endif + +#if defined (READLINE) +extern int history_reediting, perform_hostname_completion; +extern void enable_hostname_completion (); +#endif + +static int set_interactive_comments (); + +static struct { + char *name; + int *value; + Function *set_func; +} shopt_vars[] = { + { "cdable_vars", &cdable_vars, (Function *)NULL }, + { "cdspell", &cdspelling, (Function *)NULL }, + { "checkhash", &check_hashed_filenames, (Function *)NULL }, + { "checkwinsize", &check_window_size, (Function *)NULL }, +#if defined (HISTORY) + { "cmdhist", &command_oriented_history, (Function *)NULL }, +#endif + { "dotglob", &glob_dot_filenames, (Function *)NULL }, + { "execfail", &no_exit_on_failed_exec, (Function *)NULL }, + { "expand_aliases", &expand_aliases, (Function *)NULL }, +#if defined (READLINE) + { "histreedit", &history_reediting, (Function *)NULL }, +#endif +#if defined (HISTORY) + { "histappend", &force_append_history, (Function *)NULL }, + { "histverify", &hist_verify, (Function *)NULL }, +#endif +#if defined (READLINE) + { "hostcomplete", &perform_hostname_completion, (Function *)enable_hostname_completion }, +#endif + { "interactive_comments", &interactive_comments, set_interactive_comments }, +#if defined (HISTORY) + { "lithist", &literal_history, (Function *)NULL }, +#endif + { "mailwarn", &mail_warning, (Function *)NULL }, + { "nullglob", &allow_null_glob_expansion, (Function *)NULL }, + { "promptvars", &promptvars, (Function *)NULL }, + { "shift_verbose", &print_shift_error, (Function *)NULL }, + { "sourcepath", &source_uses_path, (Function *)NULL }, + { (char *)0, (int *)0, (Function *)NULL } +}; + +static char *on = "on"; +static char *off = "off"; + +static int list_shopt_o_options (); +static int list_some_o_options (), list_some_shopts (); +static int toggle_shopts (), list_shopts (), set_shopt_o_options (); + +#define SFLAG 0x01 +#define UFLAG 0x02 +#define QFLAG 0x04 +#define OFLAG 0x08 +#define PFLAG 0x10 + +int +shopt_builtin (list) + WORD_LIST *list; +{ + int opt, flags, rval; + + flags = 0; + reset_internal_getopt (); + while ((opt = internal_getopt (list, "psuoq")) != -1) + { + switch (opt) + { + case 's': + flags |= SFLAG; + break; + case 'u': + flags |= UFLAG; + break; + case 'q': + flags |= QFLAG; + break; + case 'o': + flags |= OFLAG; + break; + case 'p': + flags |= PFLAG; + break; + default: + builtin_usage (); + return (EX_USAGE); + } + } + list = loptend; + + if ((flags & (SFLAG|UFLAG)) == (SFLAG|UFLAG)) + { + builtin_error ("cannot set and unset shell options simultaneously"); + return (EXECUTION_FAILURE); + } + + rval = EXECUTION_SUCCESS; + if ((flags & OFLAG) && ((flags & (SFLAG|UFLAG)) == 0)) /* shopt -o */ + rval = list_shopt_o_options (list, flags & QFLAG); + else if (list && (flags & OFLAG)) /* shopt -so args */ + rval = set_shopt_o_options ((flags & SFLAG) ? FLAG_ON : FLAG_OFF, list, flags & QFLAG); + else if (flags & OFLAG) /* shopt -so */ + rval = list_some_o_options ((flags & SFLAG) ? FLAG_ON : FLAG_OFF, flags & QFLAG); + else if (list && (flags & (SFLAG|UFLAG))) /* shopt -su args */ + rval = toggle_shopts ((flags & SFLAG) ? SETOPT : UNSETOPT, list, flags & QFLAG); + else if ((flags & (SFLAG|UFLAG)) == 0) /* shopt [args] */ + rval = list_shopts (list, flags & QFLAG); + else /* shopt -su */ + rval = list_some_shopts ((flags & SFLAG) ? SETOPT : UNSETOPT, flags & QFLAG); + return (rval); +} + +static int +find_shopt (name) + char *name; +{ + int i; + + for (i = 0; shopt_vars[i].name; i++) + if (STREQ (name, shopt_vars[i].name)) + return i; + return -1; +} + +#define SHOPT_ERROR(str) builtin_error ("%s: unknown shell option name", str) + +static int +toggle_shopts (mode, list, quiet) + int mode; + WORD_LIST *list; + int quiet; +{ + WORD_LIST *l; + int ind, rval; + + for (l = list, rval = EXECUTION_SUCCESS; l; l = l->next) + { + ind = find_shopt (l->word->word); + if (ind < 0) + { + SHOPT_ERROR (l->word->word); + rval = EXECUTION_FAILURE; + } + else + { + *shopt_vars[ind].value = mode; /* 1 for set, 0 for unset */ + if (shopt_vars[ind].set_func) + (*shopt_vars[ind].set_func) (mode); + } + } + return (rval); +} + +/* List the values of all or any of the `shopt' options. Returns 0 if + all were listed or all variables queried were on; 1 otherwise. */ +static int +list_shopts (list, quiet) + WORD_LIST *list; + int quiet; +{ + WORD_LIST *l; + int i, val, rval; + + if (list == 0) + { + for (i = 0; shopt_vars[i].name; i++) + { + val = *shopt_vars[i].value; + if (quiet == 0) + printf (OPTFMT, shopt_vars[i].name, val ? on : off); + } + return (EXECUTION_SUCCESS); + } + + for (l = list, rval = EXECUTION_SUCCESS; l; l = l->next) + { + i = find_shopt (l->word->word); + if (i < 0) + { + SHOPT_ERROR (l->word->word); + rval = EXECUTION_FAILURE; + continue; + } + val = *shopt_vars[i].value; + if (val == 0) + rval = EXECUTION_FAILURE; + if (quiet == 0) + printf (OPTFMT, l->word->word, val ? on : off); + } + return (rval); +} + +static int +list_some_shopts (mode, quiet) + int mode, quiet; +{ + int val, i; + + for (i = 0; shopt_vars[i].name; i++) + { + val = *shopt_vars[i].value; + if (quiet == 0 && mode == val) + printf (OPTFMT, shopt_vars[i].name, val ? on : off); + } + return (EXECUTION_SUCCESS); +} + +static int +list_shopt_o_options (list, quiet) + WORD_LIST *list; + int quiet; +{ + WORD_LIST *l; + int val, rval; + + if (list == 0) + { + if (quiet == 0) + list_minus_o_opts (-1); + return (EXECUTION_SUCCESS); + } + + for (l = list, rval = EXECUTION_SUCCESS; l; l = l->next) + { + val = minus_o_option_value (l->word->word); + if (val == -1) + { + builtin_error ("%s: unknown option name", l->word->word); + rval = EXECUTION_FAILURE; + continue; + } + if (val == 0) + rval = EXECUTION_FAILURE; + if (quiet == 0) + printf (OPTFMT, l->word->word, val ? "on" : "off"); + } + return (rval); +} + +static int +list_some_o_options (mode, quiet) + int mode, quiet; +{ + if (quiet == 0) + list_minus_o_opts (mode); + return (EXECUTION_SUCCESS); +} + +static int +set_shopt_o_options (mode, list, quiet) + int mode; + WORD_LIST *list; + int quiet; +{ + WORD_LIST *l; + int rval; + + for (l = list, rval = EXECUTION_SUCCESS; l; l = l->next) + { + if (set_minus_o_option (mode, l->word->word) == EXECUTION_FAILURE) + rval = EXECUTION_FAILURE; + } + set_shellopts (); + return rval; +} + +/* If we set or unset interactive_comments with shopt, make sure the + change is reflected in $SHELLOPTS. */ +static int +set_interactive_comments (mode) + int mode; +{ + set_shellopts (); + return (0); +} diff --git a/builtins/source.def b/builtins/source.def index 895e98b..1bb3e73 100644 --- a/builtins/source.def +++ b/builtins/source.def @@ -36,34 +36,34 @@ in $PATH are used to find the directory containing FILENAME. $END /* source.c - Implements the `.' and `source' builtins. */ -#include +#include + +#include "../bashtypes.h" +#include "../posixstat.h" +#include "../filecntl.h" #include #include -#if defined (HAVE_STRING_H) -# include -#else /* !HAVE_STRING_H */ -# include -#endif /* !HAVE_STRING_H */ +#if defined (HAVE_UNISTD_H) +# include +#endif + +#include "../bashansi.h" #include "../shell.h" -#include "../posixstat.h" -#include "../filecntl.h" #include "../execute_cmd.h" +#include "common.h" -/* Not all systems declare ERRNO in errno.h... and some systems #define it! */ #if !defined (errno) extern int errno; #endif /* !errno */ -/* Variables used here but defined in other files. */ -extern int return_catch_flag, return_catch_value; -extern jmp_buf return_catch; -extern int posixly_correct; -extern int interactive, interactive_shell, last_command_exit_value; +#if defined (RESTRICTED_SHELL) +extern int restricted; +#endif -/* How many `levels' of sourced files we have. */ -int sourcelevel = 0; +/* If non-zero, `.' uses $PATH to look up the script to be sourced. */ +int source_uses_path = 1; /* If this . script is supplied arguments, we save the dollar vars and replace them with the script arguments for the duration of the script's @@ -86,101 +86,51 @@ maybe_pop_dollar_vars () This cannot be done in a subshell, since things like variable assignments take place in there. So, I open the file, place it into a large string, close the file, and then execute the string. */ +int source_builtin (list) WORD_LIST *list; { - int result, return_val; - - /* Assume the best. */ - result = EXECUTION_SUCCESS; + int result; + char *filename; - if (list) + if (list == 0) { - char *string, *filename; - struct stat finfo; - int fd, tt; - - filename = find_path_file (list->word->word); - if (!filename) - filename = savestring (list->word->word); - - if (((fd = open (filename, O_RDONLY)) < 0) || (fstat (fd, &finfo) < 0)) - goto file_error_exit; - - string = (char *)xmalloc (1 + (int)finfo.st_size); - tt = read (fd, string, finfo.st_size); - string[finfo.st_size] = '\0'; - - /* Close the open file, preserving the state of errno. */ - { int temp = errno; close (fd); errno = temp; } - - if (tt != finfo.st_size) - { - free (string); - - file_error_exit: - file_error (filename); - free (filename); - - /* POSIX shells exit if non-interactive and file error. */ - if (posixly_correct && !interactive_shell) - { - last_command_exit_value = 1; - longjmp (top_level, EXITPROG); - } - - return (EXECUTION_FAILURE); - } - - if (tt > 80) - tt = 80; - - if (check_binary_file ((unsigned char *)string, tt)) - { - free (string); - builtin_error ("%s: cannot execute binary file", filename); - free (filename); - return (EX_BINARY_FILE); - } - - begin_unwind_frame ("File Sourcing"); - - if (list->next) - { - push_dollar_vars (); - add_unwind_protect ((Function *)maybe_pop_dollar_vars, (char *)NULL); - remember_args (list->next, 1); - } - - unwind_protect_int (return_catch_flag); - unwind_protect_jmp_buf (return_catch); - unwind_protect_int (interactive); - unwind_protect_int (sourcelevel); - add_unwind_protect ((Function *)xfree, filename); - interactive = 0; - sourcelevel++; + builtin_error ("filename argument required"); + builtin_usage (); + return (EX_USAGE); + } - set_dollar_vars_unchanged (); + if (no_options (list)) + return (EX_USAGE); - return_catch_flag++; - return_val = setjmp (return_catch); +#if defined (RESTRICTED_SHELL) + if (restricted && strchr (list->word->word, '/')) + { + builtin_error ("%s: restricted", list->word->word); + return (EXECUTION_FAILURE); + } +#endif - if (return_val) - parse_and_execute_cleanup (); - else - result = parse_and_execute (string, filename, -1); + filename = (char *)NULL; + if (source_uses_path) + filename = find_path_file (list->word->word); + if (filename == 0) + filename = savestring (list->word->word); - run_unwind_frame ("File Sourcing"); + begin_unwind_frame ("source"); + add_unwind_protect ((Function *)xfree, filename); - /* If RETURN_VAL is non-zero, then we return the value given - to return_builtin (), since that is how we got here. */ - if (return_val) - result = return_catch_value; - } - else + if (list->next) { - builtin_error ("filename argument required"); - result = EXECUTION_FAILURE; + push_dollar_vars (); + add_unwind_protect ((Function *)maybe_pop_dollar_vars, (char *)NULL); + remember_args (list->next, 1); } + set_dollar_vars_unchanged (); + + result = source_file (filename); + + run_unwind_frame ("source"); + return (result); } diff --git a/builtins/suspend.def b/builtins/suspend.def index 48edc20..151c34d 100644 --- a/builtins/suspend.def +++ b/builtins/suspend.def @@ -30,15 +30,23 @@ signal. The `-f' if specified says not to complain about this being a login shell if it is; just suspend anyway. $END -#include +#include + +#if defined (JOB_CONTROL) +#if defined (HAVE_UNISTD_H) +# include +#endif + +#include "../bashtypes.h" #include #include "../shell.h" #include "../jobs.h" +#include "common.h" +#include "bashgetopt.h" -#if defined (JOB_CONTROL) extern int job_control; -static SigHandler *old_cont, *old_tstp; +static SigHandler *old_cont, *old_stop; /* Continue handler. */ sighandler @@ -46,10 +54,10 @@ suspend_continue (sig) int sig; { set_signal_handler (SIGCONT, old_cont); - set_signal_handler (SIGTSTP, old_tstp); -#if !defined (VOID_SIGHANDLER) - return (0); -#endif /* !VOID_SIGHANDLER */ +#if 0 + set_signal_handler (SIGSTOP, old_stop); +#endif + SIGRETURN (0); } /* Suspending the shell. If -f is the arg, then do the suspend @@ -58,28 +66,45 @@ int suspend_builtin (list) WORD_LIST *list; { - if (!job_control) + int opt, force; + + reset_internal_getopt (); + force = 0; + while ((opt = internal_getopt (list, "f")) != -1) + switch (opt) + { + case 'f': + force++; + break; + default: + builtin_usage (); + return (EX_USAGE); + } + + list = loptend; + + if (job_control == 0) { - builtin_error ("Cannot suspend a shell without job control"); + builtin_error ("cannot suspend a shell without job control"); return (EXECUTION_FAILURE); } - if (list) - if (strcmp (list->word->word, "-f") == 0) - goto do_suspend; - - no_args (list); - - if (login_shell) + if (force == 0) { - builtin_error ("Can't suspend a login shell"); - return (EXECUTION_FAILURE); + no_args (list); + + if (login_shell) + { + builtin_error ("cannot suspend a login shell"); + return (EXECUTION_FAILURE); + } } -do_suspend: old_cont = (SigHandler *)set_signal_handler (SIGCONT, suspend_continue); - old_tstp = (SigHandler *)set_signal_handler (SIGTSTP, SIG_DFL); - killpg (shell_pgrp, SIGTSTP); +#if 0 + old_stop = (SigHandler *)set_signal_handler (SIGSTOP, SIG_DFL); +#endif + killpg (shell_pgrp, SIGSTOP); return (EXECUTION_SUCCESS); } diff --git a/builtins/test.def b/builtins/test.def index 2b1457b..03de47d 100644 --- a/builtins/test.def +++ b/builtins/test.def @@ -37,12 +37,12 @@ File operators: -e FILE True if file exists. -f FILE True if file exists and is a regular file. -g FILE True if file is set-group-id. - -h FILE True if file is a symbolic link. Use "-L". + -h FILE True if file is a symbolic link. -L FILE True if file is a symbolic link. - -k FILE True if file has its "sticky" bit set. + -k FILE True if file has its `sticky' bit set. -p FILE True if file is a named pipe. -r FILE True if file is readable by you. - -s FILE True if file is not empty. + -s FILE True if file exists and is not empty. -S FILE True if file is a socket. -t FD True if FD is opened on a terminal. -u FILE True if the file is set-user-id. @@ -63,12 +63,16 @@ String operators: -z STRING True if string is empty. -n STRING - or STRING True if string is not empty. + STRING True if string is not empty. STRING1 = STRING2 True if the strings are equal. STRING1 != STRING2 True if the strings are not equal. + STRING1 < STRING2 + True if STRING1 sorts before STRING2 lexicographically + STRING1 > STRING2 + True if STRING1 sorts after STRING2 lexicographically Other operators: @@ -88,18 +92,21 @@ $BUILTIN [ $DOCNAME test_bracket $FUNCTION test_builtin $SHORT_DOC [ arg... ] -This is a synonym for the "test" shell builtin, excepting that the -last argument must be literally `]', to match the `[' which invoked -the test. +This is a synonym for the "test" builtin, but the last +argument must be a literal `]', to match the opening `['. $END -#if defined (HAVE_STRING_H) -# include -#else /* !HAVE_STRING_H */ -# include -#endif /* !HAVE_STRING_H */ +#include + +#if defined (HAVE_UNISTD_H) +# include +#endif + +#include "../bashansi.h" #include "../shell.h" +#include "common.h" + extern char *this_command_name; /* TEST/[ builtin. */ @@ -109,12 +116,11 @@ test_builtin (list) { char **argv; int argc, result; - WORD_LIST *t = list; /* We let Matthew Bradburn and Kevin Braunsdorf's code do the actual test command. So turn the list of args into an array - of strings, since that is what his code wants. */ - if (!list) + of strings, since that is what their code wants. */ + if (list == 0) { if (this_command_name[0] == '[' && !this_command_name[1]) builtin_error ("missing `]'"); @@ -122,23 +128,9 @@ test_builtin (list) return (EXECUTION_FAILURE); } - /* Get the length of the argument list. */ - for (argc = 0; t; t = t->next, argc++); - - /* Account for argv[0] being a command name. This makes our life easier. */ - argc++; - argv = (char **)xmalloc ((1 + argc) * sizeof (char *)); - argv[argc] = (char *)NULL; - - /* this_command_name is the name of the command that invoked this - function. So you can't call test_builtin () directly from - within this code, there are too many things to worry about. */ - argv[0] = savestring (this_command_name); - - for (t = list, argc = 1; t; t = t->next, argc++) - argv[argc] = savestring (t->word->word); - + argv = make_builtin_argv (list, &argc); result = test_command (argc, argv); - free_array (argv); + free ((char *)argv); + return (result); } diff --git a/builtins/times.def b/builtins/times.def index 9c42768..216abcb 100644 --- a/builtins/times.def +++ b/builtins/times.def @@ -28,62 +28,79 @@ Print the accumulated user and system times for processes run from the shell. $END -#include "../shell.h" -#include +#include -#if defined (hpux) || defined (USGr4) || defined (XD88) || defined (USGr3) -# undef HAVE_RESOURCE -#endif /* hpux || USGr4 || XD88 || USGr3 */ +#if defined (HAVE_UNISTD_H) +# include +#endif -#if defined (_POSIX_VERSION) || !defined (HAVE_RESOURCE) -# include -#else /* !_POSIX_VERSION && HAVE_RESOURCE */ +#include +#include "../bashtypes.h" +#include "../shell.h" + +#if TIME_WITH_SYS_TIME # include +# include +#else +# if defined (HAVE_SYS_TIME_H) +# include +# else +# include +# endif +#endif + +#if defined (HAVE_SYS_TIMES_H) +# include +#endif /* HAVE_SYS_TIMES_H */ + +#if defined (HAVE_SYS_RESOURCE_H) # include -#endif /* !_POSIX_VERSION && HAVE_RESOURCE */ +#endif + +#include "common.h" -/* Print the totals for system and user time used. The - information comes from variables in jobs.c used to keep - track of this stuff. */ +/* Print the totals for system and user time used. */ +int times_builtin (list) WORD_LIST *list; { -#if !defined (_POSIX_VERSION) && defined (HAVE_RESOURCE) && defined (RUSAGE_SELF) +#if defined (HAVE_GETRUSAGE) && defined (HAVE_TIMEVAL) && defined (RUSAGE_SELF) struct rusage self, kids; getrusage (RUSAGE_SELF, &self); getrusage (RUSAGE_CHILDREN, &kids); /* terminated child processes */ - print_timeval (&self.ru_utime); + print_timeval (stdout, &self.ru_utime); putchar (' '); - print_timeval (&self.ru_stime); + print_timeval (stdout, &self.ru_stime); putchar ('\n'); - print_timeval (&kids.ru_utime); + print_timeval (stdout, &kids.ru_utime); putchar (' '); - print_timeval (&kids.ru_stime); + print_timeval (stdout, &kids.ru_stime); putchar ('\n'); -#else /* _POSIX_VERSION || !HAVE_RESOURCE || !RUSAGE_SELF */ -# if !defined (BrainDeath) - struct tms t; - - times (&t); - +#else +# if defined (HAVE_TIMES) /* As of System V.3, HP-UX 6.5, and other ATT-like systems, this stuff is returned in terms of clock ticks (HZ from sys/param.h). C'mon, guys. This kind of stupid clock-dependent stuff is exactly the reason 4.2BSD introduced the `timeval' struct. */ + struct tms t; + + times (&t); - print_time_in_hz (t.tms_utime); + print_time_in_hz (stdout, t.tms_utime); putchar (' '); - print_time_in_hz (t.tms_stime); + print_time_in_hz (stdout, t.tms_stime); putchar ('\n'); - print_time_in_hz (t.tms_cutime); + print_time_in_hz (stdout, t.tms_cutime); putchar (' '); - print_time_in_hz (t.tms_cstime); + print_time_in_hz (stdout, t.tms_cstime); putchar ('\n'); -# endif /* BrainDeath */ -#endif /* _POSIX_VERSION || !HAVE_RESOURCE || !RUSAGE_SELF */ +# else /* !HAVE_TIMES */ + printf ("0.00 0.00\n0.00 0.00\n"); +# endif /* HAVE_TIMES */ +#endif /* !HAVE_TIMES */ return (EXECUTION_SUCCESS); } diff --git a/builtins/trap.def b/builtins/trap.def index b81651d..f6a8ee4 100644 --- a/builtins/trap.def +++ b/builtins/trap.def @@ -23,30 +23,46 @@ $PRODUCES trap.c $BUILTIN trap $FUNCTION trap_builtin -$SHORT_DOC trap [arg] [signal_spec] +$SHORT_DOC trap [arg] [signal_spec] or trap -l The command ARG is to be read and executed when the shell receives signal(s) SIGNAL_SPEC. If ARG is absent all specified signals are -reset to their original values. If ARG is the null string this -signal is ignored by the shell and by the commands it invokes. If -SIGNAL_SPEC is EXIT (0) the command ARG is executed on exit from -the shell. The trap command with no arguments prints the list of -commands associated with each signal number. SIGNAL_SPEC is either -a signal name in , or a signal number. The syntax `trap -l' -prints a list of signal names and their corresponding numbers. -Note that a signal can be sent to the shell with "kill -signal $$". +reset to their original values. If ARG is the null string each +SIGNAL_SPEC is ignored by the shell and by the commands it invokes. +If SIGNAL_SPEC is EXIT (0) the command ARG is executed on exit from +the shell. If SIGNAL_SPEC is DEBUG, ARG is executed after every +command. If ARG is `-p' then the trap commands associated with +each SIGNAL_SPEC are displayed. If no arguments are supplied or if +only `-p' is given, trap prints the list of commands associated with +each signal number. SIGNAL_SPEC is either a signal name in +or a signal number. `trap -l' prints a list of signal names and their +corresponding numbers. Note that a signal can be sent to the shell +with "kill -signal $$". $END -#include +#include + +#if defined (HAVE_UNISTD_H) +# include +#endif + +#include "../bashtypes.h" #include +#include +#include "../bashansi.h" + #include "../shell.h" #include "../trap.h" #include "common.h" +#include "bashgetopt.h" + +static int display_traps (); /* The trap command: trap trap trap -l + trap -p [sigspec ...] trap [--] Set things up so that ARG is executed when SIGNAL(s) N is recieved. @@ -62,60 +78,44 @@ $END extern int interactive; +int trap_builtin (list) WORD_LIST *list; { - register int i; - int list_signal_names = 0; + int list_signal_names, display, result, opt; - while (list) + list_signal_names = display = 0; + result = EXECUTION_SUCCESS; + reset_internal_getopt (); + while ((opt = internal_getopt (list, "lp")) != -1) { - if (ISOPTION (list->word->word, 'l')) + switch (opt) { + case 'l': list_signal_names++; - list = list->next; - } - else if (ISOPTION (list->word->word, '-')) - { - list = list->next; break; - } - else if ((*list->word->word == '-') && list->word->word[1]) - { - bad_option (list->word->word); - builtin_error ("usage: trap [-l] [arg] [sigspec]"); + case 'p': + display++; + break; + default: + builtin_usage (); return (EX_USAGE); } - else - break; } + list = loptend; if (list_signal_names) + return (display_signal_list ((WORD_LIST *)NULL, 1)); + else if (display || list == 0) + return (display_traps (list)); + else { - int column = 0; - - for (i = 0; i < NSIG; i++) - { - printf ("%2d) %s", i, signal_name (i)); - if (++column < 4) - printf ("\t"); - else - { - printf ("\n"); - column = 0; - } - } - if (column != 0) - printf ("\n"); - return (EXECUTION_SUCCESS); - } + char *first_arg; + int operation, sig; - if (list) - { - char *first_arg = list->word->word; - int operation = SET, any_failed = 0; - - if (signal_object_p (first_arg)) + operation = SET; + first_arg = list->word->word; + if (first_arg && *first_arg && signal_object_p (first_arg)) operation = REVERT; else { @@ -128,15 +128,13 @@ trap_builtin (list) while (list) { - int sig; - sig = decode_signal (list->word->word); if (sig == NO_SIG) { builtin_error ("%s: not a signal specification", list->word->word); - any_failed++; + result = EXECUTION_FAILURE; } else { @@ -183,22 +181,52 @@ trap_builtin (list) } list = list->next; } - return ((!any_failed) ? EXECUTION_SUCCESS : EXECUTION_FAILURE); } - for (i = 0; i < NSIG; i++) - { - char *t, *p; + return (result); +} + +static void +showtrap (i) + int i; +{ + char *t, *p; + + p = trap_list[i]; + + if (p == (char *)DEFAULT_SIG) + return; + + t = (p == (char *)IGNORE_SIG) ? (char *)NULL : single_quote (p); + printf ("trap -- %s %s\n", t ? t : "''", signal_name (i)); + if (t) + free (t); +} - p = trap_list[i]; +static int +display_traps (list) + WORD_LIST *list; +{ + int result, i; - if (p == (char *)DEFAULT_SIG) - continue; + if (list == 0) + { + for (i = 0; i <= NSIG; i++) + showtrap (i); + return (EXECUTION_SUCCESS); + } - t = (p == (char *)IGNORE_SIG) ? (char *)NULL : single_quote (p); - printf ("trap -- %s %s\n", t ? t : "''", signal_name (i)); - if (t) - free (t); + for (result = EXECUTION_SUCCESS; list; list = list->next) + { + i = decode_signal (list->word->word); + if (i == NO_SIG) + { + result = EXECUTION_FAILURE; + builtin_error ("%s: not a signal specification", list->word->word); + } + else + showtrap (i); } - return (EXECUTION_SUCCESS); + + return (result); } diff --git a/builtins/type.def b/builtins/type.def index aecc303..5e828c6 100644 --- a/builtins/type.def +++ b/builtins/type.def @@ -23,26 +23,38 @@ $PRODUCES type.c $BUILTIN type $FUNCTION type_builtin -$SHORT_DOC type [-all] [-type | -path] [name ...] +$SHORT_DOC type [-apt] name [name ...] For each NAME, indicate how it would be interpreted if used as a command name. -If the -type flag is used, returns a single word which is one of +If the -t option is used, returns a single word which is one of `alias', `keyword', `function', `builtin', `file' or `', if NAME is an alias, shell reserved word, shell function, shell builtin, disk file, or unfound, respectively. -If the -path flag is used, either returns the name of the disk file -that would be exec'ed, or nothing if -type wouldn't return `file'. +If the -p flag is used, either returns the name of the disk file +that would be executed, or nothing if -t would not return `file'. -If the -all flag is used, displays all of the places that contain an +If the -a flag is used, displays all of the places that contain an executable named `file'. This includes aliases and functions, if and -only if the -path flag is not also used. +only if the -p flag is not also used. + +Type accepts -all, -path, and -type in place of -a, -p, and -t, +respectively. $END -#include -#include +#include + +#include "../bashtypes.h" #include "../posixstat.h" + +#if defined (HAVE_UNISTD_H) +# include +#endif + +#include +#include "../bashansi.h" + #include "../shell.h" #include "../execute_cmd.h" @@ -52,7 +64,7 @@ $END #include "common.h" -extern STRING_INT_ALIST word_token_alist[]; +extern int find_reserved_word (); /* For each word in LIST, find out what the shell is going to do with it as a simple command. i.e., which file would this shell use to @@ -75,18 +87,19 @@ extern STRING_INT_ALIST word_token_alist[]; builtin file */ +int type_builtin (list) WORD_LIST *list; { int path_only, type_only, all, verbose; int successful_finds; + if (list == 0) + return (EXECUTION_SUCCESS); + path_only = type_only = all = 0; successful_finds = 0; - if (!list) - return (EXECUTION_SUCCESS); - while (list && *(list->word->word) == '-') { char *flag = &(list->word->word[1]); @@ -108,7 +121,7 @@ type_builtin (list) else { bad_option (flag); - builtin_error ("usage: type [-all | -path | -type ] name [name ...]"); + builtin_usage (); return (EX_USAGE); } list = list->next; @@ -116,7 +129,7 @@ type_builtin (list) if (type_only) verbose = 1; - else if (!path_only) + else if (path_only == 0) verbose = 2; else if (path_only) verbose = 3; @@ -156,22 +169,29 @@ type_builtin (list) * ALL says whether or not to look for all occurrences of COMMAND, or * return after finding it once. */ +int describe_command (command, verbose, all) char *command; int verbose, all; { - int found = 0, i, found_file = 0; - char *full_path = (char *)NULL; + int found, i, found_file; + char *full_path; SHELL_VAR *func; +#if defined (ALIAS) + alias_t *alias; +#endif + + found = found_file = 0; + full_path = (char *)NULL; #if defined (ALIAS) /* Command is an alias? */ - ASSOC *alias = find_alias (command); + alias = find_alias (command); if (alias) { if (verbose == 1) - printf ("alias\n"); + puts ("alias"); else if (verbose == 2) printf ("%s is aliased to `%s'\n", command, alias->value); else if (verbose == 4) @@ -193,7 +213,7 @@ describe_command (command, verbose, all) if (i >= 0) { if (verbose == 1) - printf ("keyword\n"); + puts ("keyword"); else if (verbose == 2) printf ("%s is a shell keyword\n", command); else if (verbose == 4) @@ -211,7 +231,7 @@ describe_command (command, verbose, all) if (func) { if (verbose == 1) - printf ("function\n"); + puts ("function"); else if (verbose == 2) { #define PRETTY_PRINT_FUNC 1 @@ -240,7 +260,7 @@ describe_command (command, verbose, all) if (find_shell_builtin (command)) { if (verbose == 1) - printf ("builtin\n"); + puts ("builtin"); else if (verbose == 2) printf ("%s is a shell builtin\n", command); else if (verbose == 4) @@ -261,7 +281,7 @@ describe_command (command, verbose, all) if (f & FS_EXECABLE) { if (verbose == 1) - printf ("file\n"); + puts ("file"); else if (verbose == 2) printf ("%s is %s\n", command, command); else if (verbose == 3 || verbose == 4) @@ -281,7 +301,7 @@ describe_command (command, verbose, all) if ((full_path = find_hashed_filename (command)) != (char *)NULL) { if (verbose == 1) - printf ("file\n"); + puts ("file"); else if (verbose == 2) printf ("%s is hashed (%s)\n", command, full_path); else if (verbose == 3 || verbose == 4) @@ -308,7 +328,7 @@ describe_command (command, verbose, all) found = 1; if (verbose == 1) - printf ("file\n"); + puts ("file"); else if (verbose == 2) printf ("%s is %s\n", command, full_path); else if (verbose == 3 || verbose == 4) diff --git a/builtins/ulimit.def b/builtins/ulimit.def index 1947c36..546dfd4 100644 --- a/builtins/ulimit.def +++ b/builtins/ulimit.def @@ -24,7 +24,7 @@ $PRODUCES ulimit.c $BUILTIN ulimit $FUNCTION ulimit_builtin $DEPENDS_ON !MINIX -$SHORT_DOC ulimit [-SHacdfmstpnuv [limit]] +$SHORT_DOC ulimit [-SHacdflmnpstuv] [limit] Ulimit provides control over the resources available to processes started by the shell, on systems that allow such control. If an option is given, it is interpreted as follows: @@ -34,52 +34,68 @@ option is given, it is interpreted as follows: -a all current limits are reported -c the maximum size of core files created -d the maximum size of a process's data segment + -f the maximum size of files created by the shell + -l the maximum size a process may lock into memory -m the maximum resident set size + -n the maximum number of open file descriptors + -p the pipe buffer size -s the maximum stack size -t the maximum amount of cpu time in seconds - -f the maximum size of files created by the shell - -p the pipe buffer size - -n the maximum number of open file descriptors -u the maximum number of user processes -v the size of virtual memory If LIMIT is given, it is the new value of the specified resource. Otherwise, the current value of the specified resource is printed. -If no option is given, then -f is assumed. Values are in 1k +If no option is given, then -f is assumed. Values are in 1024-byte increments, except for -t, which is in seconds, -p, which is in increments of 512 bytes, and -u, which is an unscaled number of processes. $END -#include -#include +#include + +#include "../bashtypes.h" #include + +#if defined (HAVE_UNISTD_H) +# include +#endif + +#include #include + #include "../shell.h" +#include "common.h" +#include "bashgetopt.h" #include "pipesize.h" #if !defined (errno) extern int errno; #endif +/* For some reason, HPUX chose to make these definitions visible only if + _KERNEL is defined, so we define _KERNEL before including + and #undef it afterward. */ #if defined (HAVE_RESOURCE) # include +# if defined (HPUX) && defined (RLIMIT_NEEDS_KERNEL) +# define _KERNEL +# endif # include +# if defined (HPUX) && defined (RLIMIT_NEEDS_KERNEL) +# undef _KERNEL +# endif #else # include #endif -#if defined (HAVE_UNISTD_H) -# include -#endif - #if defined (HAVE_LIMITS_H) # include #endif /* Check for the most basic symbols. If they aren't present, this system's isn't very useful to us. */ -#if !defined (RLIMIT_FSIZE) || defined (GETRLIMIT_MISSING) +#if !defined (RLIMIT_FSIZE) || !defined (HAVE_GETRLIMIT) # undef HAVE_RESOURCE #endif @@ -89,509 +105,412 @@ extern int errno; # define print_rlimtype(num, nl) printf ("%ld%s", num, nl ? "\n" : "") #endif -static void print_long (); +#define DESCFMT "%-28s" -/* **************************************************************** */ -/* */ -/* Ulimit builtin and Hacks. */ -/* */ -/* **************************************************************** */ +/* Some systems use RLIMIT_NOFILE, others use RLIMIT_OFILE */ +#if defined (HAVE_RESOURCE) && defined (RLIMIT_OFILE) && !defined (RLIMIT_NOFILE) +# define RLIMIT_NOFILE RLIMIT_OFILE +#endif /* HAVE_RESOURCE && RLIMIT_OFILE && !RLIMIT_NOFILE */ -/* Block size for ulimit operations. */ -#define ULIMIT_BLOCK_SIZE ((long)1024) +/* Some systems have these, some do not. */ +#ifdef RLIMIT_FSIZE +# define RLIMIT_FILESIZE RLIMIT_FSIZE +#else +# define RLIMIT_FILESIZE 256 +#endif + +#define RLIMIT_PIPESIZE 257 -#define u_FILE_SIZE 0x001 -#define u_MAX_BREAK_VAL 0x002 -#define u_PIPE_SIZE 0x004 -#define u_CORE_FILE_SIZE 0x008 -#define u_DATA_SEG_SIZE 0x010 -#define u_PHYS_MEM_SIZE 0x020 -#define u_CPU_TIME_LIMIT 0x040 -#define u_STACK_SIZE 0x080 -#define u_NUM_OPEN_FILES 0x100 -#define u_MAX_VIRTUAL_MEM 0x200 -#define u_MAX_USER_PROCS 0x400 +#ifdef RLIMIT_NOFILE +# define RLIMIT_OPENFILES RLIMIT_NOFILE +#else +# define RLIMIT_OPENFILES 258 +#endif -#define u_ALL_LIMITS 0x7ff +#ifdef RLIMIT_VMEM +# define RLIMIT_VIRTMEM RLIMIT_VMEM +# define RLIMIT_VMBLKSZ 1024 +#else +# ifdef RLIMIT_AS +# define RLIMIT_VIRTMEM RLIMIT_AS +# define RLIMIT_VMBLKSZ 1024 +# else +# define RLIMIT_VIRTMEM 259 +# define RLIMIT_VMBLKSZ 1 +# endif +#endif + +#ifdef RLIMIT_NPROC +# define RLIMIT_MAXUPROC RLIMIT_NPROC +#else +# define RLIMIT_MAXUPROC 260 +#endif #if !defined (RLIM_INFINITY) -# define RLIM_INFINITY 0x7fffffff +# define RLIM_INFINITY 0x7fffffff #endif -/* Some systems use RLIMIT_NOFILE, others use RLIMIT_OFILE */ -#if defined (HAVE_RESOURCE) && defined (RLIMIT_OFILE) && !defined (RLIMIT_NOFILE) -# define RLIMIT_NOFILE RLIMIT_OFILE -#endif /* HAVE_RESOURCE && RLIMIT_OFILE && !RLIMIT_NOFILE */ +#if !defined (RLIM_INVALID) +# define RLIM_INVALID (RLIMTYPE)-1 +#endif #define LIMIT_HARD 0x01 #define LIMIT_SOFT 0x02 -static RLIMTYPE shell_ulimit (); +static int ulimit_internal (); +static void printone (); +static void print_all_limits (); + +static int get_limit (); +static int set_limit (); + +static RLIMTYPE filesize (); static RLIMTYPE pipesize (); -static RLIMTYPE open_files (); +static RLIMTYPE getmaxuprc (); +static RLIMTYPE getmaxvm (); + +typedef struct { + int option; /* The ulimit option for this limit. */ + int parameter; /* Parameter to pass to get_limit (). */ + int block_factor; /* Blocking factor for specific limit. */ + char *description; /* Descriptive string to output. */ +} RESOURCE_LIMITS; +static RESOURCE_LIMITS limits[] = { +#ifdef RLIMIT_CORE + { 'c', RLIMIT_CORE, 1024, "core file size (blocks)" }, +#endif +#ifdef RLIMIT_DATA + { 'd', RLIMIT_DATA, 1024, "data seg size (kbytes)" }, +#endif + { 'f', RLIMIT_FILESIZE, 1024, "file size (blocks)" }, +#ifdef RLIMIT_MEMLOCK + { 'l', RLIMIT_MEMLOCK, 1024, "max locked memory (kbytes)" }, +#endif +#ifdef RLIMIT_RSS + { 'm', RLIMIT_RSS, 1024, "max memory size (kbytes)" }, +#endif /* RLIMIT_RSS */ + { 'n', RLIMIT_OPENFILES, 1, "open files" }, + { 'p', RLIMIT_PIPESIZE, 512, "pipe size (512 bytes)" }, +#ifdef RLIMIT_STACK + { 's', RLIMIT_STACK, 1024, "stack size (kbytes)" }, +#endif +#ifdef RLIMIT_CPU + { 't', RLIMIT_CPU, 1, "cpu time (seconds)" }, +#endif /* RLIMIT_CPU */ + { 'u', RLIMIT_MAXUPROC, 1, "max user processes" }, #if defined (HAVE_RESOURCE) -static RLIMTYPE getmaxvm (); -#endif /* HAVE_RESOURCE */ + { 'v', RLIMIT_VIRTMEM, RLIMIT_VMBLKSZ, "virtual memory (kbytes)" }, +#endif + { -1, -1, -1, (char *)NULL } +}; +#define NCMDS (sizeof(limits) / sizeof(limits[0])) -static void print_specific_limits (); -static void print_all_limits (); +typedef struct _cmd { + int cmd; + char *arg; +} ULCMD; -static char t[2]; +static ULCMD *cmdlist; +static int ncmd; +static int cmdlistsz; -/* Return 1 if the limit associated with CMD can be raised from CURRENT - to NEW. This is for USG systems without HAVE_RESOURCE, most of which - do not allow any user other than root to raise limits. There are, - however, exceptions. */ -#if !defined (HAVE_RESOURCE) static int -canraise (cmd, current, new) - int cmd; - RLIMTYPE current, new; +_findlim (opt) + int opt; { -# if defined (HAVE_SETDTABLESIZE) - if (cmd == u_NUM_OPEN_FILES) - return (1); -# endif /* HAVE_SETDTABLSIZE */ + register int i; - return ((current > new) || (current_user.uid == 0)); + for (i = 0; limits[i].option > 0; i++) + if (limits[i].option == opt) + return i; + return -1; } -#endif /* !HAVE_RESOURCE */ -/* Report or set limits associated with certain per-process resources. - See the help documentation in builtins.c for a full description. +static char optstring[4 + 2 * NCMDS]; - Rewritten by Chet Ramey 6/30/91. */ +/* Report or set limits associated with certain per-process resources. + See the help documentation in builtins.c for a full description. */ int ulimit_builtin (list) register WORD_LIST *list; { register char *s; - int c, setting, cmd, mode, verbose_print, opt_eof; - int all_limits, specific_limits; - long block_factor; - RLIMTYPE current_limit, real_limit, limit; + int c, limind, mode, opt, all_limits; - c = mode = verbose_print = opt_eof = 0; - limit = (RLIMTYPE)-1; + mode = 0; - do - { - cmd = setting = all_limits = specific_limits = 0; - block_factor = ULIMIT_BLOCK_SIZE; + all_limits = 0; - /* read_options: */ - if (list && !opt_eof && *list->word->word == '-') + /* Idea stolen from pdksh -- build option string the first time called. */ + if (optstring[0] == 0) + { + s = optstring; + *s++ = 'a'; *s++ = 'S'; *s++ = 'H'; + for (c = 0; limits[c].option > 0; c++) { - s = &(list->word->word[1]); - list = list->next; - - while (*s && (c = *s++)) - { - switch (c) - { -#define ADD_CMD(x) { if (cmd) specific_limits++; cmd |= (x); } - - case '-': /* ulimit -- */ - opt_eof++; - break; - - case 'a': - all_limits++; - break; - - case 'f': - ADD_CMD (u_FILE_SIZE); - break; - -#if defined (HAVE_RESOURCE) - /* -S and -H are modifiers, not real options. */ - case 'S': - mode |= LIMIT_SOFT; - break; - - case 'H': - mode |= LIMIT_HARD; - break; - - case 'c': - ADD_CMD (u_CORE_FILE_SIZE); - break; - - case 'd': - ADD_CMD (u_DATA_SEG_SIZE); - break; - -#if !defined (USGr4) - case 'm': - ADD_CMD (u_PHYS_MEM_SIZE); - break; -#endif /* USGr4 */ - - case 't': - ADD_CMD (u_CPU_TIME_LIMIT); - block_factor = 1; /* seconds */ - break; - - case 's': - ADD_CMD (u_STACK_SIZE); - break; - - case 'v': - ADD_CMD (u_MAX_VIRTUAL_MEM); - block_factor = 1; - break; - - case 'u': - ADD_CMD (u_MAX_USER_PROCS); - block_factor = 1; - break; - -#endif /* HAVE_RESOURCE */ - - case 'p': - ADD_CMD (u_PIPE_SIZE); - block_factor = 512; - break; - - case 'n': - ADD_CMD (u_NUM_OPEN_FILES); - block_factor = 1; - break; - - default: /* error_case: */ - t[0] = c; - t[1] = '\0'; - bad_option (t); -#if !defined (HAVE_RESOURCE) - builtin_error("usage: ulimit [-afnp] [new limit]"); -#else - builtin_error("usage: ulimit [-SHacmdstfnpuv] [new limit]"); -#endif - return (EX_USAGE); - } - } + *s++ = limits[c].option; + *s++ = ';'; } + *s = '\0'; + } - if (all_limits) - { - print_all_limits (mode); - return (EXECUTION_SUCCESS); - } - - if (specific_limits) - { - print_specific_limits (cmd, mode); - if (list) - verbose_print++; - continue; - } - - if (cmd == 0) - cmd = u_FILE_SIZE; - - /* If an argument was supplied for the command, then we want to - set the limit. Note that `ulimit something' means a command - of -f with argument `something'. */ - if (list) - { - if (opt_eof || (*list->word->word != '-')) - { - s = list->word->word; - list = list->next; - - if (STREQ (s, "unlimited")) - limit = RLIM_INFINITY; - else if (all_digits (s)) - limit = string_to_rlimtype (s); - else - { - builtin_error ("bad non-numeric arg `%s'", s); - return (EXECUTION_FAILURE); - } - setting++; - } - else if (!opt_eof) - verbose_print++; - } - - if (limit == RLIM_INFINITY) - block_factor = 1; - - real_limit = limit * block_factor; - - /* If more than one option is given, list each in a verbose format, - the same that is used for -a. */ - if (!setting && verbose_print) + /* Initialize the command list. */ + if (cmdlistsz == 0) + cmdlist = (ULCMD *)xmalloc ((cmdlistsz = 16) * sizeof (ULCMD)); + ncmd = 0; + + reset_internal_getopt (); + while ((opt = internal_getopt (list, optstring)) != -1) + { + switch (opt) { - print_specific_limits (cmd, mode); - continue; + case 'a': + all_limits++; + break; + + /* -S and -H are modifiers, not real options. */ + case 'S': + mode |= LIMIT_SOFT; + break; + + case 'H': + mode |= LIMIT_HARD; + break; + + case '?': + builtin_usage (); + return (EX_USAGE); + + default: + if (ncmd >= cmdlistsz) + cmdlist = (ULCMD *)xrealloc (cmdlist, (cmdlistsz *= 2) * sizeof (ULCMD)); + cmdlist[ncmd].cmd = opt; + cmdlist[ncmd++].arg = list_optarg; + break; } + } + list = loptend; - current_limit = shell_ulimit (cmd, real_limit, 0, mode); + if (all_limits) + { + print_all_limits (mode == 0 ? LIMIT_SOFT : mode); + return (EXECUTION_SUCCESS); + } - if (setting) - { -#if !defined (HAVE_RESOURCE) - /* Most USG systems do not most allow limits to be raised by any - user other than root. There are, however, exceptions. */ - if (canraise (cmd, current_limit, real_limit) == 0) - { - builtin_error ("cannot raise limit: %s", strerror (EPERM)); - return (EXECUTION_FAILURE); - } -#endif /* !HAVE_RESOURCE */ - - if (shell_ulimit (cmd, real_limit, 1, mode) == (RLIMTYPE)-1) - { - builtin_error ("cannot raise limit: %s", strerror (errno)); - return (EXECUTION_FAILURE); - } - - continue; - } - else + /* default is `ulimit -f' */ + if (ncmd == 0) + { + cmdlist[ncmd].cmd = 'f'; + /* `ulimit something' is same as `ulimit -f something' */ + cmdlist[ncmd++].arg = list ? list->word->word : (char *)NULL; + if (list) + list = list->next; + } + + /* verify each command in the list. */ + for (c = 0; c < ncmd; c++) + { + limind = _findlim (cmdlist[c].cmd); + if (limind == -1) { - if (current_limit < 0) - builtin_error ("cannot get limit: %s", strerror (errno)); - else if (current_limit != RLIM_INFINITY) - print_rlimtype ((current_limit / block_factor), 1); - else - printf ("unlimited\n"); + builtin_error ("bad command: `%c'", cmdlist[c].cmd); + return (EX_USAGE); } } - while (list); + + for (c = 0; c < ncmd; c++) + if (ulimit_internal (cmdlist[c].cmd, cmdlist[c].arg, mode, ncmd > 1) == EXECUTION_FAILURE) + return (EXECUTION_FAILURE); return (EXECUTION_SUCCESS); } -/* The ulimit that we call from within Bash. +static int +ulimit_internal (cmd, cmdarg, mode, multiple) + int cmd; + char *cmdarg; + int mode, multiple; +{ + int opt, limind, setting; + long block_factor; + RLIMTYPE current_limit, real_limit, limit; - WHICH says which limit to twiddle; SETTING is non-zero if NEWLIM - contains the desired new limit. Otherwise, the existing limit is - returned. If mode & LIMIT_HARD, the hard limit is used; if - mode & LIMIT_SOFT, the soft limit. Both may be set by specifying - -H and -S; if both are specified, or if neither is specified, the - soft limit will be returned. + limit = RLIM_INVALID; + setting = cmdarg != 0; + limind = _findlim (cmd); + if (mode == 0) + mode = setting ? (LIMIT_HARD|LIMIT_SOFT) : LIMIT_SOFT; + opt = get_limit (limind, mode, ¤t_limit); + if (opt < 0) + { + builtin_error ("cannot get limit: %s", strerror (errno)); + return (EXECUTION_FAILURE); + } - Systems without BSD resource limits can specify only u_FILE_SIZE. - This includes most USG systems. + if (setting == 0) /* print the value of the specified limit */ + { + printone (limind, current_limit, multiple); + return (EXECUTION_SUCCESS); + } + + /* Setting the limit. */ + if (STREQ (cmdarg, "unlimited")) + limit = RLIM_INFINITY; + else if (all_digits (cmdarg)) + limit = string_to_rlimtype (cmdarg); + else + { + builtin_error ("bad non-numeric arg `%s'", cmdarg); + return (EXECUTION_FAILURE); + } - Chet Ramey supplied the BSD resource limit code. */ -static RLIMTYPE -shell_ulimit (which, newlim, setting, mode) - int which, setting, mode; - RLIMTYPE newlim; + block_factor = (limit == RLIM_INFINITY) ? 1 : limits[limind].block_factor; + real_limit = limit * block_factor; + + if (set_limit (limind, real_limit, mode) < 0) + { + builtin_error ("cannot modify limit: %s", strerror (errno)); + return (EXECUTION_FAILURE); + } + return (EXECUTION_SUCCESS); +} + +static int +get_limit (ind, mode, limptr) + int ind, mode; + RLIMTYPE *limptr; { + RLIMTYPE value; #if defined (HAVE_RESOURCE) struct rlimit limit; - int cmd; - - if (mode == 0) - mode |= LIMIT_SOFT; #endif - switch (which) + if (limits[ind].parameter >= 256) { -#if !defined (HAVE_RESOURCE) - - case u_FILE_SIZE: - if (!setting) + switch (limits[ind].parameter) { - /* ulimit () returns a number that is in 512 byte blocks, thus we - must multiply it by 512 to get back to bytes. This is false - only under HP/UX 6.x. */ - RLIMTYPE result; - - result = ulimit (1, 0L); - -# if defined (hpux) && !defined (_POSIX_VERSION) - return (result); -# else - return (result * 512); -# endif /* hpux 6.x */ + case RLIMIT_FILESIZE: + value = filesize (); + break; + case RLIMIT_PIPESIZE: + value = pipesize (); + break; + case RLIMIT_OPENFILES: + value = (RLIMTYPE)getdtablesize (); + break; + case RLIMIT_VIRTMEM: + value = getmaxvm (mode); + break; + case RLIMIT_MAXUPROC: + value = getmaxuprc (mode); + break; + default: + errno = EINVAL; + return -1; } - else - return (ulimit (2, newlim / 512L)); - - break; - -#else /* defined (HAVE_RESOURCE) */ - - case u_FILE_SIZE: - cmd = RLIMIT_FSIZE; - goto do_ulimit; - - case u_CORE_FILE_SIZE: - cmd = RLIMIT_CORE; - goto do_ulimit; - - case u_DATA_SEG_SIZE: - cmd = RLIMIT_DATA; - goto do_ulimit; - -#if !defined (USGr4) - case u_PHYS_MEM_SIZE: -# if defined (RLIMIT_RSS) - cmd = RLIMIT_RSS; -# else /* !RLIMIT_RSS */ - errno = EINVAL; - return ((RLIMTYPE)-1); -# endif /* !RLIMIT_RSS */ - - goto do_ulimit; -#endif /* USGr4 */ - - case u_CPU_TIME_LIMIT: -#if defined (RLIMIT_CPU) - cmd = RLIMIT_CPU; - goto do_ulimit; + *limptr = value; + return ((value == RLIM_INVALID) ? -1 : 0); + } + else + { +#if defined (HAVE_RESOURCE) + if (getrlimit (limits[ind].parameter, &limit) < 0) + return -1; + value = (mode & LIMIT_SOFT) ? limit.rlim_cur : limit.rlim_max; + *limptr = value; + return 0; #else errno = EINVAL; - return ((RLIMTYPE)-1); -# endif /* !RLIMIT_CPU */ - - - case u_STACK_SIZE: - cmd = RLIMIT_STACK; - - do_ulimit: - - if (getrlimit (cmd, &limit) != 0) - return ((RLIMTYPE)-1); - - if (!setting) - { - if (mode & LIMIT_SOFT) - return (limit.rlim_cur); - else - return (limit.rlim_max); - } - else - { - if (mode & LIMIT_SOFT) - { - /* Non-root users are only allowed to raise a limit up to the - hard limit, not to infinity. */ - if (current_user.euid != 0 && newlim == RLIM_INFINITY) - limit.rlim_cur = limit.rlim_max; - else - limit.rlim_cur = newlim; - } - if (mode & LIMIT_HARD) - limit.rlim_max = newlim; - - return (setrlimit (cmd, &limit)); - } - - break; - -#endif /* HAVE_RESOURCE */ + return -1; +#endif + } +} - /* You can't get or set the pipe size with getrlimit, so we have to - cheat. */ - case u_PIPE_SIZE: - if (setting) - { - errno = EINVAL; - return ((RLIMTYPE)-1); - } - return (pipesize ()); +static int +set_limit (ind, newlim, mode) + int ind; + RLIMTYPE newlim; + int mode; +{ +#if defined (HAVE_RESOURCE) + struct rlimit limit; + RLIMTYPE val; +#endif - case u_NUM_OPEN_FILES: - if (setting) - { -#if defined (HAVE_RESOURCE) && defined (RLIMIT_NOFILE) - cmd = RLIMIT_NOFILE; - goto do_ulimit; -#else -# if defined (HAVE_SETDTABLESIZE) - return (setdtablesize (newlim)); -# else - errno = EINVAL; - return ((RLIMTYPE)-1); -# endif /* HAVE_SETDTABLESIZE */ -#endif /* !HAVE_RESOURCE || !RLIMIT_NOFILE */ - } - else - return (open_files (mode)); + if (limits[ind].parameter >= 256) + switch (limits[ind].parameter) + { + case RLIMIT_FILESIZE: +#if !defined (HAVE_RESOURCE) + return (ulimit (2, newlim / 512L)); +#endif - case u_MAX_VIRTUAL_MEM: - if (setting) - { - errno = EINVAL; - return ((RLIMTYPE)-1); - } - else - { + case RLIMIT_OPENFILES: +#if defined (HAVE_SETDTABLESIZE) + return (setdtablesize (newlim)); +#endif + case RLIMIT_PIPESIZE: + case RLIMIT_VIRTMEM: + case RLIMIT_MAXUPROC: + default: + errno = EINVAL; + return -1; + } + else + { #if defined (HAVE_RESOURCE) - return (getmaxvm (mode)); -#else /* !HAVE_RESOURCE */ - errno = EINVAL; - return ((RLIMTYPE)-1); -#endif /* !HAVE_RESOURCE */ - } - - case u_MAX_USER_PROCS: -#if defined (HAVE_RESOURCE) && defined (RLIMIT_NPROC) - cmd = RLIMIT_NPROC; - goto do_ulimit; -#else /* !HAVE_RESOURCE || !RLIMIT_NPROC */ - errno = EINVAL; - return ((RLIMTYPE)-1); -#endif /* !HAVE_RESOURCE || !RLIMIT_NPROC */ - - default: + if (getrlimit (limits[ind].parameter, &limit) < 0) + return -1; + val = (current_user.euid != 0 && newlim == RLIM_INFINITY) + ? limit.rlim_max : newlim; + if (mode & LIMIT_SOFT) + limit.rlim_cur = val; + if (mode & LIMIT_HARD) + limit.rlim_max = val; + + return (setrlimit (limits[ind].parameter, &limit)); +#else errno = EINVAL; - return ((RLIMTYPE)-1); + return -1; +#endif } } -#if defined (HAVE_RESOURCE) static RLIMTYPE getmaxvm (mode) int mode; { +#if defined (HAVE_RESOURCE) struct rlimit rl; - -#if defined (RLIMIT_VMEM) - if (getrlimit (RLIMIT_VMEM, &rl) < 0) - return ((RLIMTYPE)-1); - else - return (((mode & LIMIT_SOFT) ? rl.rlim_cur : rl.rlim_max) / 1024L); -#else /* !RLIMIT_VMEM */ RLIMTYPE maxdata, maxstack; if (getrlimit (RLIMIT_DATA, &rl) < 0) - return ((RLIMTYPE)-1); + return (RLIM_INVALID); else maxdata = (mode & LIMIT_SOFT) ? rl.rlim_cur : rl.rlim_max; if (getrlimit (RLIMIT_STACK, &rl) < 0) - return ((RLIMTYPE)-1); + return (RLIM_INVALID); else maxstack = (mode & LIMIT_SOFT) ? rl.rlim_cur : rl.rlim_max; /* Protect against overflow. */ return ((maxdata / 1024L) + (maxstack / 1024L)); -#endif /* !RLIMIT_VMEM */ -} +#else + errno = EINVAL; + return RLIM_INVALID; #endif /* HAVE_RESOURCE */ +} static RLIMTYPE -open_files (mode) - int mode; +filesize() { -#if !defined (RLIMIT_NOFILE) - return ((RLIMTYPE)getdtablesize ()); +#if !defined (HAVE_RESOURCE) + return ((RLIMTYPE)ulimit (1, 0L)); #else - struct rlimit rl; - - getrlimit (RLIMIT_NOFILE, &rl); - if (mode & LIMIT_SOFT) - return (rl.rlim_cur); - else - return (rl.rlim_max); + errno = EINVAL; + return RLIM_INVALID; #endif } @@ -607,125 +526,57 @@ pipesize () return ((RLIMTYPE) PIPESIZE); # else errno = EINVAL; - return ((RLIMTYPE)-1); + return RLIM_INVALID; # endif /* PIPESIZE */ #endif /* PIPE_BUF */ } -/* ulimit(2) returns information about file size limits in terms of 512-byte - blocks. This is the factor by which to divide to turn it into information - in terms of 1024-byte blocks. Except for hpux 6.x, which returns it in - terms of bytes. */ -#if !defined (hpux) || defined (_POSIX_VERSION) -# define ULIMIT_DIVISOR 2 -#else -# define ULIMIT_DIVISOR 1024 -#endif - -#if defined (HAVE_RESOURCE) - -typedef struct { - int option_cmd; /* The ulimit command for this limit. */ - int parameter; /* Parameter to pass to getrlimit (). */ - int block_factor; /* Blocking factor for specific limit. */ - char *description; /* Descriptive string to output. */ -} BSD_RESOURCE_LIMITS; - -static BSD_RESOURCE_LIMITS limits[] = { - { u_CORE_FILE_SIZE, RLIMIT_CORE, 1024, "core file size (blocks)" }, - { u_DATA_SEG_SIZE, RLIMIT_DATA, 1024, "data seg size (kbytes)" }, - { u_FILE_SIZE, RLIMIT_FSIZE, 1024, "file size (blocks)" }, -#if !defined (USGr4) && defined (RLIMIT_RSS) - { u_PHYS_MEM_SIZE, RLIMIT_RSS, 1024, "max memory size (kbytes)" }, -#endif /* USGr4 && RLIMIT_RSS */ - { u_STACK_SIZE, RLIMIT_STACK, 1024, "stack size (kbytes)" }, -#if defined (RLIMIT_CPU) - { u_CPU_TIME_LIMIT, RLIMIT_CPU, 1, "cpu time (seconds)" }, -#endif /* RLIMIT_CPU */ -#if defined (RLIMIT_NPROC) - { u_MAX_USER_PROCS, RLIMIT_NPROC, 1, "max user processes" }, -#endif /* RLIMIT_NPROC */ - { 0, 0, 0, (char *)NULL } -}; - -static void -print_bsd_limit (i, mode) - int i, mode; +static RLIMTYPE +getmaxuprc (mode) + int mode; { - struct rlimit rl; - RLIMTYPE limit; - - getrlimit (limits[i].parameter, &rl); - if (mode & LIMIT_HARD) - limit = rl.rlim_max; - else - limit = rl.rlim_cur; - printf ("%-25s", limits[i].description); - if (limit == RLIM_INFINITY) - printf ("unlimited\n"); - else - print_rlimtype ((limit / limits[i].block_factor), 1); +# if defined (HAVE_SYSCONF) && defined (_SC_CHILD_MAX) + return ((RLIMTYPE)sysconf (_SC_CHILD_MAX)); +# else /* !HAVE_SYSCONF || !_SC_CHILD_MAX */ +# if defined (MAXUPRC) + return ((RLIMTYPE)MAXUPRC); +# else /* MAXUPRC */ + errno = EINVAL; + return RLIM_INVALID; +# endif /* !MAXUPRC */ +# endif /* !HAVE_SYSCONF || !_SC_CHILD_MAX */ } static void -print_specific_bsd_limits (cmd, mode) - int cmd, mode; +print_all_limits (mode) + int mode; { register int i; + RLIMTYPE value; - for (i = 0; limits[i].option_cmd; i++) - if (cmd & limits[i].option_cmd) - print_bsd_limit (i, mode); -} -#endif /* HAVE_RESOURCE */ - -/* Print the limits corresponding to a specific set of resources. This is - called when an option string contains more than one character (e.g. -at), - because limits may not be specified with that kind of argument. */ -static void -print_specific_limits (cmd, mode) - int cmd, mode; -{ if (mode == 0) - mode = LIMIT_SOFT; - -#if defined (HAVE_RESOURCE) - print_specific_bsd_limits (cmd, mode); -#else /* !HAVE_RESOURCE */ - if (cmd & u_FILE_SIZE) - { - printf ("%-25s", "file size (blocks)"); - print_rlimtype ((ulimit (1, 0L) / ULIMIT_DIVISOR), 1); - } -#endif /* !HAVE_RESOURCE */ - - if (cmd & u_PIPE_SIZE) - { - printf ("%-25s", "pipe size (512 bytes)"); - print_rlimtype ((pipesize () / 512), 1); - } - - if (cmd & u_NUM_OPEN_FILES) - { - printf ("%-25s", "open files"); - print_rlimtype (open_files (mode), 1); - } + mode |= LIMIT_SOFT; -#if defined (HAVE_RESOURCE) - if (cmd & u_MAX_VIRTUAL_MEM) + for (i = 0; limits[i].option > 0; i++) { - printf ("%-25s", "virtual memory (kbytes)"); - print_rlimtype (getmaxvm (mode), 1); + if (get_limit (i, mode, &value) < 0) + value = RLIM_INVALID; + printone (i, value, 1); } -#endif /* HAVE_RESOURCE */ } static void -print_all_limits (mode) - int mode; +printone (limind, curlim, pdesc) + int limind; + RLIMTYPE curlim; + int pdesc; { - if (mode == 0) - mode |= LIMIT_SOFT; - - print_specific_limits (u_ALL_LIMITS, mode); + if (pdesc) + printf (DESCFMT, limits[limind].description); + if (curlim == RLIM_INFINITY) + puts ("unlimited"); + else if (curlim == RLIM_INVALID) + printf ("cannot get limit: %s\n", strerror (errno)); + else + print_rlimtype ((curlim / limits[limind].block_factor), 1); } diff --git a/builtins/umask.def b/builtins/umask.def index 1d84aa9..5ef8f3b 100644 --- a/builtins/umask.def +++ b/builtins/umask.def @@ -31,12 +31,22 @@ If MODE begins with a digit, it is interpreted as an octal number, otherwise it is a symbolic mode string like that accepted by chmod(1). $END -#include -#include +#include + +#include "../bashtypes.h" +#include "../filecntl.h" #include + +#if defined (HAVE_UNISTD_H) +#include +#endif + +#include + #include "../shell.h" #include "../posixstat.h" #include "common.h" +#include "bashgetopt.h" /* **************************************************************** */ /* */ @@ -49,47 +59,40 @@ static int symbolic_umask (); /* Set or display the mask used by the system when creating files. Flag of -S means display the umask in a symbolic mode. */ +int umask_builtin (list) WORD_LIST *list; { - int print_symbolically = 0; + int print_symbolically, opt, umask_value; - while (list) + print_symbolically = 0; + reset_internal_getopt (); + while ((opt = internal_getopt (list, "S")) != -1) { - if (ISOPTION (list->word->word, 'S')) + switch (opt) { - list = list->next; + case 'S': print_symbolically++; - continue; - } - else if (ISOPTION (list->word->word, '-')) - { - list = list->next; break; - } - else if (*(list->word->word) == '-') - { - bad_option (list->word->word); - builtin_error ("usage: umask [-S] [mode]"); + default: + builtin_usage (); return (EX_USAGE); } - else - break; } + list = loptend; + if (list) { - int new_umask; - if (digit (*list->word->word)) { - new_umask = read_octal (list->word->word); + umask_value = read_octal (list->word->word); /* Note that other shells just let you set the umask to zero by specifying a number out of range. This is a problem with those shells. We don't change the umask if the input is lousy. */ - if (new_umask == -1) + if (umask_value == -1) { builtin_error ("`%s' is not an octal number from 000 to 777", list->word->word); @@ -98,26 +101,25 @@ umask_builtin (list) } else { - new_umask = symbolic_umask (list); - if (new_umask == -1) + umask_value = symbolic_umask (list); + if (umask_value == -1) return (EXECUTION_FAILURE); } - umask (new_umask); + umask (umask_value); if (print_symbolically) - print_symbolic_umask (new_umask); + print_symbolic_umask (umask_value); } else /* Display the UMASK for this user. */ { - int old_umask; - - old_umask = umask (022); - umask (old_umask); + umask_value = umask (022); + umask (umask_value); if (print_symbolically) - print_symbolic_umask (old_umask); + print_symbolic_umask (umask_value); else - printf ("%03o\n", old_umask); + printf ("%03o\n", umask_value); } + fflush (stdout); return (EXECUTION_SUCCESS); } @@ -176,7 +178,7 @@ symbolic_umask (list) um = umask (022); umask (um); - /* All work below is done with the complement of the umask -- its + /* All work below is done with the complement of the umask -- it's more intuitive and easier to deal with. It is complemented again before being returned. */ umc = ~um; @@ -266,7 +268,7 @@ symbolic_umask (list) break; default: - builtin_error ("bad operation character: %c", op); + builtin_error ("bad symbolic mode operator: %c", op); return (-1); } diff --git a/builtins/wait.def b/builtins/wait.def index f613179..b9290d9 100644 --- a/builtins/wait.def +++ b/builtins/wait.def @@ -19,7 +19,6 @@ 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, 675 Mass Ave, Cambridge, MA 02139, USA. - $BUILTIN wait $FUNCTION wait_builtin $DEPENDS_ON JOB_CONTROL @@ -42,10 +41,18 @@ and the return code is zero. N is a process ID; if it is not given, all child processes of the shell are waited for. $END -#include +#include + +#include "../bashtypes.h" #include + +#if defined (HAVE_UNISTD_H) +# include +#endif + #include "../shell.h" #include "../jobs.h" +#include "common.h" extern int interrupt_immediately; @@ -53,10 +60,17 @@ extern int interrupt_immediately; wait for all of the active background processes of the shell and return 0. If a list of pids or job specs are given, return the exit status of the last one waited for. */ + +#define WAIT_RETURN(s) do { run_unwind_frame ("wait_builtin"); return (s); } while (0) + +int wait_builtin (list) WORD_LIST *list; { - int status = EXECUTION_SUCCESS; + int status; + + if (no_options (list)) + return (EX_USAGE); begin_unwind_frame ("wait_builtin"); unwind_protect_int (interrupt_immediately); @@ -67,13 +81,13 @@ wait_builtin (list) /* But wait without any arguments means to wait for all of the shell's currently active background processes. */ - if (!list) + if (list == 0) { wait_for_background_pids (); - status = EXECUTION_SUCCESS; - goto return_status; + WAIT_RETURN (EXECUTION_SUCCESS); } + status = EXECUTION_SUCCESS; while (list) { pid_t pid; @@ -89,9 +103,8 @@ wait_builtin (list) } else { - builtin_error ("`%s' is not a pid or legal job spec", w); - status = EXECUTION_FAILURE; - goto return_status; + builtin_error ("`%s' is not a pid or valid job spec", w); + WAIT_RETURN (EXECUTION_FAILURE); } } #if defined (JOB_CONTROL) @@ -107,7 +120,7 @@ wait_builtin (list) if (job < 0 || job >= job_slots || !jobs[job]) { if (job != DUP_JOB) - builtin_error ("No such job %s", list->word->word); + builtin_error ("%s: no such job", list->word->word); UNBLOCK_CHILD (oset); status = 127; /* As per Posix.2, section 4.70.2 */ list = list->next; @@ -121,12 +134,11 @@ wait_builtin (list) #endif /* JOB_CONTROL */ else { - builtin_error ("`%s' is not a pid or legal job spec", w); + builtin_error ("`%s' is not a pid or valid job spec", w); status = EXECUTION_FAILURE; } list = list->next; } - return_status: - run_unwind_frame ("wait_builtin"); - return (status); + + WAIT_RETURN (status); } diff --git a/command.h b/command.h index cffc15f..cbbb028 100644 --- a/command.h +++ b/command.h @@ -19,8 +19,8 @@ with Bash; see the file COPYING. If not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ -#if !defined (_COMMAND_H) -#define _COMMAND_H +#if !defined (_COMMAND_H_) +#define _COMMAND_H_ #include "stdc.h" @@ -33,18 +33,45 @@ enum r_instruction { r_duplicating_input_word, r_duplicating_output_word }; +/* Redirection errors. */ +#define AMBIGUOUS_REDIRECT -1 +#define NOCLOBBER_REDIRECT -2 +#define RESTRICTED_REDIRECT -3 /* can only happen in restricted shells. */ + +#define OUTPUT_REDIRECT(ri) \ + (ri == r_output_direction || ri == r_input_output || ri == r_err_and_out) + +#define INPUT_REDIRECT(ri) \ + (ri == r_input_direction || ri == r_inputa_direction || ri == r_input_output) + +#define WRITE_REDIRECT(ri) \ + (ri == r_output_direction || \ + ri == r_input_output || \ + ri == r_err_and_out || \ + ri == r_appending_to || \ + ri == r_output_force) + /* Command Types: */ enum command_type { cm_for, cm_case, cm_while, cm_if, cm_simple, cm_select, cm_connection, cm_function_def, cm_until, cm_group }; +/* Possible values for the `flags' field of a WORD_DESC. */ +#define W_HASDOLLAR 0x01 /* Dollar sign present. */ +#define W_QUOTED 0x02 /* Some form of quote character is present. */ +#define W_ASSIGNMENT 0x04 /* This word is a variable assignment. */ +#define W_GLOBEXP 0x08 /* This word is the result of a glob expansion. */ +#define W_NOSPLIT 0x10 /* Do not perform word splitting on this word. */ + +/* Possible values for subshell_environment */ +#define SUBSHELL_ASYNC 0x01 /* subshell caused by `command &' */ +#define SUBSHELL_PAREN 0x02 /* subshell caused by ( ... ) */ +#define SUBSHELL_COMSUB 0x04 /* subshell caused by `command` or $(command) */ +#define SUBSHELL_FORK 0x08 /* subshell caused by executing a disk command */ + /* A structure which represents a word. */ typedef struct word_desc { char *word; /* Zero terminated string. */ - int dollar_present; /* Non-zero means dollar sign present. */ - int quoted; /* Non-zero means single, double, or back quote - or backslash is present. */ - int assignment; /* Non-zero means that this word contains an - assignment. */ + int flags; /* Flags associated with this word. */ } WORD_DESC; /* A linked list of words. */ @@ -92,6 +119,8 @@ typedef struct element { #define CMD_NO_FUNCTIONS 0x10 /* Ignore functions during command lookup. */ #define CMD_INHIBIT_EXPANSION 0x20 /* Do not expand the command words. */ #define CMD_NO_FORK 0x40 /* Don't fork; just call execve */ +#define CMD_TIME_PIPELINE 0x80 /* Time a pipeline */ +#define CMD_TIME_POSIX 0x100 /* time -p; use POSIX.2 time output spec. */ /* What a command looks like. */ typedef struct command { @@ -184,19 +213,16 @@ typedef struct simple_com { int line; /* line number the command starts on */ } SIMPLE_COM; -/* The "function_def" command. This isn't really a command, but it is - represented as such for now. If the function def appears within - `(' `)' the parser tries to set the SUBSHELL bit of the command. That - means that FUNCTION_DEF has to be run through the executor. Maybe this - command should be defined in a subshell. Who knows or cares. */ +/* The "function definition" command. */ typedef struct function_def { int ignore; /* See description of CMD flags. */ WORD_DESC *name; /* The name of the function. */ COMMAND *command; /* The parsed execution tree. */ + int line; /* Line number the function def starts on. */ } FUNCTION_DEF; -/* A command that is `grouped' allows pipes to take effect over - the entire command structure. */ +/* A command that is `grouped' allows pipes and redirections to affect all + commands in the group. */ typedef struct group_com { int ignore; /* See description of CMD flags. */ COMMAND *command; @@ -212,4 +238,4 @@ extern REDIRECT *copy_redirect __P((REDIRECT *)); extern REDIRECT *copy_redirects __P((REDIRECT *)); extern COMMAND *copy_command __P((COMMAND *)); -#endif /* _COMMAND_H */ +#endif /* _COMMAND_H_ */ diff --git a/config.h b/config.h deleted file mode 100644 index 8fd2ba3..0000000 --- a/config.h +++ /dev/null @@ -1,186 +0,0 @@ -/* config.h -- Configuration file for bash. */ - -/* Copyright (C) 1987,1991 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 1, 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, 675 Mass Ave, Cambridge, MA 02139, USA. */ - -#if !defined (_CONFIG_H_) -#define _CONFIG_H_ - -#if !defined (BUILDING_MAKEFILE) -#include "memalloc.h" -#endif - -#if defined (HAVE_UNISTD_H) && !defined (BUILDING_MAKEFILE) -# ifdef CRAY -# define word __word -# endif -#include -# ifdef CRAY -# undef word -# endif -#endif - -/* Define JOB_CONTROL if your operating system supports - BSD-like job control. */ -#define JOB_CONTROL - -/* Note that vanilla System V machines don't support BSD job control, - although some do support Posix job control. */ -#if defined (USG) || defined (MINIX) || defined (Minix) -# if !defined (_POSIX_JOB_CONTROL) -# undef JOB_CONTROL -# endif /* !_POSIX_JOB_CONTROL */ -#endif /* USG || Minix || MINIX */ - -/* Define ALIAS if you want the alias features. */ -#define ALIAS - -/* Define PUSHD_AND_POPD if you want those commands to be compiled in. - (Also the `dirs' commands.) */ -#define PUSHD_AND_POPD - -/* Define BRACE_EXPANSION if you want curly brace expansion a la Csh: - foo{a,b} -> fooa foob. Even if this is compiled in (the default) you - can turn it off at shell startup with `-nobraceexpansion', or during - shell execution with `set +o braceexpand'. */ -#define BRACE_EXPANSION - -/* Define READLINE to get the nifty/glitzy editing features. - This is on by default. You can turn it off interactively - with the -nolineediting flag. */ -#define READLINE - -/* Define BANG_HISTORY if you want to have Csh style "!" history expansion. - This is unrelated to READLINE. */ -#define BANG_HISTORY - -/* Define HISTORY if you want to have access to previously typed commands. - - If both HISTORY and READLINE are defined, you can get at the commands - with line editing commands, and you can directly manipulate the history - from the command line. - - If only HISTORY is defined, the `fc' and `history' builtins are - available. */ -#define HISTORY - -#if defined (BANG_HISTORY) && !defined (HISTORY) - /* BANG_HISTORY requires HISTORY. */ -# define HISTORY -#endif /* BANG_HISTORY && !HISTORY */ - -#if defined (READLINE) && !defined (HISTORY) -# define HISTORY -#endif - -/* The default value of the PATH variable. */ -#define DEFAULT_PATH_VALUE \ - "/usr/gnu/bin:/usr/local/bin:/usr/ucb:/bin:/usr/bin:." - -/* The value for PATH when invoking `command -p'. This is only used when - the Posix.2 confstr () function, or CS_PATH define are not present. */ -#define STANDARD_UTILS_PATH \ - "/bin:/usr/bin:/usr/ucb:/usr/sbin:/sbin:/etc:/usr/etc:/usr/lib" - -/* Put system-specific default mail directories here. */ -#if defined (__bsdi__) || defined (__FreeBSD__) || defined (__NetBSD__) -# define DEFAULT_MAIL_PATH "/var/mail/" -#endif - -#if !defined (DEFAULT_MAIL_PATH) -#if defined (USG) -# define DEFAULT_MAIL_PATH "/usr/mail/" -#else -# define DEFAULT_MAIL_PATH "/usr/spool/mail/" -#endif -#endif - -/* Define V9_ECHO if you want to give the echo builtin backslash-escape - interpretation using the -e option, in the style of the Bell Labs 9th - Edition version of echo. */ -#define V9_ECHO - -/* Define DEFAULT_ECHO_TO_USG if you want the echo builtin to interpret - the backslash-escape characters by default, like the System V echo. - This requires that V9_ECHO be defined. */ -/* #define DEFAULT_ECHO_TO_USG */ -#if !defined (V9_ECHO) -# undef DEFAULT_ECHO_TO_USG -#endif - -/* Define CONTINUE_AFTER_KILL_ERROR if you want the kill command to - continue processing arguments after one of them fails. */ -#define CONTINUE_AFTER_KILL_ERROR - -/* Define BREAK_COMPLAINS if you want the non-standard, but useful - error messages about `break' and `continue' out of context. */ -#define BREAK_COMPLAINS - -/* Define GETOPTS_BUILTIN if you want the Posix.2 `getopts' shell builtin - compiled into the shell. */ -#define GETOPTS_BUILTIN - -/* When ALLOW_RIGID_POSIX_COMPLIANCE is defined, you can turn on strictly - Posix compliant behaviour by setting the environment variable - POSIXLY_CORRECT. */ -#define ALLOW_RIGID_POSIX_COMPLIANCE - -/* Define RESTRICTED_SHELL if you want the generated shell to have the - ability to be a restricted one. The shell thus generated can become - restricted by being run with the name "rbash", or by setting the -r - flag. */ -/* #define RESTRICTED_SHELL */ - -/* Define DISABLED_BUILTINS if you want "builtin foo" to always run the - shell builtin "foo", even if it has been disabled with "enable -n foo". */ -/* #define DISABLED_BUILTINS */ - -/* Define PROCESS_SUBSTITUTION if you want the K*rn shell-like process - substitution features "<(file)". */ -/* Right now, you cannot do this on machines without fully operational - FIFO support. This currently include NeXT and Alliant. */ -#if !defined (MKFIFO_MISSING) || defined (HAVE_DEV_FD) -# define PROCESS_SUBSTITUTION -#endif /* !MKFIFO_MISSING */ - -/* Define PROMPT_STRING_DECODE if you want the backslash-escaped special - characters in PS1 and PS2 expanded. Variable expansion will still be - performed. */ -#define PROMPT_STRING_DECODE - -/* Define BUFFERED_INPUT if you want the shell to do its own input - buffering. */ -#define BUFFERED_INPUT - -/* Define INTERACTIVE_COMMENTS if you want # comments to work by default - when the shell is interactive, as Posix.2a specifies. */ -#define INTERACTIVE_COMMENTS - -/* Define ONESHOT if you want sh -c 'command' to avoid forking to execute - `command' whenever possible. */ -#define ONESHOT - -/* Default primary and secondary prompt strings. */ -#define PPROMPT "bash\\$ " -#define SPROMPT "> " - -/* Define SELECT_COMMAND if you want the Korn-shell style `select' command: - select word in word_list; do command_list; done */ -#define SELECT_COMMAND - -#endif /* !_CONFIG_H_ */ diff --git a/config.h.bot b/config.h.bot new file mode 100644 index 0000000..2261917 --- /dev/null +++ b/config.h.bot @@ -0,0 +1,63 @@ +/* config.h.bot */ +/* modify settings or make new ones based on what autoconf tells us. */ + +#if !defined (HAVE_VPRINTF) && defined (HAVE_DOPRNT) +# define USE_VFPRINTF_EMULATION +# define HAVE_VPRINTF +#endif + +/* Ultrix botches type-ahead when switching from canonical to + non-canonical mode, at least through version 4.3 */ +#if !defined (HAVE_TERMIOS_H) || !defined (HAVE_TCGETATTR) || defined (ultrix) +# define TERMIOS_MISSING +#endif + +/* If we have a getcwd(3), but it calls popen(), #undef HAVE_GETCWD so + the replacement in getcwd.c will be built. */ +#if defined (HAVE_GETCWD) && defined (GETCWD_BROKEN) +# undef HAVE_GETCWD +#endif + +#if defined (HAVE_SYS_RESOURCE_H) && defined (HAVE_GETRLIMIT) +# define HAVE_RESOURCE +#endif + +#if !defined (GETPGRP_VOID) +# define HAVE_BSD_PGRP +#endif + +#if !defined (HAVE_DEV_FD) && defined (NAMED_PIPES_MISSING) +# undef PROCESS_SUBSTITUTION +#endif + +/* If the shell is called by this name, it will become restricted. */ +#if defined (RESTRICTED_SHELL) +# define RESTRICTED_SHELL_NAME "rbash" +#endif + +/* BANG_HISTORY requires HISTORY. */ +#if defined (BANG_HISTORY) && !defined (HISTORY) +# define HISTORY +#endif /* BANG_HISTORY && !HISTORY */ + +#if defined (READLINE) && !defined (HISTORY) +# define HISTORY +#endif + +#if !defined (V9_ECHO) +# undef DEFAULT_ECHO_TO_USG +#endif + +#if defined (JOB_CONTROL_MISSING) +# undef JOB_CONTROL +#endif + +#if defined (__STDC__) && defined (HAVE_STDARG_H) +# define PREFER_STDARG +# define USE_VARARGS +#else +# if defined (HAVE_VARARGS_H) +# define PREFER_VARARGS +# define USE_VARARGS +# endif +#endif diff --git a/config.h.in b/config.h.in new file mode 100644 index 0000000..584f814 --- /dev/null +++ b/config.h.in @@ -0,0 +1,505 @@ +/* config.h -- Configuration file for bash. */ + +/* Copyright (C) 1987,1991 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 1, 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, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#ifndef _CONFIG_H_ +#define _CONFIG_H_ + +/* Configuration settings controllable by autoconf. */ + +/* Define JOB_CONTROL if your operating system supports + BSD-like job control. */ +#undef JOB_CONTROL + +/* Define ALIAS if you want the alias features. */ +#undef ALIAS + +/* Define PUSHD_AND_POPD if you want those commands to be compiled in. + (Also the `dirs' commands.) */ +#undef PUSHD_AND_POPD + +/* Define BRACE_EXPANSION if you want curly brace expansion a la Csh: + foo{a,b} -> fooa foob. Even if this is compiled in (the default) you + can turn it off at shell startup with `-nobraceexpansion', or during + shell execution with `set +o braceexpand'. */ +#undef BRACE_EXPANSION + +/* Define READLINE to get the nifty/glitzy editing features. + This is on by default. You can turn it off interactively + with the -nolineediting flag. */ +#undef READLINE + +/* Define BANG_HISTORY if you want to have Csh style "!" history expansion. + This is unrelated to READLINE. */ +#undef BANG_HISTORY + +/* Define HISTORY if you want to have access to previously typed commands. + + If both HISTORY and READLINE are defined, you can get at the commands + with line editing commands, and you can directly manipulate the history + from the command line. + + If only HISTORY is defined, the `fc' and `history' builtins are + available. */ +#undef HISTORY + +/* Define this if you want completion that puts all alternatives into + a brace expansion shell expression. */ +#if defined (BRACE_EXPANSION) && defined (READLINE) +# define BRACE_COMPLETION +#endif /* BRACE_EXPANSION */ + +/* Define DEFAULT_ECHO_TO_USG if you want the echo builtin to interpret + the backslash-escape characters by default, like the System V echo. + This requires that V9_ECHO be defined. */ +#undef DEFAULT_ECHO_TO_USG + +/* Define HELP_BUILTIN if you want the `help' shell builtin and the long + documentation strings compiled into the shell. */ +#undef HELP_BUILTIN + +/* Define RESTRICTED_SHELL if you want the generated shell to have the + ability to be a restricted one. The shell thus generated can become + restricted by being run with the name "rbash", or by setting the -r + flag. */ +#undef RESTRICTED_SHELL + +/* Define DISABLED_BUILTINS if you want "builtin foo" to always run the + shell builtin "foo", even if it has been disabled with "enable -n foo". */ +#undef DISABLED_BUILTINS + +/* Define PROCESS_SUBSTITUTION if you want the K*rn shell-like process + substitution features "<(file)". */ +/* Right now, you cannot do this on machines without fully operational + FIFO support. This currently include NeXT and Alliant. */ +#undef PROCESS_SUBSTITUTION + +/* Define PROMPT_STRING_DECODE if you want the backslash-escaped special + characters in PS1 and PS2 expanded. Variable expansion will still be + performed. */ +#undef PROMPT_STRING_DECODE + +/* Define SELECT_COMMAND if you want the Korn-shell style `select' command: + select word in word_list; do command_list; done */ +#undef SELECT_COMMAND + +/* Define COMMAND_TIMING of you want the ksh-style `time' reserved word and + the ability to time pipelines, functions, and builtins. */ +#undef COMMAND_TIMING + +/* Define ARRAY_VARS if you want ksh-style one-dimensional array variables. */ +#undef ARRAY_VARS + +/* Define DPAREN_ARITHMETIC if you want the ksh-style ((...)) arithmetic + evaluation command. */ +#undef DPAREN_ARITHMETIC + +/* Define AFS if you are using Transarc's AFS. */ +#undef AFS + +/* End of configuration settings controllable by autoconf. */ +/* Other settable options appear in config.h.top. */ + +#include "config.h.top" + +/* Beginning of autoconf additions. */ + +/* Define if using alloca.c. */ +#undef C_ALLOCA + +/* Define to one of _getb67, GETB67, getb67 for Cray-2 and Cray-YMP systems. + This function is required for alloca.c support on those systems. */ +#undef CRAY_STACKSEG_END + +/* Define to the type of elements in the array set by `getgroups'. + Usually this is either `int' or `gid_t'. */ +#undef GETGROUPS_T + +/* Define if the `getpgrp' function takes no argument. */ +#undef GETPGRP_VOID + +/* Define to `int' if doesn't define. */ +#undef gid_t + +/* Define if you have alloca, as a function or macro. */ +#undef HAVE_ALLOCA + +/* Define if you have and it should be used (not on Ultrix). */ +#undef HAVE_ALLOCA_H + +/* Define if you don't have vprintf but do have _doprnt. */ +#undef HAVE_DOPRNT + +/* Define if system calls automatically restart after interruption + by a signal. */ +#undef HAVE_RESTARTABLE_SYSCALLS + +/* Define if you have that is POSIX.1 compatible. */ +#undef HAVE_SYS_WAIT_H + +/* Define if you have */ +#undef HAVE_SYS_TIME_H + +#undef TIME_WITH_SYS_TIME + +#undef HAVE_SYS_TIMES_H + +/* Define if you have the vprintf function. */ +#undef HAVE_VPRINTF + +#undef HAVE_WAIT3 + +#undef HAVE_SETOSTYPE + +/* Define if on MINIX. */ +#undef _MINIX + +/* Define to `long' if doesn't define. */ +#undef off_t + +/* Define to `int' if doesn't define. */ +#undef mode_t + +/* Define to `int' if doesn't define. */ +#undef sigset_t + +/* Define to `int' if doesn't define. */ +#undef pid_t + +/* Define if the system does not provide POSIX.1 features except + with this defined. */ +#undef _POSIX_1_SOURCE + +/* Define if you need to in order for stat and other things to work. */ +#undef _POSIX_SOURCE + +/* Define as the return type of signal handlers (int or void). */ +#undef RETSIGTYPE + +/* Define if the setvbuf function takes the buffering type as its second + argument and the buffer pointer as the third, as on System V + before release 3. */ +#undef SETVBUF_REVERSED + +/* Define to `unsigned' if doesn't define. */ +#undef size_t + +/* If using the C implementation of alloca, define if you know the + direction of stack growth for your system; otherwise it will be + automatically deduced at run-time. + STACK_DIRECTION > 0 => grows toward higher addresses + STACK_DIRECTION < 0 => grows toward lower addresses + STACK_DIRECTION = 0 => direction of growth unknown + */ +#undef STACK_DIRECTION + +/* Define if you have the ANSI C header files. */ +#undef STDC_HEADERS + +/* Define if `sys_siglist' is declared by . */ +#undef SYS_SIGLIST_DECLARED + +/* Define to `int' if doesn't define. */ +#undef uid_t + +/* Define to `long' if doesn't define. */ +#undef clock_t + +/* Define to `long' if doesn't define. */ +#undef time_t + +#undef DUP2_BROKEN + +#undef HAVE_GETRLIMIT + +#undef HAVE_GETRUSAGE + +#undef HAVE_GETTIMEOFDAY + +#undef GWINSZ_IN_SYS_IOCTL + +#undef TIOCSTAT_IN_SYS_IOCTL + +#undef FIONREAD_IN_SYS_IOCTL + +#undef WORDS_BIGENDIAN + +#undef HAVE_HASH_BANG_EXEC + +#undef HAVE_BSD_SIGNALS + +#undef HAVE_POSIX_SIGNALS + +#undef HAVE_USG_SIGHOLD + +#undef HAVE_DEV_FD + +#undef DEV_FD_PREFIX + +#undef HAVE_GETPW_DECLS + +#undef HAVE_QUAD_T + +#undef HAVE_RESOURCE + +#undef HAVE_STRSIGNAL + +#undef HAVE_SYS_ERRLIST + +#undef STAT_MACROS_BROKEN + +#undef HAVE_TIMEVAL + +#undef HAVE_MEMMOVE + +#undef HAVE_MKFIFO + +#undef NAMED_PIPES_MISSING + +#undef OPENDIR_NOT_ROBUST + +#undef PGRP_PIPE + +#undef RLIMTYPE + +#undef SBRK_DECLARED + +#undef PRINTF_DECLARED + +#undef HAVE_SYS_SIGLIST + +#undef HAVE_TIMES + +#undef HAVE_UNDER_SYS_SIGLIST + +#undef VOID_SIGHANDLER + +#undef TERMIOS_LDISC + +#undef TERMIO_LDISC + +#undef ULIMIT_MAXFDS + +#undef GETCWD_BROKEN + +#undef STRUCT_DIRENT_HAS_D_INO + +#undef CAN_REDEFINE_GETENV + +#undef MUST_REINSTALL_SIGHANDLERS + +#undef JOB_CONTROL_MISSING + +#undef HAVE_POSIX_SIGSETJMP + +#define DEFAULT_MAIL_DIRECTORY "/usr/spool/mail" + +/* Define if you have the bcopy function. */ +#undef HAVE_BCOPY + +/* Define if you have the bzero function. */ +#undef HAVE_BZERO + +/* Define if you have the confstr function. */ +#undef HAVE_CONFSTR + +/* Define if you have the dlclose function. */ +#undef HAVE_DLCLOSE + +/* Define if you have the dlopen function. */ +#undef HAVE_DLOPEN + +/* Define if you have the dlsym function. */ +#undef HAVE_DLSYM + +/* Define if you have the dup2 function. */ +#undef HAVE_DUP2 + +/* Define if you have the getcwd function. */ +#undef HAVE_GETCWD + +/* Define if you have the getdtablesize function. */ +#undef HAVE_GETDTABLESIZE + +/* Define if you have the getgroups function. */ +#undef HAVE_GETGROUPS + +/* Define if you have the gethostname function. */ +#undef HAVE_GETHOSTNAME + +/* Define if you have the getpagesize function. */ +#undef HAVE_GETPAGESIZE + +/* Define if you have the getpeername function. */ +#undef HAVE_GETPEERNAME + +/* Define if you have the getwd function. */ +#undef HAVE_GETWD + +/* Define if you have the killpg function. */ +#undef HAVE_KILLPG + +#undef HAVE_LSTAT + +/* Define if you have the putenv function. */ +#undef HAVE_PUTENV + +/* Define if you have the select function. */ +#undef HAVE_SELECT + +/* Define if you have the setdtablesize function. */ +#undef HAVE_SETDTABLESIZE + +/* Define if you have the setenv function. */ +#undef HAVE_SETENV + +/* Define if you have the setlinebuf function. */ +#undef HAVE_SETLINEBUF + +/* Define if you have the setlocale function. */ +#undef HAVE_SETLOCALE + +#undef HAVE_SIGINTERRUPT + +/* Define if you have the strcasecmp function. */ +#undef HAVE_STRCASECMP + +/* Define if you have the strchr function. */ +#undef HAVE_STRCHR + +/* Define if you have the strerror function. */ +#undef HAVE_STRERROR + +/* Define if you have the tcgetattr function. */ +#undef HAVE_TCGETATTR + +/* Define if you have the sysconf function. */ +#undef HAVE_SYSCONF + +/* Define if you have the uname function. */ +#undef HAVE_UNAME + +/* Define if you have the ulimit function. */ +#undef HAVE_ULIMIT + +#undef HAVE_WAITPID + +#undef HAVE_TCGETPGRP + +#undef HAVE_GETTEXT + +#undef HAVE_TEXTDOMAIN + +#undef HAVE_BINDTEXTDOMAIN + +#undef HAVE_STRCOLL + +#undef HAVE_TZSET + +/* Define if you have the header file. */ +#undef HAVE_DIRENT_H + +/* Define if you have the header file. */ +#undef HAVE_LIMITS_H + +/* Define if you have the header file. */ +#undef HAVE_LOCALE_H + +/* Define if you have the header file. */ +#undef HAVE_NDIR_H + +/* Define if you have the header file. */ +#undef HAVE_STDLIB_H + +/* Define if you have the header file. */ +#undef HAVE_STDARG_H + +/* Define if you have the header file. */ +#undef HAVE_STRING_H + +/* Define if you have the header file. */ +#undef HAVE_MEMORY_H + +/* Define if you have the header file. */ +#undef HAVE_SYS_DIR_H + +/* Define if you have the header file. */ +#undef HAVE_SYS_FILE_H + +/* Define if you have the header file. */ +#undef HAVE_SYS_NDIR_H + +/* Define if you have the header file. */ +#undef HAVE_SYS_PARAM_H + +/* Define if you have the header file. */ +#undef HAVE_SYS_PTE_H + +/* Define if you have the header file. */ +#undef HAVE_SYS_PTEM_H + +/* Define if you have the header file. */ +#undef HAVE_SYS_RESOURCE_H + +/* Define if you have the header file. */ +#undef HAVE_SYS_SELECT_H + +/* Define if you have the header file. */ +#undef HAVE_SYS_SOCKET_H + +/* Define if you have the header file. */ +#undef HAVE_SYS_STREAM_H + +/* Define if you have the header file. */ +#undef HAVE_TERMCAP_H + +/* Define if you have the header file. */ +#undef HAVE_TERMIO_H + +/* Define if you have the header file. */ +#undef HAVE_TERMIOS_H + +/* Define if you have the header file. */ +#undef HAVE_UNISTD_H + +/* Define if you have the header file. */ +#undef HAVE_VARARGS_H + +/* Define if you have the header file. */ +#undef HAVE_LIBINTL_H + +#undef HAVE_LIBDL + +#undef HAVE_LIBSUN + +#undef HAVE_LIBSOCKET + +/* Are we running SVR4.2? */ +#undef SVR4_2 + +/* Are we running some version of SVR4? */ +#undef SVR4 + +/* Do we need to define _KERNEL to get the RLIMIT_* defines from + ? */ +#undef RLIMIT_NEEDS_KERNEL + +#include "config.h.bot" + +#endif /* _CONFIG_H_ */ diff --git a/config.h.mini b/config.h.mini deleted file mode 100644 index 3acc84e..0000000 --- a/config.h.mini +++ /dev/null @@ -1,194 +0,0 @@ -/* config.h -- Configuration file for bash. */ - -/* This is a `minimal' configuration file. It will create a shell without: - job control - aliases - pushd and popd - readline - history - restricted shell mode - `disabled' builtins (builtin xxx finds xxx even after enable -n xxx) - process substitution - prompt string decoding (though variable expansion is still done) - the `select' command */ - -/* Copyright (C) 1987,1991 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 1, 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, 675 Mass Ave, Cambridge, MA 02139, USA. */ - -#if !defined (_CONFIG_H_) -#define _CONFIG_H_ - -#include "memalloc.h" - -#if defined (HPUX) || defined (UNIXPC) || defined (Xenix) -# if !defined (USG) -# define USG -# endif -#endif - -#if defined (HAVE_UNISTD_H) && !defined (BUILDING_MAKEFILE) -#include -#endif - -/* Define JOB_CONTROL if your operating system supports - BSD-like job control. */ -/* #define JOB_CONTROL */ - -/* Note that vanilla System V machines don't support BSD job control, - although some do support Posix job control. */ -#if defined (USG) && !defined (_POSIX_JOB_CONTROL) -# undef JOB_CONTROL -#endif /* USG && !_POSIX_JOB_CONTROL */ - -/* Define ALIAS if you want the alias features. */ -/* #define ALIAS */ - -/* Define PUSHD_AND_POPD if you want those commands to be compiled in. - (Also the `dirs' commands.) */ -/* #define PUSHD_AND_POPD */ - -/* Define BRACE_EXPANSION if you want curly brace expansion a la Csh: - foo{a,b} -> fooa foob. Even if this is compiled in (the default) you - can turn it off at shell startup with `-nobraceexpansion', or during - shell execution with `set +o braceexpand'. */ -/* #define BRACE_EXPANSION */ - -/* Define READLINE to get the nifty/glitzy editing features. - This is on by default. You can turn it off interactively - with the -nolineediting flag. */ -/* #define READLINE */ - -/* Define BANG_HISTORY if you want to have Csh style "!" history expansion. - This is unrelated to READLINE. */ -/* #define BANG_HISTORY */ - -/* Define HISTORY if you want to have access to previously typed commands. - - If both HISTORY and READLINE are defined, you can get at the commands - with line editing commands, and you can directly manipulate the history - from the command line. - - If only HISTORY is defined, the `fc' and `history' builtins are - available. */ -/* #define HISTORY */ - -#if defined (BANG_HISTORY) && !defined (HISTORY) - /* BANG_HISTORY requires HISTORY. */ -# define HISTORY -#endif /* BANG_HISTORY && !HISTORY */ - -#if defined (READLINE) && !defined (HISTORY) -# define HISTORY -#endif - -/* The default value of the PATH variable. */ -#define DEFAULT_PATH_VALUE \ - "/usr/gnu/bin:/usr/local/bin:/usr/ucb:/bin:/usr/bin:." - -/* The value for PATH when invoking `command -p'. This is only used when - the Posix.2 confstr () function, or CS_PATH define are not present. */ -#define STANDARD_UTILS_PATH \ - "/bin:/usr/bin:/usr/ucb:/usr/sbin:/sbin:/etc:/usr/etc:/usr/lib" - -/* Put system-specific default mail directories here. */ -#if defined (__bsdi__) || defined (__FreeBSD__) || defined (__NetBSD__) -# define DEFAULT_MAIL_PATH "/var/mail/" -#endif - -#if !defined (DEFAULT_MAIL_PATH) -#if defined (USG) -# define DEFAULT_MAIL_PATH "/usr/mail/" -#else -# define DEFAULT_MAIL_PATH "/usr/spool/mail/" -#endif -#endif - -/* Define V9_ECHO if you want to give the echo builtin backslash-escape - interpretation using the -e option, in the style of the Bell Labs 9th - Edition version of echo. */ -#define V9_ECHO - -/* Define DEFAULT_ECHO_TO_USG if you want the echo builtin to interpret - the backslash-escape characters by default, like the System V echo. - This requires that V9_ECHO be defined. */ -/* #define DEFAULT_ECHO_TO_USG */ -#if !defined (V9_ECHO) -# undef DEFAULT_ECHO_TO_USG -#endif - -/* Define CONTINUE_AFTER_KILL_ERROR if you want the kill command to - continue processing arguments after one of them fails. */ -#define CONTINUE_AFTER_KILL_ERROR - -/* Define BREAK_COMPLAINS if you want the non-standard, but useful - error messages about `break' and `continue' out of context. */ -#define BREAK_COMPLAINS - -/* Define GETOPTS_BUILTIN if you want the Posix.2 `getopts' shell builtin - compiled into the shell. */ -#define GETOPTS_BUILTIN - -/* When ALLOW_RIGID_POSIX_COMPLIANCE is defined, you can turn on strictly - Posix compliant behaviour by setting the environment variable - POSIXLY_CORRECT. */ -#define ALLOW_RIGID_POSIX_COMPLIANCE - -/* Define RESTRICTED_SHELL if you want the generated shell to have the - ability to be a restricted one. The shell thus generated can become - restricted by being run with the name "rbash", or by setting the -r - flag. */ -/* #define RESTRICTED_SHELL */ - -/* Define DISABLED_BUILTINS if you want "builtin foo" to always run the - shell builtin "foo", even if it has been disabled with "enable -n foo". */ -/* #define DISABLED_BUILTINS */ - -/* Define PROCESS_SUBSTITUTION if you want the K*rn shell-like process - substitution features "<(file)". */ -/* Right now, you cannot do this on machines without fully operational - FIFO support. This currently include NeXT and Alliant. */ -#if !defined (MKFIFO_MISSING) -# define PROCESS_SUBSTITUTION -#endif /* !MKFIFO_MISSING */ - -/* Define PROMPT_STRING_DECODE if you want the backslash-escaped special - characters in PS1 and PS2 expanded. Variable expansion will still be - performed. */ -/* #define PROMPT_STRING_DECODE */ - -/* Define BUFFERED_INPUT if you want the shell to do its own input - buffering. */ -#define BUFFERED_INPUT - -/* Define INTERACTIVE_COMMENTS if you want # comments to work by default - when the shell is interactive, as Posix.2a specifies. */ -#define INTERACTIVE_COMMENTS - -/* Define ONESHOT if you want sh -c 'command' to avoid forking to execute - `command' whenever possible. */ -#define ONESHOT - -/* Default primary and secondary prompt strings. */ -#define PPROMPT "bash\\$ " -#define SPROMPT "> " - -/* Define SELECT_COMMAND if you want the Korn-shell style `select' command: - select word in word_list; do command_list; done */ -/* #define SELECT_COMMAND */ - -#endif /* !_CONFIG_H_ */ diff --git a/config.h.top b/config.h.top new file mode 100644 index 0000000..491a49f --- /dev/null +++ b/config.h.top @@ -0,0 +1,51 @@ +/* config.h.top */ + +/* This contains various user-settable options not under the control of + autoconf. */ + +/* Define CONTINUE_AFTER_KILL_ERROR if you want the kill command to + continue processing arguments after one of them fails. This is + what POSIX.2 specifies. */ +#define CONTINUE_AFTER_KILL_ERROR + +/* Define BREAK_COMPLAINS if you want the non-standard, but useful + error messages about `break' and `continue' out of context. */ +#define BREAK_COMPLAINS + +/* Define BUFFERED_INPUT if you want the shell to do its own input + buffering, rather than using stdio. Do not undefine this; it's + required to preserve semantics required by POSIX. */ +#define BUFFERED_INPUT + +/* Define ONESHOT if you want sh -c 'command' to avoid forking to execute + `command' whenever possible. This is a big efficiency improvement. */ +#define ONESHOT + +/* Define V9_ECHO if you want to give the echo builtin backslash-escape + interpretation using the -e option, in the style of the Bell Labs 9th + Edition version of echo. You cannot emulate the System V echo behavior + without this option. */ +#define V9_ECHO + +/* The default value of the PATH variable. */ +#ifndef DEFAULT_PATH_VALUE +#define DEFAULT_PATH_VALUE \ + "/usr/gnu/bin:/usr/local/bin:/usr/ucb:/bin:/usr/bin:." +#endif + +/* The value for PATH when invoking `command -p'. This is only used when + the Posix.2 confstr () function, or CS_PATH define are not present. */ +#ifndef STANDARD_UTILS_PATH +#define STANDARD_UTILS_PATH \ + "/bin:/usr/bin:/usr/ucb:/sbin:/usr/sbin:/etc:/usr/etc" +#endif + +/* Default primary and secondary prompt strings. */ +#define PPROMPT "\\s-\\v\\$ " +#define SPROMPT "> " + +/* System-wide .bashrc file for interactive shells. */ +/* #define SYS_BASHRC "/etc/bash.bashrc" */ + +/* System-wide .bash_logout for login shells. */ +/* #define SYS_BASH_LOGOUT "/etc/bash.bash_logout" */ diff --git a/configure b/configure index 53e10b6..463c027 100755 --- a/configure +++ b/configure @@ -1,8 +1,6271 @@ -#!/bin/sh +#! /bin/sh + +# From configure.in for Bash 2.0, version 1.14, from autoconf version 2.12 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +# Guess values for system-dependent variables and create Makefiles. +# Generated automatically using autoconf version 2.12 +# Copyright (C) 1992, 93, 94, 95, 96 Free Software Foundation, Inc. # -# This shell script does nothing since Bash doesn't require -# configuration to be forced on it; it auto-configures. You can -# change the location of the source directory with +srcdir. +# This configure script is free software; the Free Software Foundation +# gives unlimited permission to copy, distribute and modify it. + +# Defaults: +ac_help= +ac_default_prefix=/usr/local +# Any additions from configure.in: +ac_help="$ac_help +--with-gnu-malloc use the GNU version of malloc" +ac_help="$ac_help +--with-glibc-malloc use the GNU C library version of malloc" +ac_help="$ac_help +--with-purify configure to postprocess with purify" +ac_help="$ac_help +--with-afs if you are running AFS" +ac_help="$ac_help +--enable-minimal-config a minimal sh-like configuration" +ac_help="$ac_help +--enable-job-control enable job control features" +ac_help="$ac_help +--enable-alias enable shell aliases" +ac_help="$ac_help +--enable-readline turn on command line editing" +ac_help="$ac_help +--enable-history turn on command history" +ac_help="$ac_help +--enable-bang-history turn on csh-style history substitution" +ac_help="$ac_help +--enable-directory-stack enable builtins pushd/popd/dirs" +ac_help="$ac_help +--enable-restricted enable a restricted shell" +ac_help="$ac_help +--enable-process-substitution enable process substitution" +ac_help="$ac_help +--enable-prompt-string-decoding turn on escape character decoding in prompts" +ac_help="$ac_help +--enable-select include select command" +ac_help="$ac_help +--enable-help-builtin include the help builtin" +ac_help="$ac_help +--enable-array-variables include shell array variables" +ac_help="$ac_help +--enable-dparen-arithmetic include ((...)) command" +ac_help="$ac_help +--enable-brace-expansion include brace expansion" +ac_help="$ac_help +--enable-disabled-builtins allow disabled builtins to still be invoked" +ac_help="$ac_help +--enable-command-timing enable the time reserved word and command timing" +ac_help="$ac_help +--enable-usg-echo-default make the echo builtin expand escape sequences by default" + +# Initialize some variables set by options. +# The variables have the same names as the options, with +# dashes changed to underlines. +build=NONE +cache_file=./config.cache +exec_prefix=NONE +host=NONE +no_create= +nonopt=NONE +no_recursion= +prefix=NONE +program_prefix=NONE +program_suffix=NONE +program_transform_name=s,x,x, +silent= +site= +srcdir= +target=NONE +verbose= +x_includes=NONE +x_libraries=NONE +bindir='${exec_prefix}/bin' +sbindir='${exec_prefix}/sbin' +libexecdir='${exec_prefix}/libexec' +datadir='${prefix}/share' +sysconfdir='${prefix}/etc' +sharedstatedir='${prefix}/com' +localstatedir='${prefix}/var' +libdir='${exec_prefix}/lib' +includedir='${prefix}/include' +oldincludedir='/usr/include' +infodir='${prefix}/info' +mandir='${prefix}/man' + +# Initialize some other variables. +subdirs= +MFLAGS= MAKEFLAGS= +# Maximum number of lines to put in a shell here document. +ac_max_here_lines=12 + +ac_prev= +for ac_option +do + + # If the previous option needs an argument, assign it. + if test -n "$ac_prev"; then + eval "$ac_prev=\$ac_option" + ac_prev= + continue + fi + + case "$ac_option" in + -*=*) ac_optarg=`echo "$ac_option" | sed 's/[-_a-zA-Z0-9]*=//'` ;; + *) ac_optarg= ;; + esac + + # Accept the important Cygnus configure options, so we can diagnose typos. + + case "$ac_option" in + + -bindir | --bindir | --bindi | --bind | --bin | --bi) + ac_prev=bindir ;; + -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) + bindir="$ac_optarg" ;; + + -build | --build | --buil | --bui | --bu) + ac_prev=build ;; + -build=* | --build=* | --buil=* | --bui=* | --bu=*) + build="$ac_optarg" ;; + + -cache-file | --cache-file | --cache-fil | --cache-fi \ + | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) + ac_prev=cache_file ;; + -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ + | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) + cache_file="$ac_optarg" ;; + + -datadir | --datadir | --datadi | --datad | --data | --dat | --da) + ac_prev=datadir ;; + -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \ + | --da=*) + datadir="$ac_optarg" ;; + + -disable-* | --disable-*) + ac_feature=`echo $ac_option|sed -e 's/-*disable-//'` + # Reject names that are not valid shell variable names. + if test -n "`echo $ac_feature| sed 's/[-a-zA-Z0-9_]//g'`"; then + { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; } + fi + ac_feature=`echo $ac_feature| sed 's/-/_/g'` + eval "enable_${ac_feature}=no" ;; + + -enable-* | --enable-*) + ac_feature=`echo $ac_option|sed -e 's/-*enable-//' -e 's/=.*//'` + # Reject names that are not valid shell variable names. + if test -n "`echo $ac_feature| sed 's/[-_a-zA-Z0-9]//g'`"; then + { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; } + fi + ac_feature=`echo $ac_feature| sed 's/-/_/g'` + case "$ac_option" in + *=*) ;; + *) ac_optarg=yes ;; + esac + eval "enable_${ac_feature}='$ac_optarg'" ;; + + -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ + | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ + | --exec | --exe | --ex) + ac_prev=exec_prefix ;; + -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ + | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ + | --exec=* | --exe=* | --ex=*) + exec_prefix="$ac_optarg" ;; + + -gas | --gas | --ga | --g) + # Obsolete; use --with-gas. + with_gas=yes ;; + + -help | --help | --hel | --he) + # Omit some internal or obsolete options to make the list less imposing. + # This message is too long to be a string in the A/UX 3.1 sh. + cat << EOF +Usage: configure [options] [host] +Options: [defaults in brackets after descriptions] +Configuration: + --cache-file=FILE cache test results in FILE + --help print this message + --no-create do not create output files + --quiet, --silent do not print \`checking...' messages + --version print the version of autoconf that created configure +Directory and file names: + --prefix=PREFIX install architecture-independent files in PREFIX + [$ac_default_prefix] + --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX + [same as prefix] + --bindir=DIR user executables in DIR [EPREFIX/bin] + --sbindir=DIR system admin executables in DIR [EPREFIX/sbin] + --libexecdir=DIR program executables in DIR [EPREFIX/libexec] + --datadir=DIR read-only architecture-independent data in DIR + [PREFIX/share] + --sysconfdir=DIR read-only single-machine data in DIR [PREFIX/etc] + --sharedstatedir=DIR modifiable architecture-independent data in DIR + [PREFIX/com] + --localstatedir=DIR modifiable single-machine data in DIR [PREFIX/var] + --libdir=DIR object code libraries in DIR [EPREFIX/lib] + --includedir=DIR C header files in DIR [PREFIX/include] + --oldincludedir=DIR C header files for non-gcc in DIR [/usr/include] + --infodir=DIR info documentation in DIR [PREFIX/info] + --mandir=DIR man documentation in DIR [PREFIX/man] + --srcdir=DIR find the sources in DIR [configure dir or ..] + --program-prefix=PREFIX prepend PREFIX to installed program names + --program-suffix=SUFFIX append SUFFIX to installed program names + --program-transform-name=PROGRAM + run sed PROGRAM on installed program names +EOF + cat << EOF +Host type: + --build=BUILD configure for building on BUILD [BUILD=HOST] + --host=HOST configure for HOST [guessed] + --target=TARGET configure for TARGET [TARGET=HOST] +Features and packages: + --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) + --enable-FEATURE[=ARG] include FEATURE [ARG=yes] + --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] + --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) + --x-includes=DIR X include files are in DIR + --x-libraries=DIR X library files are in DIR +EOF + if test -n "$ac_help"; then + echo "--enable and --with options recognized:$ac_help" + fi + exit 0 ;; + + -host | --host | --hos | --ho) + ac_prev=host ;; + -host=* | --host=* | --hos=* | --ho=*) + host="$ac_optarg" ;; + + -includedir | --includedir | --includedi | --included | --include \ + | --includ | --inclu | --incl | --inc) + ac_prev=includedir ;; + -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ + | --includ=* | --inclu=* | --incl=* | --inc=*) + includedir="$ac_optarg" ;; + + -infodir | --infodir | --infodi | --infod | --info | --inf) + ac_prev=infodir ;; + -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) + infodir="$ac_optarg" ;; + + -libdir | --libdir | --libdi | --libd) + ac_prev=libdir ;; + -libdir=* | --libdir=* | --libdi=* | --libd=*) + libdir="$ac_optarg" ;; + + -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ + | --libexe | --libex | --libe) + ac_prev=libexecdir ;; + -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ + | --libexe=* | --libex=* | --libe=*) + libexecdir="$ac_optarg" ;; + + -localstatedir | --localstatedir | --localstatedi | --localstated \ + | --localstate | --localstat | --localsta | --localst \ + | --locals | --local | --loca | --loc | --lo) + ac_prev=localstatedir ;; + -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ + | --localstate=* | --localstat=* | --localsta=* | --localst=* \ + | --locals=* | --local=* | --loca=* | --loc=* | --lo=*) + localstatedir="$ac_optarg" ;; + + -mandir | --mandir | --mandi | --mand | --man | --ma | --m) + ac_prev=mandir ;; + -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) + mandir="$ac_optarg" ;; + + -nfp | --nfp | --nf) + # Obsolete; use --without-fp. + with_fp=no ;; + + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c) + no_create=yes ;; + + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) + no_recursion=yes ;; + + -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ + | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ + | --oldin | --oldi | --old | --ol | --o) + ac_prev=oldincludedir ;; + -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ + | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ + | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) + oldincludedir="$ac_optarg" ;; + + -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) + ac_prev=prefix ;; + -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) + prefix="$ac_optarg" ;; + + -program-prefix | --program-prefix | --program-prefi | --program-pref \ + | --program-pre | --program-pr | --program-p) + ac_prev=program_prefix ;; + -program-prefix=* | --program-prefix=* | --program-prefi=* \ + | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) + program_prefix="$ac_optarg" ;; + + -program-suffix | --program-suffix | --program-suffi | --program-suff \ + | --program-suf | --program-su | --program-s) + ac_prev=program_suffix ;; + -program-suffix=* | --program-suffix=* | --program-suffi=* \ + | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) + program_suffix="$ac_optarg" ;; + + -program-transform-name | --program-transform-name \ + | --program-transform-nam | --program-transform-na \ + | --program-transform-n | --program-transform- \ + | --program-transform | --program-transfor \ + | --program-transfo | --program-transf \ + | --program-trans | --program-tran \ + | --progr-tra | --program-tr | --program-t) + ac_prev=program_transform_name ;; + -program-transform-name=* | --program-transform-name=* \ + | --program-transform-nam=* | --program-transform-na=* \ + | --program-transform-n=* | --program-transform-=* \ + | --program-transform=* | --program-transfor=* \ + | --program-transfo=* | --program-transf=* \ + | --program-trans=* | --program-tran=* \ + | --progr-tra=* | --program-tr=* | --program-t=*) + program_transform_name="$ac_optarg" ;; + + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + silent=yes ;; + + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) + ac_prev=sbindir ;; + -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ + | --sbi=* | --sb=*) + sbindir="$ac_optarg" ;; + + -sharedstatedir | --sharedstatedir | --sharedstatedi \ + | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ + | --sharedst | --shareds | --shared | --share | --shar \ + | --sha | --sh) + ac_prev=sharedstatedir ;; + -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ + | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ + | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ + | --sha=* | --sh=*) + sharedstatedir="$ac_optarg" ;; + + -site | --site | --sit) + ac_prev=site ;; + -site=* | --site=* | --sit=*) + site="$ac_optarg" ;; + + -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) + ac_prev=srcdir ;; + -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) + srcdir="$ac_optarg" ;; + + -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ + | --syscon | --sysco | --sysc | --sys | --sy) + ac_prev=sysconfdir ;; + -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ + | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) + sysconfdir="$ac_optarg" ;; + + -target | --target | --targe | --targ | --tar | --ta | --t) + ac_prev=target ;; + -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) + target="$ac_optarg" ;; + + -v | -verbose | --verbose | --verbos | --verbo | --verb) + verbose=yes ;; + + -version | --version | --versio | --versi | --vers) + echo "configure generated by autoconf version 2.12" + exit 0 ;; + + -with-* | --with-*) + ac_package=`echo $ac_option|sed -e 's/-*with-//' -e 's/=.*//'` + # Reject names that are not valid shell variable names. + if test -n "`echo $ac_package| sed 's/[-_a-zA-Z0-9]//g'`"; then + { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; } + fi + ac_package=`echo $ac_package| sed 's/-/_/g'` + case "$ac_option" in + *=*) ;; + *) ac_optarg=yes ;; + esac + eval "with_${ac_package}='$ac_optarg'" ;; + + -without-* | --without-*) + ac_package=`echo $ac_option|sed -e 's/-*without-//'` + # Reject names that are not valid shell variable names. + if test -n "`echo $ac_package| sed 's/[-a-zA-Z0-9_]//g'`"; then + { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; } + fi + ac_package=`echo $ac_package| sed 's/-/_/g'` + eval "with_${ac_package}=no" ;; + + --x) + # Obsolete; use --with-x. + with_x=yes ;; + + -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ + | --x-incl | --x-inc | --x-in | --x-i) + ac_prev=x_includes ;; + -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ + | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) + x_includes="$ac_optarg" ;; + + -x-libraries | --x-libraries | --x-librarie | --x-librari \ + | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) + ac_prev=x_libraries ;; + -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ + | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) + x_libraries="$ac_optarg" ;; + + -*) { echo "configure: error: $ac_option: invalid option; use --help to show usage" 1>&2; exit 1; } + ;; + + *) + if test -n "`echo $ac_option| sed 's/[-a-z0-9.]//g'`"; then + echo "configure: warning: $ac_option: invalid host type" 1>&2 + fi + if test "x$nonopt" != xNONE; then + { echo "configure: error: can only configure for one host and one target at a time" 1>&2; exit 1; } + fi + nonopt="$ac_option" + ;; + + esac +done + +if test -n "$ac_prev"; then + { echo "configure: error: missing argument to --`echo $ac_prev | sed 's/_/-/g'`" 1>&2; exit 1; } +fi + +trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15 + +# File descriptor usage: +# 0 standard input +# 1 file creation +# 2 errors and warnings +# 3 some systems may open it to /dev/tty +# 4 used on the Kubota Titan +# 6 checking for... messages and results +# 5 compiler messages saved in config.log +if test "$silent" = yes; then + exec 6>/dev/null +else + exec 6>&1 +fi +exec 5>./config.log + +echo "\ +This file contains any messages produced by compilers while +running configure, to aid debugging if configure makes a mistake. +" 1>&5 + +# Strip out --no-create and --no-recursion so they do not pile up. +# Also quote any args containing shell metacharacters. +ac_configure_args= +for ac_arg +do + case "$ac_arg" in + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c) ;; + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) ;; + *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?]*) + ac_configure_args="$ac_configure_args '$ac_arg'" ;; + *) ac_configure_args="$ac_configure_args $ac_arg" ;; + esac +done + +# NLS nuisances. +# Only set these to C if already set. These must not be set unconditionally +# because not all systems understand e.g. LANG=C (notably SCO). +# Fixing LC_MESSAGES prevents Solaris sh from translating var values in `set'! +# Non-C LC_CTYPE values break the ctype check. +if test "${LANG+set}" = set; then LANG=C; export LANG; fi +if test "${LC_ALL+set}" = set; then LC_ALL=C; export LC_ALL; fi +if test "${LC_MESSAGES+set}" = set; then LC_MESSAGES=C; export LC_MESSAGES; fi +if test "${LC_CTYPE+set}" = set; then LC_CTYPE=C; export LC_CTYPE; fi + +# confdefs.h avoids OS command line length limits that DEFS can exceed. +rm -rf conftest* confdefs.h +# AIX cpp loses on an empty file, so make sure it contains at least a newline. +echo > confdefs.h + +# A filename unique to this package, relative to the directory that +# configure is in, which we can look for to find out if srcdir is correct. +ac_unique_file=shell.h + +# Find the source files, if location was not specified. +if test -z "$srcdir"; then + ac_srcdir_defaulted=yes + # Try the directory containing this script, then its parent. + ac_prog=$0 + ac_confdir=`echo $ac_prog|sed 's%/[^/][^/]*$%%'` + test "x$ac_confdir" = "x$ac_prog" && ac_confdir=. + srcdir=$ac_confdir + if test ! -r $srcdir/$ac_unique_file; then + srcdir=.. + fi +else + ac_srcdir_defaulted=no +fi +if test ! -r $srcdir/$ac_unique_file; then + if test "$ac_srcdir_defaulted" = yes; then + { echo "configure: error: can not find sources in $ac_confdir or .." 1>&2; exit 1; } + else + { echo "configure: error: can not find sources in $srcdir" 1>&2; exit 1; } + fi +fi +srcdir=`echo "${srcdir}" | sed 's%\([^/]\)/*$%\1%'` + +# Prefer explicitly selected file to automatically selected ones. +if test -z "$CONFIG_SITE"; then + if test "x$prefix" != xNONE; then + CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site" + else + CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site" + fi +fi +for ac_site_file in $CONFIG_SITE; do + if test -r "$ac_site_file"; then + echo "loading site script $ac_site_file" + . "$ac_site_file" + fi +done + +if test -r "$cache_file"; then + echo "loading cache $cache_file" + . $cache_file +else + echo "creating cache $cache_file" + > $cache_file +fi + +ac_ext=c +# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CPP $CPPFLAGS' +ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CC-cc} -o conftest $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cc_cross + +if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null; then + # Stardent Vistra SVR4 grep lacks -e, says ghazi@caip.rutgers.edu. + if (echo -n testing; echo 1,2,3) | sed s/-n/xn/ | grep xn >/dev/null; then + ac_n= ac_c=' +' ac_t=' ' + else + ac_n=-n ac_c= ac_t= + fi +else + ac_n= ac_c='\c' ac_t= +fi + + + + + + +ac_aux_dir= +for ac_dir in ./support $srcdir/./support; do + if test -f $ac_dir/install-sh; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install-sh -c" + break + elif test -f $ac_dir/install.sh; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install.sh -c" + break + fi +done +if test -z "$ac_aux_dir"; then + { echo "configure: error: can not find install-sh or install.sh in ./support $srcdir/./support" 1>&2; exit 1; } +fi +ac_config_guess=$ac_aux_dir/config.guess +ac_config_sub=$ac_aux_dir/config.sub +ac_configure=$ac_aux_dir/configure # This should be Cygnus configure. + + + +# Make sure we can run config.sub. +if $ac_config_sub sun4 >/dev/null 2>&1; then : +else { echo "configure: error: can not run $ac_config_sub" 1>&2; exit 1; } +fi + +echo $ac_n "checking host system type""... $ac_c" 1>&6 +echo "configure:665: checking host system type" >&5 + +host_alias=$host +case "$host_alias" in +NONE) + case $nonopt in + NONE) + if host_alias=`$ac_config_guess`; then : + else { echo "configure: error: can not guess host type; you must specify one" 1>&2; exit 1; } + fi ;; + *) host_alias=$nonopt ;; + esac ;; +esac + +host=`$ac_config_sub $host_alias` +host_cpu=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'` +host_vendor=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'` +host_os=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'` +echo "$ac_t""$host" 1>&6 + + +opt_gnu_malloc=yes +opt_glibc_malloc=no +opt_purify=no +opt_afs=no + +case "${host_cpu}-${host_os}" in +alpha-*) opt_gnu_malloc=no ;; # alpha running osf/1 or linux +*cray*-*) opt_gnu_malloc=no ;; # Crays +*-osf1*) opt_gnu_malloc=no ;; # other osf/1 machines +sparc-svr4*) opt_gnu_malloc=no ;; # sparc SVR4, SVR4.2 +sparc-netbsd*) opt_gnu_malloc=no ;; # needs 8-byte alignment +sparc-linux*) opt_gnu_malloc=no ;; # sparc running linux; requires ELF +*-aix*) opt_gnu_malloc=no ;; # AIX machines +*-nextstep*) opt_gnu_malloc=no ;; # NeXT machines running NeXTstep +*-dgux*) opt_gnu_malloc=no ;; # DG/UX machines +*-qnx) opt_gnu_malloc=no ;; # QNX 4.2 +*-bsdi2.1) opt_gnu_malloc=no ; : ${CC:=shlicc2} ;; # for loadable builtins +esac + +# Check whether --with-gnu-malloc or --without-gnu-malloc was given. +if test "${with_gnu_malloc+set}" = set; then + withval="$with_gnu_malloc" + opt_gnu_malloc=$withval +fi + +# Check whether --with-glibc-malloc or --without-glibc-malloc was given. +if test "${with_glibc_malloc+set}" = set; then + withval="$with_glibc_malloc" + opt_glibc_malloc=$withval +fi + +# Check whether --with-purify or --without-purify was given. +if test "${with_purify+set}" = set; then + withval="$with_purify" + opt_purify=$withval +fi + +# Check whether --with-afs or --without-afs was given. +if test "${with_afs+set}" = set; then + withval="$with_afs" + opt_afs=$withval +fi + + +if test "$opt_glibc_malloc" = yes; then + MALLOC=gmalloc.o MALLOC_SRC='$(ALLOC_LIBSRC)/gmalloc.c' +elif test "$opt_gnu_malloc" = yes; then + MALLOC=malloc.o MALLOC_SRC='$(ALLOC_LIBSRC)/malloc.c' +else + MALLOC= MALLOC_SRC= +fi + +if test "$opt_purify" = yes; then + PURIFY=purify +else + PURIFY= +fi + +if test "$opt_afs" = yes; then + cat >> confdefs.h <<\EOF +#define AFS 1 +EOF + +fi + +opt_minimal_config=no + +opt_job_control=yes +opt_alias=yes +opt_readline=yes +opt_history=yes +opt_bang_history=yes +opt_dirstack=yes +opt_restricted=yes +opt_process_subst=yes +opt_prompt_decoding=yes +opt_select=yes +opt_help=yes +opt_array_variables=yes +opt_dparen_arith=yes +opt_brace_expansion=yes +opt_disabled_builtins=no +opt_command_timing=yes +opt_usg_echo=no + +# Check whether --enable-minimal-config or --disable-minimal-config was given. +if test "${enable_minimal_config+set}" = set; then + enableval="$enable_minimal_config" + opt_minimal_config=$enableval +fi + + +if test $opt_minimal_config = yes; then + opt_job_control=no opt_alias=no opt_readline=no + opt_history=no opt_bang_history=no opt_dirstack=no + opt_restricted=no opt_process_subst=no opt_prompt_decoding=no + opt_select=no opt_help=no opt_array_variables=no opt_dparen_arith=no + opt_brace_expansion=no opt_disabled_builtins=no opt_command_timing=no +fi + +# Check whether --enable-job-control or --disable-job-control was given. +if test "${enable_job_control+set}" = set; then + enableval="$enable_job_control" + opt_job_control=$enableval +fi + +# Check whether --enable-alias or --disable-alias was given. +if test "${enable_alias+set}" = set; then + enableval="$enable_alias" + opt_alias=$enableval +fi + +# Check whether --enable-readline or --disable-readline was given. +if test "${enable_readline+set}" = set; then + enableval="$enable_readline" + opt_readline=$enableval +fi + +# Check whether --enable-history or --disable-history was given. +if test "${enable_history+set}" = set; then + enableval="$enable_history" + opt_history=$enableval +fi + +# Check whether --enable-bang-history or --disable-bang-history was given. +if test "${enable_bang_history+set}" = set; then + enableval="$enable_bang_history" + opt_bang_history=$enableval +fi + +# Check whether --enable-directory-stack or --disable-directory-stack was given. +if test "${enable_directory_stack+set}" = set; then + enableval="$enable_directory_stack" + opt_dirstack=$enableval +fi + +# Check whether --enable-restricted or --disable-restricted was given. +if test "${enable_restricted+set}" = set; then + enableval="$enable_restricted" + opt_restricted=$enableval +fi + +# Check whether --enable-process-substitution or --disable-process-substitution was given. +if test "${enable_process_substitution+set}" = set; then + enableval="$enable_process_substitution" + opt_process_subst=$enableval +fi + +# Check whether --enable-prompt-string-decoding or --disable-prompt-string-decoding was given. +if test "${enable_prompt_string_decoding+set}" = set; then + enableval="$enable_prompt_string_decoding" + opt_prompt_decoding=$enableval +fi + +# Check whether --enable-select or --disable-select was given. +if test "${enable_select+set}" = set; then + enableval="$enable_select" + opt_select=$enableval +fi + +# Check whether --enable-help-builtin or --disable-help-builtin was given. +if test "${enable_help_builtin+set}" = set; then + enableval="$enable_help_builtin" + opt_help=$enableval +fi + +# Check whether --enable-array-variables or --disable-array-variables was given. +if test "${enable_array_variables+set}" = set; then + enableval="$enable_array_variables" + opt_array_variables=$enableval +fi + +# Check whether --enable-dparen-arithmetic or --disable-dparen-arithmetic was given. +if test "${enable_dparen_arithmetic+set}" = set; then + enableval="$enable_dparen_arithmetic" + opt_dparen_arith=$enableval +fi + +# Check whether --enable-brace-expansion or --disable-brace-expansion was given. +if test "${enable_brace_expansion+set}" = set; then + enableval="$enable_brace_expansion" + opt_brace_expansion=$enableval +fi + +# Check whether --enable-disabled-builtins or --disable-disabled-builtins was given. +if test "${enable_disabled_builtins+set}" = set; then + enableval="$enable_disabled_builtins" + opt_disabled_builtins=$enableval +fi + +# Check whether --enable-command-timing or --disable-command-timing was given. +if test "${enable_command_timing+set}" = set; then + enableval="$enable_command_timing" + opt_command_timing=$enableval +fi + +# Check whether --enable-usg-echo-default or --disable-usg-echo-default was given. +if test "${enable_usg_echo_default+set}" = set; then + enableval="$enable_usg_echo_default" + opt_usg_echo=$enableval +fi + + + +if test $opt_alias = yes; then +cat >> confdefs.h <<\EOF +#define ALIAS 1 +EOF + +fi +if test $opt_readline = yes; then +cat >> confdefs.h <<\EOF +#define READLINE 1 +EOF + +READLINE_LIB=-lreadline +READLINE_DEP='$(READLINE_LIBRARY)' +else +READLINE_LIB= READLINE_DEP= +fi +if test $opt_history = yes; then +cat >> confdefs.h <<\EOF +#define HISTORY 1 +EOF + +HISTORY_LIB=-lhistory +HISTORY_DEP='$(HISTORY_LIBRARY)' +else +HISTORY_LIB= HISTORY_DEP= +fi +if test $opt_bang_history = yes; then +cat >> confdefs.h <<\EOF +#define BANG_HISTORY 1 +EOF + +HISTORY_LIB=-lhistory +HISTORY_DEP='$(HISTORY_LIBRARY)' +else +HISTORY_LIB= HISTORY_DEP= +fi +if test $opt_dirstack = yes; then +cat >> confdefs.h <<\EOF +#define PUSHD_AND_POPD 1 +EOF + +fi +if test $opt_restricted = yes; then +cat >> confdefs.h <<\EOF +#define RESTRICTED_SHELL 1 +EOF + +fi +if test $opt_process_subst = yes; then +cat >> confdefs.h <<\EOF +#define PROCESS_SUBSTITUTION 1 +EOF + +fi +if test $opt_prompt_decoding = yes; then +cat >> confdefs.h <<\EOF +#define PROMPT_STRING_DECODE 1 +EOF + +fi +if test $opt_select = yes; then +cat >> confdefs.h <<\EOF +#define SELECT_COMMAND 1 +EOF + +fi +if test $opt_help = yes; then +cat >> confdefs.h <<\EOF +#define HELP_BUILTIN 1 +EOF + +fi +if test $opt_array_variables = yes; then +cat >> confdefs.h <<\EOF +#define ARRAY_VARS 1 +EOF + +fi +if test $opt_dparen_arith = yes; then +cat >> confdefs.h <<\EOF +#define DPAREN_ARITHMETIC 1 +EOF + +fi +if test $opt_brace_expansion = yes; then +cat >> confdefs.h <<\EOF +#define BRACE_EXPANSION 1 +EOF + +fi +if test $opt_disabled_builtins = yes; then +cat >> confdefs.h <<\EOF +#define DISABLED_BUILTINS 1 +EOF + +fi +if test $opt_command_timing = yes; then +cat >> confdefs.h <<\EOF +#define COMMAND_TIMING 1 +EOF + +fi +if test $opt_usg_echo = yes ; then +cat >> confdefs.h <<\EOF +#define DEFAULT_ECHO_TO_USG 1 +EOF + +fi + + + + + + + + + +echo "Beginning configuration for bash-2.0" + +# Extract the first word of "gcc", so it can be a program name with args. +set dummy gcc; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:1012: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:" + for ac_dir in $PATH; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_CC="gcc" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +CC="$ac_cv_prog_CC" +if test -n "$CC"; then + echo "$ac_t""$CC" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +if test -z "$CC"; then + # Extract the first word of "cc", so it can be a program name with args. +set dummy cc; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:1041: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:" + ac_prog_rejected=no + for ac_dir in $PATH; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + if test "$ac_dir/$ac_word" = "/usr/ucb/cc"; then + ac_prog_rejected=yes + continue + fi + ac_cv_prog_CC="cc" + break + fi + done + IFS="$ac_save_ifs" +if test $ac_prog_rejected = yes; then + # We found a bogon in the path, so make sure we never use it. + set dummy $ac_cv_prog_CC + shift + if test $# -gt 0; then + # We chose a different compiler from the bogus one. + # However, it has the same basename, so the bogon will be chosen + # first if we set CC to just the basename; use the full file name. + shift + set dummy "$ac_dir/$ac_word" "$@" + shift + ac_cv_prog_CC="$@" + fi +fi +fi +fi +CC="$ac_cv_prog_CC" +if test -n "$CC"; then + echo "$ac_t""$CC" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + + test -z "$CC" && { echo "configure: error: no acceptable cc found in \$PATH" 1>&2; exit 1; } +fi + +echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works""... $ac_c" 1>&6 +echo "configure:1089: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works" >&5 + +ac_ext=c +# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CPP $CPPFLAGS' +ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CC-cc} -o conftest $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cc_cross + +cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest; then + ac_cv_prog_cc_works=yes + # If we can't run a trivial program, we are probably using a cross compiler. + if (./conftest; exit) 2>/dev/null; then + ac_cv_prog_cc_cross=no + else + ac_cv_prog_cc_cross=yes + fi +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + ac_cv_prog_cc_works=no +fi +rm -fr conftest* + +echo "$ac_t""$ac_cv_prog_cc_works" 1>&6 +if test $ac_cv_prog_cc_works = no; then + { echo "configure: error: installation or configuration problem: C compiler cannot create executables." 1>&2; exit 1; } +fi +echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler""... $ac_c" 1>&6 +echo "configure:1123: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler" >&5 +echo "$ac_t""$ac_cv_prog_cc_cross" 1>&6 +cross_compiling=$ac_cv_prog_cc_cross + +echo $ac_n "checking whether we are using GNU C""... $ac_c" 1>&6 +echo "configure:1128: checking whether we are using GNU C" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_gcc'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.c <&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then + ac_cv_prog_gcc=yes +else + ac_cv_prog_gcc=no +fi +fi + +echo "$ac_t""$ac_cv_prog_gcc" 1>&6 + +if test $ac_cv_prog_gcc = yes; then + GCC=yes + ac_test_CFLAGS="${CFLAGS+set}" + ac_save_CFLAGS="$CFLAGS" + CFLAGS= + echo $ac_n "checking whether ${CC-cc} accepts -g""... $ac_c" 1>&6 +echo "configure:1152: checking whether ${CC-cc} accepts -g" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_cc_g'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + echo 'void f(){}' > conftest.c +if test -z "`${CC-cc} -g -c conftest.c 2>&1`"; then + ac_cv_prog_cc_g=yes +else + ac_cv_prog_cc_g=no +fi +rm -f conftest* + +fi + +echo "$ac_t""$ac_cv_prog_cc_g" 1>&6 + if test "$ac_test_CFLAGS" = set; then + CFLAGS="$ac_save_CFLAGS" + elif test $ac_cv_prog_cc_g = yes; then + CFLAGS="-g -O2" + else + CFLAGS="-O2" + fi +else + GCC= + test "${CFLAGS+set}" = set || CFLAGS="-g" +fi + +echo $ac_n "checking for POSIXized ISC""... $ac_c" 1>&6 +echo "configure:1180: checking for POSIXized ISC" >&5 +if test -d /etc/conf/kconfig.d && + grep _POSIX_VERSION /usr/include/sys/unistd.h >/dev/null 2>&1 +then + echo "$ac_t""yes" 1>&6 + ISC=yes # If later tests want to check for ISC. + cat >> confdefs.h <<\EOF +#define _POSIX_SOURCE 1 +EOF + + if test "$GCC" = yes; then + CC="$CC -posix" + else + CC="$CC -Xp" + fi +else + echo "$ac_t""no" 1>&6 + ISC= +fi + +echo $ac_n "checking how to run the C preprocessor""... $ac_c" 1>&6 +echo "configure:1201: checking how to run the C preprocessor" >&5 +# On Suns, sometimes $CPP names a directory. +if test -n "$CPP" && test -d "$CPP"; then + CPP= +fi +if test -z "$CPP"; then +if eval "test \"`echo '$''{'ac_cv_prog_CPP'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + # This must be in double quotes, not single quotes, because CPP may get + # substituted into the Makefile and "${CC-cc}" will confuse make. + CPP="${CC-cc} -E" + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. + cat > conftest.$ac_ext < +Syntax Error +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:1222: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out` +if test -z "$ac_err"; then + : +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + CPP="${CC-cc} -E -traditional-cpp" + cat > conftest.$ac_ext < +Syntax Error +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:1239: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out` +if test -z "$ac_err"; then + : +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + CPP=/lib/cpp +fi +rm -f conftest* +fi +rm -f conftest* + ac_cv_prog_CPP="$CPP" +fi + CPP="$ac_cv_prog_CPP" +else + ac_cv_prog_CPP="$CPP" +fi +echo "$ac_t""$CPP" 1>&6 + +ac_safe=`echo "minix/config.h" | sed 'y%./+-%__p_%'` +echo $ac_n "checking for minix/config.h""... $ac_c" 1>&6 +echo "configure:1263: checking for minix/config.h" >&5 +if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:1273: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out` +if test -z "$ac_err"; then + rm -rf conftest* + eval "ac_cv_header_$ac_safe=yes" +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_header_$ac_safe=no" +fi +rm -f conftest* +fi +if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then + echo "$ac_t""yes" 1>&6 + MINIX=yes +else + echo "$ac_t""no" 1>&6 +MINIX= +fi + +if test "$MINIX" = yes; then + cat >> confdefs.h <<\EOF +#define _POSIX_SOURCE 1 +EOF + + cat >> confdefs.h <<\EOF +#define _POSIX_1_SOURCE 2 +EOF + + cat >> confdefs.h <<\EOF +#define _MINIX 1 +EOF + +fi + + +echo $ac_n "checking whether CC works at all""... $ac_c" 1>&6 +echo "configure:1312: checking whether CC works at all" >&5 +if eval "test \"`echo '$''{'bash_cv_prog_cc_works'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test "$cross_compiling" = yes; then + bash_cv_prog_cc_works=no +else + cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null +then + bash_cv_prog_cc_works=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + bash_cv_prog_cc_works=no +fi +rm -fr conftest* +fi + + + +fi + +echo "$ac_t""$bash_cv_prog_cc_works" 1>&6 +if test "$bash_cv_prog_cc_works" = "no"; then +{ echo "configure: error: Installation or configuration problem: C compiler cannot create executables" 1>&2; exit 1; } +fi + + +test -z "$CFLAGS" && CFLAGS=-g auto_cflags=1 + +test -n "$GCC" && test -n "$auto_cflags" && CFLAGS="$CFLAGS -O2" + + + + + +if test $ac_cv_prog_gcc = yes; then + echo $ac_n "checking whether ${CC-cc} needs -traditional""... $ac_c" 1>&6 +echo "configure:1356: checking whether ${CC-cc} needs -traditional" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_gcc_traditional'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_pattern="Autoconf.*'x'" + cat > conftest.$ac_ext < +Autoconf TIOCGETP +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "$ac_pattern" >/dev/null 2>&1; then + rm -rf conftest* + ac_cv_prog_gcc_traditional=yes +else + rm -rf conftest* + ac_cv_prog_gcc_traditional=no +fi +rm -f conftest* + + + if test $ac_cv_prog_gcc_traditional = no; then + cat > conftest.$ac_ext < +Autoconf TCGETA +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "$ac_pattern" >/dev/null 2>&1; then + rm -rf conftest* + ac_cv_prog_gcc_traditional=yes +fi +rm -f conftest* + + fi +fi + +echo "$ac_t""$ac_cv_prog_gcc_traditional" 1>&6 + if test $ac_cv_prog_gcc_traditional = yes; then + CC="$CC -traditional" + fi +fi + + +# Find a good install program. We prefer a C program (faster), +# so one script is as good as another. But avoid the broken or +# incompatible versions: +# SysV /etc/install, /usr/sbin/install +# SunOS /usr/etc/install +# IRIX /sbin/install +# AIX /bin/install +# AFS /usr/afsws/bin/install, which mishandles nonexistent args +# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" +# ./install, which can be erroneously created by make from ./install.sh. +echo $ac_n "checking for a BSD compatible install""... $ac_c" 1>&6 +echo "configure:1413: checking for a BSD compatible install" >&5 +if test -z "$INSTALL"; then +if eval "test \"`echo '$''{'ac_cv_path_install'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + IFS="${IFS= }"; ac_save_IFS="$IFS"; IFS="${IFS}:" + for ac_dir in $PATH; do + # Account for people who put trailing slashes in PATH elements. + case "$ac_dir/" in + /|./|.//|/etc/*|/usr/sbin/*|/usr/etc/*|/sbin/*|/usr/afsws/bin/*|/usr/ucb/*) ;; + *) + # OSF1 and SCO ODT 3.0 have their own names for install. + for ac_prog in ginstall installbsd scoinst install; do + if test -f $ac_dir/$ac_prog; then + if test $ac_prog = install && + grep dspmsg $ac_dir/$ac_prog >/dev/null 2>&1; then + # AIX install. It has an incompatible calling convention. + # OSF/1 installbsd also uses dspmsg, but is usable. + : + else + ac_cv_path_install="$ac_dir/$ac_prog -c" + break 2 + fi + fi + done + ;; + esac + done + IFS="$ac_save_IFS" + +fi + if test "${ac_cv_path_install+set}" = set; then + INSTALL="$ac_cv_path_install" + else + # As a last resort, use the slow shell script. We don't cache a + # path for INSTALL within a source directory, because that will + # break other packages using the cache if that directory is + # removed, or if the path is relative. + INSTALL="$ac_install_sh" + fi +fi +echo "$ac_t""$INSTALL" 1>&6 + +# Use test -z because SunOS4 sh mishandles braces in ${var-val}. +# It thinks the first close brace ends the variable substitution. +test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' + +test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' + +# Extract the first word of "ar", so it can be a program name with args. +set dummy ar; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:1465: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_AR'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$AR"; then + ac_cv_prog_AR="$AR" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:" + for ac_dir in $PATH; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_AR="ar" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +AR="$ac_cv_prog_AR" +if test -n "$AR"; then + echo "$ac_t""$AR" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +# Extract the first word of "ranlib", so it can be a program name with args. +set dummy ranlib; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:1493: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_RANLIB'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$RANLIB"; then + ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:" + for ac_dir in $PATH; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_RANLIB="ranlib" + break + fi + done + IFS="$ac_save_ifs" + test -z "$ac_cv_prog_RANLIB" && ac_cv_prog_RANLIB=":" +fi +fi +RANLIB="$ac_cv_prog_RANLIB" +if test -n "$RANLIB"; then + echo "$ac_t""$RANLIB" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +for ac_prog in 'bison -y' byacc +do +# Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:1524: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_YACC'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$YACC"; then + ac_cv_prog_YACC="$YACC" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:" + for ac_dir in $PATH; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_YACC="$ac_prog" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +YACC="$ac_cv_prog_YACC" +if test -n "$YACC"; then + echo "$ac_t""$YACC" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +test -n "$YACC" && break +done +test -n "$YACC" || YACC="yacc" + +echo $ac_n "checking whether ${MAKE-make} sets \${MAKE}""... $ac_c" 1>&6 +echo "configure:1554: checking whether ${MAKE-make} sets \${MAKE}" >&5 +set dummy ${MAKE-make}; ac_make=`echo "$2" | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_prog_make_${ac_make}_set'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftestmake <<\EOF +all: + @echo 'ac_maketemp="${MAKE}"' +EOF +# GNU make sometimes prints "make[1]: Entering...", which would confuse us. +eval `${MAKE-make} -f conftestmake 2>/dev/null | grep temp=` +if test -n "$ac_maketemp"; then + eval ac_cv_prog_make_${ac_make}_set=yes +else + eval ac_cv_prog_make_${ac_make}_set=no +fi +rm -f conftestmake +fi +if eval "test \"`echo '$ac_cv_prog_make_'${ac_make}_set`\" = yes"; then + echo "$ac_t""yes" 1>&6 + SET_MAKE= +else + echo "$ac_t""no" 1>&6 + SET_MAKE="MAKE=${MAKE-make}" +fi + + +# The Ultrix 4.2 mips builtin alloca declared by alloca.h only works +# for constant arguments. Useless! +echo $ac_n "checking for working alloca.h""... $ac_c" 1>&6 +echo "configure:1584: checking for working alloca.h" >&5 +if eval "test \"`echo '$''{'ac_cv_header_alloca_h'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +int main() { +char *p = alloca(2 * sizeof(int)); +; return 0; } +EOF +if { (eval echo configure:1596: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then + rm -rf conftest* + ac_cv_header_alloca_h=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_header_alloca_h=no +fi +rm -f conftest* +fi + +echo "$ac_t""$ac_cv_header_alloca_h" 1>&6 +if test $ac_cv_header_alloca_h = yes; then + cat >> confdefs.h <<\EOF +#define HAVE_ALLOCA_H 1 +EOF + +fi + +echo $ac_n "checking for alloca""... $ac_c" 1>&6 +echo "configure:1617: checking for alloca" >&5 +if eval "test \"`echo '$''{'ac_cv_func_alloca_works'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +# else +# ifdef _AIX + #pragma alloca +# else +# ifndef alloca /* predefined by HP cc +Olibcalls */ +char *alloca (); +# endif +# endif +# endif +#endif + +int main() { +char *p = (char *) alloca(1); +; return 0; } +EOF +if { (eval echo configure:1645: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then + rm -rf conftest* + ac_cv_func_alloca_works=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_func_alloca_works=no +fi +rm -f conftest* +fi + +echo "$ac_t""$ac_cv_func_alloca_works" 1>&6 +if test $ac_cv_func_alloca_works = yes; then + cat >> confdefs.h <<\EOF +#define HAVE_ALLOCA 1 +EOF + +fi + +if test $ac_cv_func_alloca_works = no; then + # The SVR3 libPW and SVR4 libucb both contain incompatible functions + # that cause trouble. Some versions do not even contain alloca or + # contain a buggy version. If you still want to use their alloca, + # use ar to extract alloca.o from them instead of compiling alloca.c. + ALLOCA=alloca.o + cat >> confdefs.h <<\EOF +#define C_ALLOCA 1 +EOF + + +echo $ac_n "checking whether alloca needs Cray hooks""... $ac_c" 1>&6 +echo "configure:1677: checking whether alloca needs Cray hooks" >&5 +if eval "test \"`echo '$''{'ac_cv_os_cray'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <&5 | + egrep "webecray" >/dev/null 2>&1; then + rm -rf conftest* + ac_cv_os_cray=yes +else + rm -rf conftest* + ac_cv_os_cray=no +fi +rm -f conftest* + +fi + +echo "$ac_t""$ac_cv_os_cray" 1>&6 +if test $ac_cv_os_cray = yes; then +for ac_func in _getb67 GETB67 getb67; do + echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 +echo "configure:1707: checking for $ac_func" >&5 +if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char $ac_func(); + +int main() { + +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_$ac_func) || defined (__stub___$ac_func) +choke me +#else +$ac_func(); +#endif + +; return 0; } +EOF +if { (eval echo configure:1735: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then + rm -rf conftest* + eval "ac_cv_func_$ac_func=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_func_$ac_func=no" +fi +rm -f conftest* +fi + +if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then + echo "$ac_t""yes" 1>&6 + cat >> confdefs.h <&6 +fi + +done +fi + +echo $ac_n "checking stack direction for C alloca""... $ac_c" 1>&6 +echo "configure:1762: checking stack direction for C alloca" >&5 +if eval "test \"`echo '$''{'ac_cv_c_stack_direction'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test "$cross_compiling" = yes; then + ac_cv_c_stack_direction=0 +else + cat > conftest.$ac_ext < addr) ? 1 : -1; +} +main () +{ + exit (find_stack_direction() < 0); +} +EOF +if { (eval echo configure:1789: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null +then + ac_cv_c_stack_direction=1 +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + ac_cv_c_stack_direction=-1 +fi +rm -fr conftest* +fi + +fi + +echo "$ac_t""$ac_cv_c_stack_direction" 1>&6 +cat >> confdefs.h <&6 +echo "configure:1811: checking whether getpgrp takes no argument" >&5 +if eval "test \"`echo '$''{'ac_cv_func_getpgrp_void'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test "$cross_compiling" = yes; then + { echo "configure: error: cannot check getpgrp if cross compiling" 1>&2; exit 1; } +else + cat > conftest.$ac_ext < +#include + +int pid; +int pg1, pg2, pg3, pg4; +int ng, np, s, child; + +main() +{ + pid = getpid(); + pg1 = getpgrp(0); + pg2 = getpgrp(); + pg3 = getpgrp(pid); + pg4 = getpgrp(1); + + /* + * If all of these values are the same, it's pretty sure that + * we're on a system that ignores getpgrp's first argument. + */ + if (pg2 == pg4 && pg1 == pg3 && pg2 == pg3) + exit(0); + + child = fork(); + if (child < 0) + exit(1); + else if (child == 0) { + np = getpid(); + /* + * If this is Sys V, this will not work; pgrp will be + * set to np because setpgrp just changes a pgrp to be + * the same as the pid. + */ + setpgrp(np, pg1); + ng = getpgrp(0); /* Same result for Sys V and BSD */ + if (ng == pg1) { + exit(1); + } else { + exit(0); + } + } else { + wait(&s); + exit(s>>8); + } +} + +EOF +if { (eval echo configure:1874: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null +then + ac_cv_func_getpgrp_void=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + ac_cv_func_getpgrp_void=no +fi +rm -fr conftest* +fi + + +fi + +echo "$ac_t""$ac_cv_func_getpgrp_void" 1>&6 +if test $ac_cv_func_getpgrp_void = yes; then + cat >> confdefs.h <<\EOF +#define GETPGRP_VOID 1 +EOF + +fi + +echo $ac_n "checking whether setvbuf arguments are reversed""... $ac_c" 1>&6 +echo "configure:1898: checking whether setvbuf arguments are reversed" >&5 +if eval "test \"`echo '$''{'ac_cv_func_setvbuf_reversed'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test "$cross_compiling" = yes; then + { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; } +else + cat > conftest.$ac_ext < +/* If setvbuf has the reversed format, exit 0. */ +main () { + /* This call has the arguments reversed. + A reversed system may check and see that the address of main + is not _IOLBF, _IONBF, or _IOFBF, and return nonzero. */ + if (setvbuf(stdout, _IOLBF, (char *) main, BUFSIZ) != 0) + exit(1); + putc('\r', stdout); + exit(0); /* Non-reversed systems segv here. */ +} +EOF +if { (eval echo configure:1920: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null +then + ac_cv_func_setvbuf_reversed=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + ac_cv_func_setvbuf_reversed=no +fi +rm -fr conftest* +fi + +rm -f core core.* *.core +fi + +echo "$ac_t""$ac_cv_func_setvbuf_reversed" 1>&6 +if test $ac_cv_func_setvbuf_reversed = yes; then + cat >> confdefs.h <<\EOF +#define SETVBUF_REVERSED 1 +EOF + +fi + +echo $ac_n "checking for vprintf""... $ac_c" 1>&6 +echo "configure:1944: checking for vprintf" >&5 +if eval "test \"`echo '$''{'ac_cv_func_vprintf'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char vprintf(); + +int main() { + +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_vprintf) || defined (__stub___vprintf) +choke me +#else +vprintf(); +#endif + +; return 0; } +EOF +if { (eval echo configure:1972: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then + rm -rf conftest* + eval "ac_cv_func_vprintf=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_func_vprintf=no" +fi +rm -f conftest* +fi + +if eval "test \"`echo '$ac_cv_func_'vprintf`\" = yes"; then + echo "$ac_t""yes" 1>&6 + cat >> confdefs.h <<\EOF +#define HAVE_VPRINTF 1 +EOF + +else + echo "$ac_t""no" 1>&6 +fi + +if test "$ac_cv_func_vprintf" != yes; then +echo $ac_n "checking for _doprnt""... $ac_c" 1>&6 +echo "configure:1996: checking for _doprnt" >&5 +if eval "test \"`echo '$''{'ac_cv_func__doprnt'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char _doprnt(); + +int main() { + +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub__doprnt) || defined (__stub____doprnt) +choke me +#else +_doprnt(); +#endif + +; return 0; } +EOF +if { (eval echo configure:2024: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then + rm -rf conftest* + eval "ac_cv_func__doprnt=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_func__doprnt=no" +fi +rm -f conftest* +fi + +if eval "test \"`echo '$ac_cv_func_'_doprnt`\" = yes"; then + echo "$ac_t""yes" 1>&6 + cat >> confdefs.h <<\EOF +#define HAVE_DOPRNT 1 +EOF + +else + echo "$ac_t""no" 1>&6 +fi + +fi + +echo $ac_n "checking for wait3 that fills in rusage""... $ac_c" 1>&6 +echo "configure:2049: checking for wait3 that fills in rusage" >&5 +if eval "test \"`echo '$''{'ac_cv_func_wait3_rusage'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test "$cross_compiling" = yes; then + ac_cv_func_wait3_rusage=no +else + cat > conftest.$ac_ext < +#include +#include +#include +/* HP-UX has wait3 but does not fill in rusage at all. */ +main() { + struct rusage r; + int i; + /* Use a field that we can force nonzero -- + voluntary context switches. + For systems like NeXT and OSF/1 that don't set it, + also use the system CPU time. And page faults (I/O) for Linux. */ + r.ru_nvcsw = 0; + r.ru_stime.tv_sec = 0; + r.ru_stime.tv_usec = 0; + r.ru_majflt = r.ru_minflt = 0; + switch (fork()) { + case 0: /* Child. */ + sleep(1); /* Give up the CPU. */ + _exit(0); + case -1: _exit(0); /* What can we do? */ + default: /* Parent. */ + wait3(&i, 0, &r); + sleep(2); /* Avoid "text file busy" from rm on fast HP-UX machines. */ + exit(r.ru_nvcsw == 0 && r.ru_majflt == 0 && r.ru_minflt == 0 + && r.ru_stime.tv_sec == 0 && r.ru_stime.tv_usec == 0); + } +} +EOF +if { (eval echo configure:2088: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null +then + ac_cv_func_wait3_rusage=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + ac_cv_func_wait3_rusage=no +fi +rm -fr conftest* +fi + +fi + +echo "$ac_t""$ac_cv_func_wait3_rusage" 1>&6 +if test $ac_cv_func_wait3_rusage = yes; then + cat >> confdefs.h <<\EOF +#define HAVE_WAIT3 1 +EOF + +fi + +echo $ac_n "checking for working strcoll""... $ac_c" 1>&6 +echo "configure:2111: checking for working strcoll" >&5 +if eval "test \"`echo '$''{'ac_cv_func_strcoll_works'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test "$cross_compiling" = yes; then + ac_cv_func_strcoll_works=no +else + cat > conftest.$ac_ext < +main () +{ + exit (strcoll ("abc", "def") >= 0 || + strcoll ("ABC", "DEF") >= 0 || + strcoll ("123", "456") >= 0); +} +EOF +if { (eval echo configure:2129: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null +then + ac_cv_func_strcoll_works=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + ac_cv_func_strcoll_works=no +fi +rm -fr conftest* +fi + +fi + +echo "$ac_t""$ac_cv_func_strcoll_works" 1>&6 +if test $ac_cv_func_strcoll_works = yes; then + cat >> confdefs.h <<\EOF +#define HAVE_STRCOLL 1 +EOF + +fi + + +if test "$ac_cv_func_vprintf" = no; then + echo $ac_n "checking for declaration of vprintf in stdio.h""... $ac_c" 1>&6 +echo "configure:2154: checking for declaration of vprintf in stdio.h" >&5 + cat > conftest.$ac_ext < +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "[int[ ]*vprintf[^a-zA-Z0-9]]" >/dev/null 2>&1; then + rm -rf conftest* + ac_cv_func_vprintf=yes +fi +rm -f conftest* + + echo "$ac_t""$ac_cv_func_vprintf" 1>&6 + if test $ac_cv_func_vprintf = yes; then + cat >> confdefs.h <<\EOF +#define HAVE_VPRINTF 1 +EOF + + fi +fi + +echo $ac_n "checking return type of signal handlers""... $ac_c" 1>&6 +echo "configure:2177: checking return type of signal handlers" >&5 +if eval "test \"`echo '$''{'ac_cv_type_signal'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +#include +#ifdef signal +#undef signal +#endif +#ifdef __cplusplus +extern "C" void (*signal (int, void (*)(int)))(int); +#else +void (*signal ()) (); +#endif + +int main() { +int i; +; return 0; } +EOF +if { (eval echo configure:2199: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + ac_cv_type_signal=void +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_type_signal=int +fi +rm -f conftest* +fi + +echo "$ac_t""$ac_cv_type_signal" 1>&6 +cat >> confdefs.h <&6 +echo "configure:2219: checking for __setostype" >&5 +if eval "test \"`echo '$''{'ac_cv_func___setostype'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char __setostype(); + +int main() { + +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub___setostype) || defined (__stub_____setostype) +choke me +#else +__setostype(); +#endif + +; return 0; } +EOF +if { (eval echo configure:2247: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then + rm -rf conftest* + eval "ac_cv_func___setostype=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_func___setostype=no" +fi +rm -f conftest* +fi + +if eval "test \"`echo '$ac_cv_func_'__setostype`\" = yes"; then + echo "$ac_t""yes" 1>&6 + cat >> confdefs.h <<\EOF +#define HAVE_SETOSTYPE 1 +EOF + +else + echo "$ac_t""no" 1>&6 +fi + +echo $ac_n "checking for wait3""... $ac_c" 1>&6 +echo "configure:2270: checking for wait3" >&5 +if eval "test \"`echo '$''{'ac_cv_func_wait3'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char wait3(); + +int main() { + +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_wait3) || defined (__stub___wait3) +choke me +#else +wait3(); +#endif + +; return 0; } +EOF +if { (eval echo configure:2298: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then + rm -rf conftest* + eval "ac_cv_func_wait3=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_func_wait3=no" +fi +rm -f conftest* +fi + +if eval "test \"`echo '$ac_cv_func_'wait3`\" = yes"; then + echo "$ac_t""yes" 1>&6 + cat >> confdefs.h <<\EOF +#define HAVE_WAIT3 1 +EOF + +else + echo "$ac_t""no" 1>&6 +fi + + +echo $ac_n "checking for mkfifo""... $ac_c" 1>&6 +echo "configure:2322: checking for mkfifo" >&5 +if eval "test \"`echo '$''{'ac_cv_func_mkfifo'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char mkfifo(); + +int main() { + +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_mkfifo) || defined (__stub___mkfifo) +choke me +#else +mkfifo(); +#endif + +; return 0; } +EOF +if { (eval echo configure:2350: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then + rm -rf conftest* + eval "ac_cv_func_mkfifo=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_func_mkfifo=no" +fi +rm -f conftest* +fi + +if eval "test \"`echo '$ac_cv_func_'mkfifo`\" = yes"; then + echo "$ac_t""yes" 1>&6 + cat >> confdefs.h <<\EOF +#define HAVE_MKFIFO 1 +EOF + +else + echo "$ac_t""no" 1>&6 +cat >> confdefs.h <<\EOF +#define MKFIFO_MISSING 1 +EOF + +fi + + +for ac_func in dup2 select getdtablesize getgroups gethostname \ + setdtablesize getpagesize killpg lstat getpeername \ + getrlimit getrusage gettimeofday waitpid tcgetpgrp +do +echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 +echo "configure:2382: checking for $ac_func" >&5 +if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char $ac_func(); + +int main() { + +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_$ac_func) || defined (__stub___$ac_func) +choke me +#else +$ac_func(); +#endif + +; return 0; } +EOF +if { (eval echo configure:2410: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then + rm -rf conftest* + eval "ac_cv_func_$ac_func=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_func_$ac_func=no" +fi +rm -f conftest* +fi + +if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'` + cat >> confdefs.h <&6 +fi +done + + +for ac_func in bcopy bzero confstr getcwd strcasecmp setenv putenv \ + setlinebuf setlocale strchr strerror tcgetattr uname \ + sysconf ulimit times tzset siginterrupt memmove +do +echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 +echo "configure:2440: checking for $ac_func" >&5 +if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char $ac_func(); + +int main() { + +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_$ac_func) || defined (__stub___$ac_func) +choke me +#else +$ac_func(); +#endif + +; return 0; } +EOF +if { (eval echo configure:2468: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then + rm -rf conftest* + eval "ac_cv_func_$ac_func=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_func_$ac_func=no" +fi +rm -f conftest* +fi + +if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'` + cat >> confdefs.h <&6 +fi +done + + +for ac_hdr in libintl.h +do +ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` +echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 +echo "configure:2497: checking for $ac_hdr" >&5 +if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:2507: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out` +if test -z "$ac_err"; then + rm -rf conftest* + eval "ac_cv_header_$ac_safe=yes" +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_header_$ac_safe=no" +fi +rm -f conftest* +fi +if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'` + cat >> confdefs.h <&6 +fi +done + +for ac_func in gettext textdomain bindtextdomain +do +echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 +echo "configure:2536: checking for $ac_func" >&5 +if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char $ac_func(); + +int main() { + +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_$ac_func) || defined (__stub___$ac_func) +choke me +#else +$ac_func(); +#endif + +; return 0; } +EOF +if { (eval echo configure:2564: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then + rm -rf conftest* + eval "ac_cv_func_$ac_func=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_func_$ac_func=no" +fi +rm -f conftest* +fi + +if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'` + cat >> confdefs.h <&6 +fi +done + + +if test "$ac_cv_func_bindtextdomain" = "no"; then + echo $ac_n "checking for bindtextdomain in -lintl""... $ac_c" 1>&6 +echo "configure:2591: checking for bindtextdomain in -lintl" >&5 +ac_lib_var=`echo intl'_'bindtextdomain | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-lintl $LIBS" +cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_lib=HAVE_LIB`echo intl | sed -e 's/[^a-zA-Z0-9_]/_/g' \ + -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'` + cat >> confdefs.h <&6 +fi + + if test "$ac_cv_lib_intl" = "yes"; then + for ac_func in gettext textdomain bindtextdomain +do +echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 +echo "configure:2641: checking for $ac_func" >&5 +if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char $ac_func(); + +int main() { + +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_$ac_func) || defined (__stub___$ac_func) +choke me +#else +$ac_func(); +#endif + +; return 0; } +EOF +if { (eval echo configure:2669: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then + rm -rf conftest* + eval "ac_cv_func_$ac_func=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_func_$ac_func=no" +fi +rm -f conftest* +fi + +if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'` + cat >> confdefs.h <&6 +fi +done + + fi +fi + +echo $ac_n "checking for dlopen in -ldl""... $ac_c" 1>&6 +echo "configure:2697: checking for dlopen in -ldl" >&5 +ac_lib_var=`echo dl'_'dlopen | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-ldl $LIBS" +cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_lib=HAVE_LIB`echo dl | sed -e 's/[^a-zA-Z0-9_]/_/g' \ + -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'` + cat >> confdefs.h <&6 +fi + +for ac_func in dlopen dlclose dlsym +do +echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 +echo "configure:2746: checking for $ac_func" >&5 +if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char $ac_func(); + +int main() { + +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_$ac_func) || defined (__stub___$ac_func) +choke me +#else +$ac_func(); +#endif + +; return 0; } +EOF +if { (eval echo configure:2774: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then + rm -rf conftest* + eval "ac_cv_func_$ac_func=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_func_$ac_func=no" +fi +rm -f conftest* +fi + +if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'` + cat >> confdefs.h <&6 +fi +done + + +echo $ac_n "checking for sys_siglist declaration in signal.h or unistd.h""... $ac_c" 1>&6 +echo "configure:2800: checking for sys_siglist declaration in signal.h or unistd.h" >&5 +if eval "test \"`echo '$''{'ac_cv_decl_sys_siglist'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +#include +/* NetBSD declares sys_siglist in unistd.h. */ +#ifdef HAVE_UNISTD_H +#include +#endif +int main() { +char *msg = *(sys_siglist + 1); +; return 0; } +EOF +if { (eval echo configure:2817: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + ac_cv_decl_sys_siglist=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_decl_sys_siglist=no +fi +rm -f conftest* +fi + +echo "$ac_t""$ac_cv_decl_sys_siglist" 1>&6 +if test $ac_cv_decl_sys_siglist = yes; then + cat >> confdefs.h <<\EOF +#define SYS_SIGLIST_DECLARED 1 +EOF + +fi + + +ac_header_dirent=no +for ac_hdr in dirent.h sys/ndir.h sys/dir.h ndir.h +do +ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` +echo $ac_n "checking for $ac_hdr that defines DIR""... $ac_c" 1>&6 +echo "configure:2843: checking for $ac_hdr that defines DIR" >&5 +if eval "test \"`echo '$''{'ac_cv_header_dirent_$ac_safe'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +#include <$ac_hdr> +int main() { +DIR *dirp = 0; +; return 0; } +EOF +if { (eval echo configure:2856: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + eval "ac_cv_header_dirent_$ac_safe=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_header_dirent_$ac_safe=no" +fi +rm -f conftest* +fi +if eval "test \"`echo '$ac_cv_header_dirent_'$ac_safe`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'` + cat >> confdefs.h <&6 +fi +done +# Two versions of opendir et al. are in -ldir and -lx on SCO Xenix. +if test $ac_header_dirent = dirent.h; then +echo $ac_n "checking for opendir in -ldir""... $ac_c" 1>&6 +echo "configure:2881: checking for opendir in -ldir" >&5 +ac_lib_var=`echo dir'_'opendir | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-ldir $LIBS" +cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + LIBS="$LIBS -ldir" +else + echo "$ac_t""no" 1>&6 +fi + +else +echo $ac_n "checking for opendir in -lx""... $ac_c" 1>&6 +echo "configure:2922: checking for opendir in -lx" >&5 +ac_lib_var=`echo x'_'opendir | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-lx $LIBS" +cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + LIBS="$LIBS -lx" +else + echo "$ac_t""no" 1>&6 +fi + +fi + +echo $ac_n "checking whether time.h and sys/time.h may both be included""... $ac_c" 1>&6 +echo "configure:2964: checking whether time.h and sys/time.h may both be included" >&5 +if eval "test \"`echo '$''{'ac_cv_header_time'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +#include +#include +int main() { +struct tm *tp; +; return 0; } +EOF +if { (eval echo configure:2978: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + ac_cv_header_time=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_header_time=no +fi +rm -f conftest* +fi + +echo "$ac_t""$ac_cv_header_time" 1>&6 +if test $ac_cv_header_time = yes; then + cat >> confdefs.h <<\EOF +#define TIME_WITH_SYS_TIME 1 +EOF + +fi + + +for ac_hdr in unistd.h stdlib.h stdarg.h varargs.h limits.h string.h \ + memory.h locale.h termcap.h termio.h termios.h +do +ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` +echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 +echo "configure:3004: checking for $ac_hdr" >&5 +if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:3014: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out` +if test -z "$ac_err"; then + rm -rf conftest* + eval "ac_cv_header_$ac_safe=yes" +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_header_$ac_safe=no" +fi +rm -f conftest* +fi +if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'` + cat >> confdefs.h <&6 +fi +done + +for ac_hdr in sys/ptem.h sys/pte.h sys/stream.h sys/select.h sys/file.h \ + sys/resource.h sys/param.h sys/socket.h \ + sys/time.h sys/times.h sys/wait.h +do +ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` +echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 +echo "configure:3046: checking for $ac_hdr" >&5 +if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:3056: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out` +if test -z "$ac_err"; then + rm -rf conftest* + eval "ac_cv_header_$ac_safe=yes" +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_header_$ac_safe=no" +fi +rm -f conftest* +fi +if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'` + cat >> confdefs.h <&6 +fi +done + + + +if test "X$bash_cv_have_socklib" = "X"; then +_bash_needmsg= +else +echo $ac_n "checking for socket library""... $ac_c" 1>&6 +echo "configure:3088: checking for socket library" >&5 +_bash_needmsg=yes +fi +if eval "test \"`echo '$''{'bash_cv_have_socklib'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + echo $ac_n "checking for getpeername in -lsocket""... $ac_c" 1>&6 +echo "configure:3095: checking for getpeername in -lsocket" >&5 +ac_lib_var=`echo socket'_'getpeername | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-lsocket -lnsl $LIBS" +cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + bash_cv_have_socklib=yes +else + echo "$ac_t""no" 1>&6 +bash_cv_have_socklib=no +fi + +fi + +if test "X$_bash_needmsg" = Xyes; then + echo "$ac_t""$bash_cv_have_socklib" 1>&6 + _bash_needmsg= +fi +if test $bash_cv_have_socklib = yes; then + # check for libnsl, add it to LIBS if present + if test "X$bash_cv_have_libnsl" = "X"; then + _bash_needmsg= + else + echo $ac_n "checking for libnsl""... $ac_c" 1>&6 +echo "configure:3147: checking for libnsl" >&5 + _bash_needmsg=yes + fi + if eval "test \"`echo '$''{'bash_cv_have_libnsl'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + echo $ac_n "checking for t_open in -lnsl""... $ac_c" 1>&6 +echo "configure:3154: checking for t_open in -lnsl" >&5 +ac_lib_var=`echo nsl'_'t_open | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-lnsl $LIBS" +cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + bash_cv_have_libnsl=yes +else + echo "$ac_t""no" 1>&6 +bash_cv_have_libnsl=no +fi + +fi + + if test "X$_bash_needmsg" = Xyes; then + echo "$ac_t""$bash_cv_have_libnsl" 1>&6 + _bash_needmsg= + fi + if test $bash_cv_have_libnsl = yes; then + LIBS="-lsocket -lnsl $LIBS" + else + LIBS="-lsocket $LIBS" + fi + cat >> confdefs.h <<\EOF +#define HAVE_LIBSOCKET 1 +EOF + + cat >> confdefs.h <<\EOF +#define HAVE_GETPEERNAME 1 +EOF + +fi + + +echo $ac_n "checking for uid_t in sys/types.h""... $ac_c" 1>&6 +echo "configure:3217: checking for uid_t in sys/types.h" >&5 +if eval "test \"`echo '$''{'ac_cv_type_uid_t'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "uid_t" >/dev/null 2>&1; then + rm -rf conftest* + ac_cv_type_uid_t=yes +else + rm -rf conftest* + ac_cv_type_uid_t=no +fi +rm -f conftest* + +fi + +echo "$ac_t""$ac_cv_type_uid_t" 1>&6 +if test $ac_cv_type_uid_t = no; then + cat >> confdefs.h <<\EOF +#define uid_t int +EOF + + cat >> confdefs.h <<\EOF +#define gid_t int +EOF + +fi + +echo $ac_n "checking type of array argument to getgroups""... $ac_c" 1>&6 +echo "configure:3251: checking type of array argument to getgroups" >&5 +if eval "test \"`echo '$''{'ac_cv_type_getgroups'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test "$cross_compiling" = yes; then + ac_cv_type_getgroups=cross +else + cat > conftest.$ac_ext < +#define NGID 256 +#undef MAX +#define MAX(x, y) ((x) > (y) ? (x) : (y)) +main() +{ + gid_t gidset[NGID]; + int i, n; + union { gid_t gval; long lval; } val; + + val.lval = -1; + for (i = 0; i < NGID; i++) + gidset[i] = val.gval; + n = getgroups (sizeof (gidset) / MAX (sizeof (int), sizeof (gid_t)) - 1, + gidset); + /* Exit non-zero if getgroups seems to require an array of ints. This + happens when gid_t is short but getgroups modifies an array of ints. */ + exit ((n > 0 && gidset[n] != val.gval) ? 1 : 0); +} + +EOF +if { (eval echo configure:3284: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null +then + ac_cv_type_getgroups=gid_t +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + ac_cv_type_getgroups=int +fi +rm -fr conftest* +fi + +if test $ac_cv_type_getgroups = cross; then + cat > conftest.$ac_ext < +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "getgroups.*int.*gid_t" >/dev/null 2>&1; then + rm -rf conftest* + ac_cv_type_getgroups=gid_t +else + rm -rf conftest* + ac_cv_type_getgroups=int +fi +rm -f conftest* + +fi +fi + +echo "$ac_t""$ac_cv_type_getgroups" 1>&6 +cat >> confdefs.h <&6 +echo "configure:3322: checking for ANSI C header files" >&5 +if eval "test \"`echo '$''{'ac_cv_header_stdc'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +#include +#include +#include +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:3335: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out` +if test -z "$ac_err"; then + rm -rf conftest* + ac_cv_header_stdc=yes +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_header_stdc=no +fi +rm -f conftest* + +if test $ac_cv_header_stdc = yes; then + # SunOS 4.x string.h does not declare mem*, contrary to ANSI. +cat > conftest.$ac_ext < +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "memchr" >/dev/null 2>&1; then + : +else + rm -rf conftest* + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. +cat > conftest.$ac_ext < +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "free" >/dev/null 2>&1; then + : +else + rm -rf conftest* + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. +if test "$cross_compiling" = yes; then + : +else + cat > conftest.$ac_ext < +#define ISLOWER(c) ('a' <= (c) && (c) <= 'z') +#define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) +#define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) +int main () { int i; for (i = 0; i < 256; i++) +if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) exit(2); +exit (0); } + +EOF +if { (eval echo configure:3402: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null +then + : +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + ac_cv_header_stdc=no +fi +rm -fr conftest* +fi + +fi +fi + +echo "$ac_t""$ac_cv_header_stdc" 1>&6 +if test $ac_cv_header_stdc = yes; then + cat >> confdefs.h <<\EOF +#define STDC_HEADERS 1 +EOF + +fi + +echo $ac_n "checking for off_t""... $ac_c" 1>&6 +echo "configure:3426: checking for off_t" >&5 +if eval "test \"`echo '$''{'ac_cv_type_off_t'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +#if STDC_HEADERS +#include +#include +#endif +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "off_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then + rm -rf conftest* + ac_cv_type_off_t=yes +else + rm -rf conftest* + ac_cv_type_off_t=no +fi +rm -f conftest* + +fi +echo "$ac_t""$ac_cv_type_off_t" 1>&6 +if test $ac_cv_type_off_t = no; then + cat >> confdefs.h <<\EOF +#define off_t long +EOF + +fi + +echo $ac_n "checking for mode_t""... $ac_c" 1>&6 +echo "configure:3459: checking for mode_t" >&5 +if eval "test \"`echo '$''{'ac_cv_type_mode_t'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +#if STDC_HEADERS +#include +#include +#endif +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "mode_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then + rm -rf conftest* + ac_cv_type_mode_t=yes +else + rm -rf conftest* + ac_cv_type_mode_t=no +fi +rm -f conftest* + +fi +echo "$ac_t""$ac_cv_type_mode_t" 1>&6 +if test $ac_cv_type_mode_t = no; then + cat >> confdefs.h <<\EOF +#define mode_t int +EOF + +fi + +echo $ac_n "checking for uid_t in sys/types.h""... $ac_c" 1>&6 +echo "configure:3492: checking for uid_t in sys/types.h" >&5 +if eval "test \"`echo '$''{'ac_cv_type_uid_t'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "uid_t" >/dev/null 2>&1; then + rm -rf conftest* + ac_cv_type_uid_t=yes +else + rm -rf conftest* + ac_cv_type_uid_t=no +fi +rm -f conftest* + +fi + +echo "$ac_t""$ac_cv_type_uid_t" 1>&6 +if test $ac_cv_type_uid_t = no; then + cat >> confdefs.h <<\EOF +#define uid_t int +EOF + + cat >> confdefs.h <<\EOF +#define gid_t int +EOF + +fi + +echo $ac_n "checking for pid_t""... $ac_c" 1>&6 +echo "configure:3526: checking for pid_t" >&5 +if eval "test \"`echo '$''{'ac_cv_type_pid_t'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +#if STDC_HEADERS +#include +#include +#endif +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "pid_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then + rm -rf conftest* + ac_cv_type_pid_t=yes +else + rm -rf conftest* + ac_cv_type_pid_t=no +fi +rm -f conftest* + +fi +echo "$ac_t""$ac_cv_type_pid_t" 1>&6 +if test $ac_cv_type_pid_t = no; then + cat >> confdefs.h <<\EOF +#define pid_t int +EOF + +fi + +echo $ac_n "checking for size_t""... $ac_c" 1>&6 +echo "configure:3559: checking for size_t" >&5 +if eval "test \"`echo '$''{'ac_cv_type_size_t'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +#if STDC_HEADERS +#include +#include +#endif +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "size_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then + rm -rf conftest* + ac_cv_type_size_t=yes +else + rm -rf conftest* + ac_cv_type_size_t=no +fi +rm -f conftest* + +fi +echo "$ac_t""$ac_cv_type_size_t" 1>&6 +if test $ac_cv_type_size_t = no; then + cat >> confdefs.h <<\EOF +#define size_t unsigned +EOF + +fi + +echo $ac_n "checking for time_t""... $ac_c" 1>&6 +echo "configure:3592: checking for time_t" >&5 +if eval "test \"`echo '$''{'ac_cv_type_time_t'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +#if STDC_HEADERS +#include +#include +#endif +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "time_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then + rm -rf conftest* + ac_cv_type_time_t=yes +else + rm -rf conftest* + ac_cv_type_time_t=no +fi +rm -f conftest* + +fi +echo "$ac_t""$ac_cv_type_time_t" 1>&6 +if test $ac_cv_type_time_t = no; then + cat >> confdefs.h <<\EOF +#define time_t long +EOF + +fi + + +echo $ac_n "checking return type of signal handlers""... $ac_c" 1>&6 +echo "configure:3626: checking return type of signal handlers" >&5 +if eval "test \"`echo '$''{'ac_cv_type_signal'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +#include +#ifdef signal +#undef signal +#endif +#ifdef __cplusplus +extern "C" void (*signal (int, void (*)(int)))(int); +#else +void (*signal ()) (); +#endif + +int main() { +int i; +; return 0; } +EOF +if { (eval echo configure:3648: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + ac_cv_type_signal=void +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_type_signal=int +fi +rm -f conftest* +fi + +echo "$ac_t""$ac_cv_type_signal" 1>&6 +cat >> confdefs.h <&6 +echo "configure:3668: checking whether stat file-mode macros are broken" >&5 +if eval "test \"`echo '$''{'ac_cv_header_stat_broken'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +#include + +#if defined(S_ISBLK) && defined(S_IFDIR) +# if S_ISBLK (S_IFDIR) +You lose. +# endif +#endif + +#if defined(S_ISBLK) && defined(S_IFCHR) +# if S_ISBLK (S_IFCHR) +You lose. +# endif +#endif + +#if defined(S_ISLNK) && defined(S_IFREG) +# if S_ISLNK (S_IFREG) +You lose. +# endif +#endif + +#if defined(S_ISSOCK) && defined(S_IFREG) +# if S_ISSOCK (S_IFREG) +You lose. +# endif +#endif + +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "You lose" >/dev/null 2>&1; then + rm -rf conftest* + ac_cv_header_stat_broken=yes +else + rm -rf conftest* + ac_cv_header_stat_broken=no +fi +rm -f conftest* + +fi + +echo "$ac_t""$ac_cv_header_stat_broken" 1>&6 +if test $ac_cv_header_stat_broken = yes; then + cat >> confdefs.h <<\EOF +#define STAT_MACROS_BROKEN 1 +EOF + +fi + +cat > conftest.$ac_ext < +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "struct timeval" >/dev/null 2>&1; then + rm -rf conftest* + bash_cv_struct_timeval=yes +fi +rm -f conftest* + +if test -z "$bash_cv_struct_timeval"; then +cat > conftest.$ac_ext < +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "struct timeval" >/dev/null 2>&1; then + rm -rf conftest* + bash_cv_struct_timeval=yes +else + rm -rf conftest* + bash_cv_struct_timeval=no +fi +rm -f conftest* + +fi +if test $bash_cv_struct_timeval = yes; then +cat >> confdefs.h <<\EOF +#define HAVE_TIMEVAL 1 +EOF + +fi + +echo $ac_n "checking whether byte ordering is bigendian""... $ac_c" 1>&6 +echo "configure:3760: checking whether byte ordering is bigendian" >&5 +if eval "test \"`echo '$''{'ac_cv_c_bigendian'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_cv_c_bigendian=unknown +# See if sys/param.h defines the BYTE_ORDER macro. +cat > conftest.$ac_ext < +#include +int main() { + +#if !BYTE_ORDER || !BIG_ENDIAN || !LITTLE_ENDIAN + bogus endian macros +#endif +; return 0; } +EOF +if { (eval echo configure:3778: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + # It does; now see whether it defined to BIG_ENDIAN or not. +cat > conftest.$ac_ext < +#include +int main() { + +#if BYTE_ORDER != BIG_ENDIAN + not big endian +#endif +; return 0; } +EOF +if { (eval echo configure:3793: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + ac_cv_c_bigendian=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_c_bigendian=no +fi +rm -f conftest* +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 +fi +rm -f conftest* +if test $ac_cv_c_bigendian = unknown; then +if test "$cross_compiling" = yes; then + { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; } +else + cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null +then + ac_cv_c_bigendian=no +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + ac_cv_c_bigendian=yes +fi +rm -fr conftest* +fi + +fi +fi + +echo "$ac_t""$ac_cv_c_bigendian" 1>&6 +if test $ac_cv_c_bigendian = yes; then + cat >> confdefs.h <<\EOF +#define WORDS_BIGENDIAN 1 +EOF + +fi + + +# Pull the hash mark out of the macro call to avoid m4 problems. +ac_msg="whether #! works in shell scripts" +echo $ac_n "checking $ac_msg""... $ac_c" 1>&6 +echo "configure:3853: checking $ac_msg" >&5 +if eval "test \"`echo '$''{'ac_cv_sys_interpreter'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + echo '#! /bin/cat +exit 69 +' > conftest +chmod u+x conftest +(SHELL=/bin/sh; export SHELL; ./conftest >/dev/null) +if test $? -ne 69; then + ac_cv_sys_interpreter=yes +else + ac_cv_sys_interpreter=no +fi +rm -f conftest +fi + +echo "$ac_t""$ac_cv_sys_interpreter" 1>&6 + +if test $ac_cv_sys_interpreter = yes; then +cat >> confdefs.h <<\EOF +#define HAVE_HASH_BANG_EXEC 1 +EOF + +fi +echo $ac_n "checking for restartable system calls""... $ac_c" 1>&6 +echo "configure:3879: checking for restartable system calls" >&5 +if eval "test \"`echo '$''{'ac_cv_sys_restartable_syscalls'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test "$cross_compiling" = yes; then + { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; } +else + cat > conftest.$ac_ext < +#include +ucatch (isig) { } +main () { + int i = fork (), status; + if (i == 0) { sleep (3); kill (getppid (), SIGINT); sleep (3); exit (0); } + signal (SIGINT, ucatch); + status = wait(&i); + if (status == -1) wait(&i); + exit (status == -1); +} + +EOF +if { (eval echo configure:3905: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null +then + ac_cv_sys_restartable_syscalls=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + ac_cv_sys_restartable_syscalls=no +fi +rm -fr conftest* +fi + +fi + +echo "$ac_t""$ac_cv_sys_restartable_syscalls" 1>&6 +if test $ac_cv_sys_restartable_syscalls = yes; then + cat >> confdefs.h <<\EOF +#define HAVE_RESTARTABLE_SYSCALLS 1 +EOF + +fi + + +if test "$ac_cv_func_lstat" = "no"; then +echo $ac_n "checking for lstat""... $ac_c" 1>&6 +echo "configure:3930: checking for lstat" >&5 +if eval "test \"`echo '$''{'bash_cv_func_lstat'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +#include + +int main() { + lstat("",(struct stat *)0); +; return 0; } +EOF +if { (eval echo configure:3945: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then + rm -rf conftest* + bash_cv_func_lstat=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + bash_cv_func_lstat=no +fi +rm -f conftest* +fi + +echo "$ac_t""$bash_cv_func_lstat" 1>&6 +if test $bash_cv_func_lstat = yes; then + cat >> confdefs.h <<\EOF +#define HAVE_LSTAT 1 +EOF + +fi + +fi + +echo $ac_n "checking if dup2 fails to clear the close-on-exec flag""... $ac_c" 1>&6 +echo "configure:3968: checking if dup2 fails to clear the close-on-exec flag" >&5 +if eval "test \"`echo '$''{'bash_cv_dup2_broken'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test "$cross_compiling" = yes; then + { echo "configure: error: cannot check dup2 if cross compiling" 1>&2; exit 1; } +else + cat > conftest.$ac_ext < +#include +main() +{ + int fd1, fd2, fl; + fd1 = open("/dev/null", 2); + if (fcntl(fd1, 2, 1) < 0) + exit(1); + fd2 = dup2(fd1, 1); + if (fd2 < 0) + exit(2); + fl = fcntl(fd2, 1, 0); + /* fl will be 1 if dup2 did not reset the close-on-exec flag. */ + exit(fl != 1); +} + +EOF +if { (eval echo configure:3996: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null +then + bash_cv_dup2_broken=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + bash_cv_dup2_broken=no +fi +rm -fr conftest* +fi + + +fi + +echo "$ac_t""$bash_cv_dup2_broken" 1>&6 +if test $bash_cv_dup2_broken = yes; then +cat >> confdefs.h <<\EOF +#define DUP2_BROKEN 1 +EOF + +fi + + +echo $ac_n "checking whether pgrps need synchronization""... $ac_c" 1>&6 +echo "configure:4021: checking whether pgrps need synchronization" >&5 +if eval "test \"`echo '$''{'bash_cv_pgrp_pipe'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test "$cross_compiling" = yes; then + { echo "configure: error: cannot check pgrp synchronization if cross compiling" 1>&2; exit 1; } +else + cat > conftest.$ac_ext < +#endif +main() +{ +# ifdef GETPGRP_VOID +# define getpgID() getpgrp() +# else +# define getpgID() getpgrp(0) +# define setpgid(x,y) setpgrp(x,y) +# endif + int pid1, pid2, fds[2]; + int status; + char ok; + + switch (pid1 = fork()) { + case -1: + exit(1); + case 0: + setpgid(0, getpid()); + exit(0); + } + setpgid(pid1, pid1); + + sleep(2); /* let first child die */ + + if (pipe(fds) < 0) + exit(2); + + switch (pid2 = fork()) { + case -1: + exit(3); + case 0: + setpgid(0, pid1); + ok = getpgID() == pid1; + write(fds[1], &ok, 1); + exit(0); + } + setpgid(pid2, pid1); + + close(fds[1]); + if (read(fds[0], &ok, 1) != 1) + exit(4); + wait(&status); + wait(&status); + exit(ok ? 0 : 5); +} + +EOF +if { (eval echo configure:4081: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null +then + bash_cv_pgrp_pipe=no +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + bash_cv_pgrp_pipe=yes +fi +rm -fr conftest* +fi + + +fi + +echo "$ac_t""$bash_cv_pgrp_pipe" 1>&6 +if test $bash_cv_pgrp_pipe = yes; then +cat >> confdefs.h <<\EOF +#define PGRP_PIPE 1 +EOF + +fi + +echo $ac_n "checking for sys_errlist and sys_nerr""... $ac_c" 1>&6 +echo "configure:4105: checking for sys_errlist and sys_nerr" >&5 +if eval "test \"`echo '$''{'bash_cv_sys_errlist'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +int main() { +extern char *sys_errlist[]; + extern int sys_nerr; + char *msg = sys_errlist[sys_nerr - 1]; +; return 0; } +EOF +if { (eval echo configure:4119: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then + rm -rf conftest* + bash_cv_sys_errlist=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + bash_cv_sys_errlist=no +fi +rm -f conftest* +fi +echo "$ac_t""$bash_cv_sys_errlist" 1>&6 +if test $bash_cv_sys_errlist = yes; then +cat >> confdefs.h <<\EOF +#define HAVE_SYS_ERRLIST 1 +EOF + +fi + + +echo $ac_n "checking for sys_siglist in system C library""... $ac_c" 1>&6 +echo "configure:4140: checking for sys_siglist in system C library" >&5 +if eval "test \"`echo '$''{'bash_cv_sys_siglist'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test "$cross_compiling" = yes; then + { echo "configure: error: cannot check for sys_siglist if cross compiling" 1>&2; exit 1; } +else + cat > conftest.$ac_ext < +#include +#ifdef HAVE_UNISTD_H +#include +#endif +#ifndef SYS_SIGLIST_DECLARED +extern char *sys_siglist[]; +#endif +main() +{ +char *msg = sys_siglist[2]; +exit(msg == 0); +} +EOF +if { (eval echo configure:4165: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null +then + bash_cv_sys_siglist=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + bash_cv_sys_siglist=no +fi +rm -fr conftest* +fi + +fi +echo "$ac_t""$bash_cv_sys_siglist" 1>&6 +if test $bash_cv_sys_siglist = yes; then +cat >> confdefs.h <<\EOF +#define HAVE_SYS_SIGLIST 1 +EOF + +fi + +echo $ac_n "checking for _sys_siglist in system C library""... $ac_c" 1>&6 +echo "configure:4187: checking for _sys_siglist in system C library" >&5 +if eval "test \"`echo '$''{'bash_cv_under_sys_siglist'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test "$cross_compiling" = yes; then + { echo "configure: error: cannot check for _sys_siglist if cross compiling" 1>&2; exit 1; } +else + cat > conftest.$ac_ext < +#include +#ifdef HAVE_UNISTD_H +#include +#endif +#ifndef _sys_siglist +extern char *_sys_siglist[]; +#endif +main() +{ +char *msg = _sys_siglist[2]; +exit(msg == 0); +} +EOF +if { (eval echo configure:4212: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null +then + bash_cv_under_sys_siglist=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + bash_cv_under_sys_siglist=no +fi +rm -fr conftest* +fi + +fi +echo "$ac_t""$bash_cv_under_sys_siglist" 1>&6 +if test $bash_cv_under_sys_siglist = yes; then +cat >> confdefs.h <<\EOF +#define HAVE_UNDER_SYS_SIGLIST 1 +EOF + +fi + + +echo $ac_n "checking for type of signal functions""... $ac_c" 1>&6 +echo "configure:4235: checking for type of signal functions" >&5 +if eval "test \"`echo '$''{'bash_cv_signal_vintage'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + + cat > conftest.$ac_ext < +int main() { + + sigset_t ss; + struct sigaction sa; + sigemptyset(&ss); sigsuspend(&ss); + sigaction(SIGINT, &sa, (struct sigaction *) 0); + sigprocmask(SIG_BLOCK, &ss, (sigset_t *) 0); + +; return 0; } +EOF +if { (eval echo configure:4254: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then + rm -rf conftest* + bash_cv_signal_vintage=posix +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + + cat > conftest.$ac_ext < +int main() { + + int mask = sigmask(SIGINT); + sigsetmask(mask); sigblock(mask); sigpause(mask); + +; return 0; } +EOF +if { (eval echo configure:4273: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then + rm -rf conftest* + bash_cv_signal_vintage=4.2bsd +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + + cat > conftest.$ac_ext < + RETSIGTYPE foo() { } +int main() { + + int mask = sigmask(SIGINT); + sigset(SIGINT, foo); sigrelse(SIGINT); + sighold(SIGINT); sigpause(SIGINT); + +; return 0; } +EOF +if { (eval echo configure:4295: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then + rm -rf conftest* + bash_cv_signal_vintage=svr3 +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + bash_cv_signal_vintage=v7 + +fi +rm -f conftest* + +fi +rm -f conftest* + +fi +rm -f conftest* + +fi + +echo "$ac_t""$bash_cv_signal_vintage" 1>&6 +if test "$bash_cv_signal_vintage" = posix; then +cat >> confdefs.h <<\EOF +#define HAVE_POSIX_SIGNALS 1 +EOF + +elif test "$bash_cv_signal_vintage" = "4.2bsd"; then +cat >> confdefs.h <<\EOF +#define HAVE_BSD_SIGNALS 1 +EOF + +elif test "$bash_cv_signal_vintage" = svr3; then +cat >> confdefs.h <<\EOF +#define HAVE_USG_SIGHOLD 1 +EOF + +fi + +echo $ac_n "checking whether signal handlers are of type void""... $ac_c" 1>&6 +echo "configure:4334: checking whether signal handlers are of type void" >&5 +if eval "test \"`echo '$''{'bash_cv_void_sighandler'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +#include +#ifdef signal +#undef signal +#endif +#ifdef __cplusplus +extern "C" +#endif +void (*signal ()) (); +int main() { +int i; +; return 0; } +EOF +if { (eval echo configure:4354: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + bash_cv_void_sighandler=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + bash_cv_void_sighandler=no +fi +rm -f conftest* +fi +echo "$ac_t""$bash_cv_void_sighandler" 1>&6 +if test $bash_cv_void_sighandler = yes; then +cat >> confdefs.h <<\EOF +#define VOID_SIGHANDLER 1 +EOF + +fi + +echo $ac_n "checking for clock_t""... $ac_c" 1>&6 +echo "configure:4374: checking for clock_t" >&5 +if eval "test \"`echo '$''{'bash_cv_type_clock_t'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +#if STDC_HEADERS +#include +#endif +#include + +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "clock_t" >/dev/null 2>&1; then + rm -rf conftest* + bash_cv_type_clock_t=yes +else + rm -rf conftest* + bash_cv_type_clock_t=no +fi +rm -f conftest* + +fi + +echo "$ac_t""$bash_cv_type_clock_t" 1>&6 + +if test $bash_cv_type_clock_t = no; then + cat >> confdefs.h <<\EOF +#define clock_t long +EOF + +fi + +echo $ac_n "checking for sigset_t""... $ac_c" 1>&6 +echo "configure:4410: checking for sigset_t" >&5 +if eval "test \"`echo '$''{'bash_cv_type_sigset_t'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +#if STDC_HEADERS +#include +#endif +#include + +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "sigset_t" >/dev/null 2>&1; then + rm -rf conftest* + bash_cv_type_sigset_t=yes +else + rm -rf conftest* + bash_cv_type_sigset_t=no +fi +rm -f conftest* + +fi + +echo "$ac_t""$bash_cv_type_sigset_t" 1>&6 + +if test $bash_cv_type_sigset_t = no; then + cat >> confdefs.h <<\EOF +#define sigset_t int +EOF + +fi + +echo $ac_n "checking for quad_t""... $ac_c" 1>&6 +echo "configure:4446: checking for quad_t" >&5 +if eval "test \"`echo '$''{'bash_cv_type_quad_t'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +#if STDC_HEADERS +#include +#endif + + +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "quad_t" >/dev/null 2>&1; then + rm -rf conftest* + bash_cv_type_quad_t=yes +else + rm -rf conftest* + bash_cv_type_quad_t=no +fi +rm -f conftest* + +fi + +echo "$ac_t""$bash_cv_type_quad_t" 1>&6 +if test $bash_cv_type_quad_t = yes; then + cat >> confdefs.h <<\EOF +#define HAVE_QUAD_T 1 +EOF + + fi +if test $bash_cv_type_quad_t = no; then + cat >> confdefs.h <<\EOF +#define quad_t long +EOF + +fi + +echo $ac_n "checking for size and type of struct rlimit fields""... $ac_c" 1>&6 +echo "configure:4487: checking for size and type of struct rlimit fields" >&5 +if eval "test \"`echo '$''{'bash_cv_type_rlimit'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +int main() { +rlim_t xxx; +; return 0; } +EOF +if { (eval echo configure:4499: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + bash_cv_type_rlimit=rlim_t +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + +if test "$cross_compiling" = yes; then + { echo "configure: error: cannot check quad_t if cross compiling" 1>&2; exit 1; } +else + cat > conftest.$ac_ext < +#include +#include +main() +{ +#ifdef HAVE_QUAD_T + struct rlimit rl; + if (sizeof(rl.rlim_cur) == sizeof(quad_t)) + exit(0); +#endif + exit(1); +} +EOF +if { (eval echo configure:4527: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null +then + bash_cv_type_rlimit=quad_t +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + bash_cv_type_rlimit=long +fi +rm -fr conftest* +fi + +fi +rm -f conftest* + +fi + +echo "$ac_t""$bash_cv_type_rlimit" 1>&6 +if test $bash_cv_type_rlimit = quad_t; then +cat >> confdefs.h <<\EOF +#define RLIMTYPE quad_t +EOF + +elif test $bash_cv_type_rlimit = rlim_t; then +cat >> confdefs.h <<\EOF +#define RLIMTYPE rlim_t +EOF + +fi + +echo $ac_n "checking for a c_line member of struct termios""... $ac_c" 1>&6 +echo "configure:4558: checking for a c_line member of struct termios" >&5 +if eval "test \"`echo '$''{'bash_cv_termios_ldisc'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +#include +int main() { +struct termios t; int i; i = t.c_line; +; return 0; } +EOF +if { (eval echo configure:4571: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + bash_cv_termios_ldisc=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + bash_cv_termios_ldisc=no +fi +rm -f conftest* +fi +echo "$ac_t""$bash_cv_termios_ldisc" 1>&6 +if test $bash_cv_termios_ldisc = yes; then +cat >> confdefs.h <<\EOF +#define TERMIOS_LDISC 1 +EOF + +fi + +echo $ac_n "checking for a c_line member of struct termio""... $ac_c" 1>&6 +echo "configure:4591: checking for a c_line member of struct termio" >&5 +if eval "test \"`echo '$''{'bash_cv_termio_ldisc'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +#include +int main() { +struct termio t; int i; i = t.c_line; +; return 0; } +EOF +if { (eval echo configure:4604: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + bash_cv_termio_ldisc=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + bash_cv_termio_ldisc=no +fi +rm -f conftest* +fi +echo "$ac_t""$bash_cv_termio_ldisc" 1>&6 +if test $bash_cv_termio_ldisc = yes; then +cat >> confdefs.h <<\EOF +#define TERMIO_LDISC 1 +EOF + +fi + + +echo $ac_n "checking if struct dirent has a d_ino member""... $ac_c" 1>&6 +echo "configure:4625: checking if struct dirent has a d_ino member" >&5 +if eval "test \"`echo '$''{'bash_cv_dirent_has_dino'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +#include +#ifdef HAVE_UNISTD_H +# include +#endif /* HAVE_UNISTD_H */ +#if defined(HAVE_DIRENT_H) +# include +#else +# define dirent direct +# ifdef HAVE_SYS_NDIR_H +# include +# endif /* SYSNDIR */ +# ifdef HAVE_SYS_DIR_H +# include +# endif /* SYSDIR */ +# ifdef HAVE_NDIR_H +# include +# endif +#endif /* HAVE_DIRENT_H */ + +int main() { + +struct dirent d; int z; z = d.d_ino; + +; return 0; } +EOF +if { (eval echo configure:4659: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + bash_cv_dirent_has_dino=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + bash_cv_dirent_has_dino=no +fi +rm -f conftest* +fi + +echo "$ac_t""$bash_cv_dirent_has_dino" 1>&6 +if test $bash_cv_dirent_has_dino = yes; then +cat >> confdefs.h <<\EOF +#define STRUCT_DIRENT_HAS_D_INO 1 +EOF + +fi + +echo $ac_n "checking for the existance of strsignal""... $ac_c" 1>&6 +echo "configure:4680: checking for the existance of strsignal" >&5 +if eval "test \"`echo '$''{'bash_cv_have_strsignal'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +#include +int main() { +char *s = (char *)strsignal(2); +; return 0; } +EOF +if { (eval echo configure:4693: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then + rm -rf conftest* + bash_cv_have_strsignal=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + bash_cv_have_strsignal=no +fi +rm -f conftest* +fi + +echo "$ac_t""$bash_cv_have_strsignal" 1>&6 +if test $bash_cv_have_strsignal = yes; then +cat >> confdefs.h <<\EOF +#define HAVE_STRSIGNAL 1 +EOF + +fi + +echo $ac_n "checking if opendir() opens non-directories""... $ac_c" 1>&6 +echo "configure:4714: checking if opendir() opens non-directories" >&5 +if eval "test \"`echo '$''{'bash_cv_opendir_not_robust'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test "$cross_compiling" = yes; then + { echo "configure: error: cannot check opendir if cross compiling" 1>&2; exit 1; } +else + cat > conftest.$ac_ext < +#include +#include +#ifdef HAVE_UNISTD_H +# include +#endif /* HAVE_UNISTD_H */ +#if defined(HAVE_DIRENT_H) +# include +#else +# define dirent direct +# ifdef HAVE_SYS_NDIR_H +# include +# endif /* SYSNDIR */ +# ifdef HAVE_SYS_DIR_H +# include +# endif /* SYSDIR */ +# ifdef HAVE_NDIR_H +# include +# endif +#endif /* HAVE_DIRENT_H */ +main() +{ +DIR *dir; +int fd; +unlink("/tmp/not_a_directory"); +fd = open("/tmp/not_a_directory", O_WRONLY|O_CREAT, 0666); +write(fd, "\n", 1); +close(fd); +dir = opendir("/tmp/not_a_directory"); +unlink("/tmp/not_a_directory"); +exit (dir == 0); +} +EOF +if { (eval echo configure:4758: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null +then + bash_cv_opendir_not_robust=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + bash_cv_opendir_not_robust=no +fi +rm -fr conftest* +fi + +fi + +echo "$ac_t""$bash_cv_opendir_not_robust" 1>&6 +if test $bash_cv_opendir_not_robust = yes; then +cat >> confdefs.h <<\EOF +#define OPENDIR_NOT_ROBUST 1 +EOF + +fi + +echo $ac_n "checking for declaration of printf in ""... $ac_c" 1>&6 +echo "configure:4781: checking for declaration of printf in " >&5 +if eval "test \"`echo '$''{'bash_cv_printf_declared'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test "$cross_compiling" = yes; then + { echo "configure: error: cannot check printf declaration if cross compiling" 1>&2; exit 1; } +else + cat > conftest.$ac_ext < +#ifdef __STDC__ +typedef int (*_bashfunc)(const char *, ...); +#else +typedef int (*_bashfunc)(); +#endif +main() +{ +_bashfunc pf; +pf = printf; +exit(pf == 0); +} + +EOF +if { (eval echo configure:4806: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null +then + bash_cv_printf_declared=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + bash_cv_printf_declared=no +fi +rm -fr conftest* +fi + +fi + +echo "$ac_t""$bash_cv_printf_declared" 1>&6 +if test $bash_cv_printf_declared = yes; then +cat >> confdefs.h <<\EOF +#define PRINTF_DECLARED 1 +EOF + +fi + +echo $ac_n "checking whether ulimit can substitute for getdtablesize""... $ac_c" 1>&6 +echo "configure:4829: checking whether ulimit can substitute for getdtablesize" >&5 +if eval "test \"`echo '$''{'bash_cv_ulimit_maxfds'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test "$cross_compiling" = yes; then + { echo "configure: error: cannot check ulimit if cross compiling" 1>&2; exit 1; } +else + cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null +then + bash_cv_ulimit_maxfds=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + bash_cv_ulimit_maxfds=no +fi +rm -fr conftest* +fi + +fi + +echo "$ac_t""$bash_cv_ulimit_maxfds" 1>&6 +if test $bash_cv_ulimit_maxfds = yes; then +cat >> confdefs.h <<\EOF +#define ULIMIT_MAXFDS 1 +EOF + +fi + +echo $ac_n "checking to see if getenv can be redefined""... $ac_c" 1>&6 +echo "configure:4870: checking to see if getenv can be redefined" >&5 +if eval "test \"`echo '$''{'bash_cv_getenv_redef'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test "$cross_compiling" = yes; then + { echo "configure: error: cannot check getenv redefinition if cross compiling" 1>&2; exit 1; } +else + cat > conftest.$ac_ext < +#endif +#ifndef __STDC__ +# ifndef const +# define const +# endif +#endif +char * +getenv (name) +#if defined (__linux__) || defined (__bsdi__) || defined (convex) + const char *name; +#else + char const *name; +#endif /* !__linux__ && !__bsdi__ && !convex */ +{ +return "42"; +} +main() +{ +char *s; +/* The next allows this program to run, but does not allow bash to link + when it redefines getenv. I'm not really interested in figuring out + why not. */ +#if defined (NeXT) +exit(1); +#endif +s = getenv("ABCDE"); +exit(s == 0); /* force optimizer to leave getenv in */ +} + +EOF +if { (eval echo configure:4913: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null +then + bash_cv_getenv_redef=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + bash_cv_getenv_redef=no +fi +rm -fr conftest* +fi + +fi + +echo "$ac_t""$bash_cv_getenv_redef" 1>&6 +if test $bash_cv_getenv_redef = yes; then +cat >> confdefs.h <<\EOF +#define CAN_REDEFINE_GETENV 1 +EOF + +fi + +echo $ac_n "checking if getcwd() calls popen()""... $ac_c" 1>&6 +echo "configure:4936: checking if getcwd() calls popen()" >&5 +if eval "test \"`echo '$''{'bash_cv_getcwd_calls_popen'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test "$cross_compiling" = yes; then + { echo "configure: error: cannot check whether getcwd calls popen if cross compiling" 1>&2; exit 1; } +else + cat > conftest.$ac_ext < +#ifdef HAVE_UNISTD_H +#include +#endif + +#ifndef __STDC__ +#ifndef const +#define const +#endif +#endif + +int popen_called; + +FILE * +popen(command, type) + const char *command; + const char *type; +{ + popen_called = 1; + return (FILE *)NULL; +} + +FILE *_popen(command, type) + const char *command; + const char *type; +{ + return (popen (command, type)); +} + +int +pclose(stream) +FILE *stream; +{ + return 0; +} + +int +_pclose(stream) +FILE *stream; +{ + return 0; +} + +main() +{ + char lbuf[32]; + popen_called = 0; + getcwd(lbuf, 32); + exit (popen_called); +} + +EOF +if { (eval echo configure:4999: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null +then + bash_cv_getcwd_calls_popen=no +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + bash_cv_getcwd_calls_popen=yes +fi +rm -fr conftest* +fi + +fi + +echo "$ac_t""$bash_cv_getcwd_calls_popen" 1>&6 +if test $bash_cv_getcwd_calls_popen = yes; then +cat >> confdefs.h <<\EOF +#define GETCWD_BROKEN 1 +EOF + +fi + +echo $ac_n "checking for declaration of sbrk in ""... $ac_c" 1>&6 +echo "configure:5022: checking for declaration of sbrk in " >&5 +if eval "test \"`echo '$''{'bash_cv_sbrk_declared'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "sbrk" >/dev/null 2>&1; then + rm -rf conftest* + bash_cv_sbrk_declared=yes +else + rm -rf conftest* + bash_cv_sbrk_declared=no +fi +rm -f conftest* + +fi + +echo "$ac_t""$bash_cv_sbrk_declared" 1>&6 +if test $bash_cv_sbrk_declared = yes; then +cat >> confdefs.h <<\EOF +#define SBRK_DECLARED 1 +EOF + +fi + + +echo $ac_n "checking for presence of POSIX-style sigsetjmp/siglongjmp""... $ac_c" 1>&6 +echo "configure:5053: checking for presence of POSIX-style sigsetjmp/siglongjmp" >&5 +if eval "test \"`echo '$''{'bash_cv_func_sigsetjmp'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test "$cross_compiling" = yes; then + { echo "configure: error: cannot check for sigsetjmp/siglongjmp if cross-compiling" 1>&2; exit 1; } +else + cat > conftest.$ac_ext < +#endif +#include +#include +#include + +main() +{ +#if !defined (_POSIX_VERSION) || !defined (HAVE_POSIX_SIGNALS) +exit (1); +#else + +int code; +sigset_t set, oset; +sigjmp_buf xx; + +/* get the mask */ +sigemptyset(&set); +sigemptyset(&oset); +sigprocmask(SIG_BLOCK, (sigset_t *)NULL, &set); +sigprocmask(SIG_BLOCK, (sigset_t *)NULL, &oset); + +/* save it */ +code = sigsetjmp(xx, 1); +if (code) + exit(0); /* could get sigmask and compare to oset here. */ + +/* change it */ +sigaddset(&set, SIGINT); +sigprocmask(SIG_BLOCK, &set, (sigset_t *)NULL); + +/* and siglongjmp */ +siglongjmp(xx, 10); +exit(1); +#endif +} +EOF +if { (eval echo configure:5102: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null +then + bash_cv_func_sigsetjmp=present +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + bash_cv_func_sigsetjmp=missing +fi +rm -fr conftest* +fi + + +fi + +echo "$ac_t""$bash_cv_func_sigsetjmp" 1>&6 +if test $bash_cv_func_sigsetjmp = present; then +cat >> confdefs.h <<\EOF +#define HAVE_POSIX_SIGSETJMP 1 +EOF + +fi + + + +echo $ac_n "checking if signal handlers must be reinstalled when invoked""... $ac_c" 1>&6 +echo "configure:5128: checking if signal handlers must be reinstalled when invoked" >&5 +if eval "test \"`echo '$''{'bash_cv_must_reinstall_sighandlers'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test "$cross_compiling" = yes; then + { echo "configure: error: cannot check signal handling if cross compiling" 1>&2; exit 1; } +else + cat > conftest.$ac_ext < +#ifdef HAVE_UNISTD_H +#include +#endif + +typedef RETSIGTYPE sigfunc(); + +int nsigint; + +#ifdef HAVE_POSIX_SIGNALS +sigfunc * +set_signal_handler(sig, handler) + int sig; + sigfunc *handler; +{ + struct sigaction act, oact; + act.sa_handler = handler; + act.sa_flags = 0; + sigemptyset (&act.sa_mask); + sigemptyset (&oact.sa_mask); + sigaction (sig, &act, &oact); + return (oact.sa_handler); +} +#else +#define set_signal_handler(s, h) signal(s, h) +#endif + +RETSIGTYPE +sigint(s) +int s; +{ + nsigint++; +} + +main() +{ + nsigint = 0; + set_signal_handler(SIGINT, sigint); + kill((int)getpid(), SIGINT); + kill((int)getpid(), SIGINT); + exit(nsigint != 2); +} + +EOF +if { (eval echo configure:5183: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null +then + bash_cv_must_reinstall_sighandlers=no +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + bash_cv_must_reinstall_sighandlers=yes +fi +rm -fr conftest* +fi + +fi + +echo "$ac_t""$bash_cv_must_reinstall_sighandlers" 1>&6 +if test $bash_cv_must_reinstall_sighandlers = yes; then +cat >> confdefs.h <<\EOF +#define MUST_REINSTALL_SIGHANDLERS 1 +EOF + +fi + + +echo $ac_n "checking for presence of necessary job control definitions""... $ac_c" 1>&6 +echo "configure:5207: checking for presence of necessary job control definitions" >&5 +if eval "test \"`echo '$''{'bash_cv_job_control_missing'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test "$cross_compiling" = yes; then + { echo "configure: error: cannot check job control if cross-compiling" 1>&2; exit 1; } +else + cat > conftest.$ac_ext < +#ifdef HAVE_SYS_WAIT_H +#include +#endif +#ifdef HAVE_UNISTD_H +#include +#endif +#include + +/* Add more tests in here as appropriate. */ +main() +{ +/* signal type */ +#if !defined (HAVE_POSIX_SIGNALS) && !defined (HAVE_BSD_SIGNALS) +exit(1); +#endif + +/* signals and tty control. */ +#if !defined (SIGTSTP) || !defined (SIGSTOP) || !defined (SIGCONT) +exit (1); +#endif + +/* process control */ +#if !defined (WNOHANG) || !defined (WUNTRACED) +exit(1); +#endif + +/* Posix systems have tcgetpgrp and waitpid. */ +#if defined (_POSIX_VERSION) && !defined (HAVE_TCGETPGRP) +exit(1); +#endif + +#if defined (_POSIX_VERSION) && !defined (HAVE_WAITPID) +exit(1); +#endif + +/* Other systems have TIOCSPGRP/TIOCGPRGP and wait3. */ +#if !defined (_POSIX_VERSION) && !defined (HAVE_WAIT3) +exit(1); +#endif + +exit(0); +} +EOF +if { (eval echo configure:5262: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null +then + bash_cv_job_control_missing=present +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + bash_cv_job_control_missing=missing +fi +rm -fr conftest* +fi + + +fi + +echo "$ac_t""$bash_cv_job_control_missing" 1>&6 +if test $bash_cv_job_control_missing = missing; then +cat >> confdefs.h <<\EOF +#define JOB_CONTROL_MISSING 1 +EOF + +fi + +echo $ac_n "checking for presence of named pipes""... $ac_c" 1>&6 +echo "configure:5286: checking for presence of named pipes" >&5 +if eval "test \"`echo '$''{'bash_cv_sys_named_pipes'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test "$cross_compiling" = yes; then + { echo "configure: error: cannot check for named pipes if cross-compiling" 1>&2; exit 1; } +else + cat > conftest.$ac_ext < +#include +#ifdef HAVE_UNISTD_H +#include +#endif + +/* Add more tests in here as appropriate. */ +main() +{ +int fd; + +#if defined (HAVE_MKFIFO) +exit (0); +#endif + +#if !defined (S_IFIFO) && (defined (_POSIX_VERSION) && !defined (S_ISFIFO)) +exit (1); +#endif + +#if defined (NeXT) +exit (1); +#endif + +fd = mknod ("/tmp/sh-np-autoconf", 0666 | S_IFIFO, 0); +if (fd == -1) + exit (1); +close(fd); +unlink ("/tmp/sh-np-autoconf"); +exit(0); +} +EOF +if { (eval echo configure:5328: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null +then + bash_cv_sys_named_pipes=present +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + bash_cv_sys_named_pipes=missing +fi +rm -fr conftest* +fi + + +fi + +echo "$ac_t""$bash_cv_sys_named_pipes" 1>&6 +if test $bash_cv_sys_named_pipes = missing; then +cat >> confdefs.h <<\EOF +#define NAMED_PIPES_MISSING 1 +EOF + +fi + +echo $ac_n "checking for TIOCGWINSZ in sys/ioctl.h""... $ac_c" 1>&6 +echo "configure:5352: checking for TIOCGWINSZ in sys/ioctl.h" >&5 +if eval "test \"`echo '$''{'bash_cv_tiocgwinsz_in_ioctl'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +#include +int main() { +int x = TIOCGWINSZ; +; return 0; } +EOF +if { (eval echo configure:5365: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + bash_cv_tiocgwinsz_in_ioctl=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + bash_cv_tiocgwinsz_in_ioctl=no +fi +rm -f conftest* +fi + +echo "$ac_t""$bash_cv_tiocgwinsz_in_ioctl" 1>&6 +if test $bash_cv_tiocgwinsz_in_ioctl = yes; then +cat >> confdefs.h <<\EOF +#define GWINSZ_IN_SYS_IOCTL 1 +EOF + +fi + +echo $ac_n "checking for TIOCSTAT in sys/ioctl.h""... $ac_c" 1>&6 +echo "configure:5386: checking for TIOCSTAT in sys/ioctl.h" >&5 +if eval "test \"`echo '$''{'bash_cv_tiocstat_in_ioctl'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +#include +int main() { +int x = TIOCSTAT; +; return 0; } +EOF +if { (eval echo configure:5399: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + bash_cv_tiocstat_in_ioctl=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + bash_cv_tiocstat_in_ioctl=no +fi +rm -f conftest* +fi + +echo "$ac_t""$bash_cv_tiocstat_in_ioctl" 1>&6 +if test $bash_cv_tiocstat_in_ioctl = yes; then +cat >> confdefs.h <<\EOF +#define TIOCSTAT_IN_SYS_IOCTL 1 +EOF + +fi + +echo $ac_n "checking for FIONREAD in sys/ioctl.h""... $ac_c" 1>&6 +echo "configure:5420: checking for FIONREAD in sys/ioctl.h" >&5 +if eval "test \"`echo '$''{'bash_cv_fionread_in_ioctl'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +#include +int main() { +int x = FIONREAD; +; return 0; } +EOF +if { (eval echo configure:5433: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + bash_cv_fionread_in_ioctl=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + bash_cv_fionread_in_ioctl=no +fi +rm -f conftest* +fi + +echo "$ac_t""$bash_cv_fionread_in_ioctl" 1>&6 +if test $bash_cv_fionread_in_ioctl = yes; then +cat >> confdefs.h <<\EOF +#define FIONREAD_IN_SYS_IOCTL 1 +EOF + +fi + +echo $ac_n "checking whether programs are able to redeclare getpw functions""... $ac_c" 1>&6 +echo "configure:5454: checking whether programs are able to redeclare getpw functions" >&5 +if eval "test \"`echo '$''{'bash_cv_can_redecl_getpw'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +#include +extern struct passwd *getpwent(); +int main() { +struct passwd *z; z = getpwent(); +; return 0; } +EOF +if { (eval echo configure:5468: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + bash_cv_can_redecl_getpw=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + bash_cv_can_redecl_getpw=no +fi +rm -f conftest* +fi + +echo "$ac_t""$bash_cv_can_redecl_getpw" 1>&6 +if test $bash_cv_can_redecl_getpw = no; then +cat >> confdefs.h <<\EOF +#define HAVE_GETPW_DECLS 1 +EOF + +fi + +echo $ac_n "checking whether /dev/fd is available""... $ac_c" 1>&6 +echo "configure:5489: checking whether /dev/fd is available" >&5 +if eval "test \"`echo '$''{'bash_cv_dev_fd'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -d /dev/fd && test -r /dev/fd/0; then + bash_cv_dev_fd=standard + elif test -d /proc/self/fd && test -r /proc/self/fd/0; then + bash_cv_dev_fd=whacky + else + bash_cv_dev_fd=absent + fi + +fi + +echo "$ac_t""$bash_cv_dev_fd" 1>&6 +if test $bash_cv_dev_fd = "standard"; then + cat >> confdefs.h <<\EOF +#define HAVE_DEV_FD 1 +EOF + + cat >> confdefs.h <<\EOF +#define DEV_FD_PREFIX "/dev/fd/" +EOF + +elif test $bash_cv_dev_fd = "whacky"; then + cat >> confdefs.h <<\EOF +#define HAVE_DEV_FD 1 +EOF + + cat >> confdefs.h <<\EOF +#define DEV_FD_PREFIX "/proc/self/fd/" +EOF + +fi + + +case "$host_os" in +hpux*) echo $ac_n "checking whether $host_os needs _KERNEL for RLIMIT defines""... $ac_c" 1>&6 +echo "configure:5527: checking whether $host_os needs _KERNEL for RLIMIT defines" >&5 +if eval "test \"`echo '$''{'bash_cv_kernel_rlimit'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +#include + +int main() { + + int f; + f = RLIMIT_DATA; + +; return 0; } +EOF +if { (eval echo configure:5545: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + bash_cv_kernel_rlimit=no +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + cat > conftest.$ac_ext < + #define _KERNEL + #include + #undef _KERNEL + +int main() { + + int f; + f = RLIMIT_DATA; + +; return 0; } +EOF +if { (eval echo configure:5568: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + bash_cv_kernel_rlimit=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + bash_cv_kernel_rlimit=no +fi +rm -f conftest* + +fi +rm -f conftest* +fi + +echo "$ac_t""$bash_cv_kernel_rlimit" 1>&6 +if test $bash_cv_kernel_rlimit = yes; then +cat >> confdefs.h <<\EOF +#define RLIMIT_NEEDS_KERNEL 1 +EOF + +fi + ;; +esac + +if test "$opt_readline" = yes; then + +if test "X$bash_cv_termcap_lib" = "X"; then +_bash_needmsg=yes +else +echo $ac_n "checking which library has the termcap functions""... $ac_c" 1>&6 +echo "configure:5599: checking which library has the termcap functions" >&5 +_bash_needmsg= +fi +if eval "test \"`echo '$''{'bash_cv_termcap_lib'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + echo $ac_n "checking for tgetent in -ltermcap""... $ac_c" 1>&6 +echo "configure:5606: checking for tgetent in -ltermcap" >&5 +ac_lib_var=`echo termcap'_'tgetent | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-ltermcap $LIBS" +cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + bash_cv_termcap_lib=libtermcap +else + echo "$ac_t""no" 1>&6 +echo $ac_n "checking for tgetent in -lcurses""... $ac_c" 1>&6 +echo "configure:5644: checking for tgetent in -lcurses" >&5 +ac_lib_var=`echo curses'_'tgetent | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-lcurses $LIBS" +cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + bash_cv_termcap_lib=libcurses +else + echo "$ac_t""no" 1>&6 +echo $ac_n "checking for tgetent in -lncurses""... $ac_c" 1>&6 +echo "configure:5682: checking for tgetent in -lncurses" >&5 +ac_lib_var=`echo ncurses'_'tgetent | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-lncurses $LIBS" +cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + bash_cv_termcap_lib=libncurses +else + echo "$ac_t""no" 1>&6 +bash_cv_termcap_lib=gnutermcap +fi + +fi + +fi + +fi + +if test "X$_bash_needmsg" = "Xyes"; then +echo $ac_n "checking which library has the termcap functions""... $ac_c" 1>&6 +echo "configure:5730: checking which library has the termcap functions" >&5 +fi +echo "$ac_t""using $bash_cv_termcap_lib" 1>&6 +if test $bash_cv_termcap_lib = gnutermcap; then +LDFLAGS="$LDFLAGS -L./lib/termcap" +TERMCAP_LIB="./lib/termcap/libtermcap.a" +TERMCAP_DEP="./lib/termcap/libtermcap.a" +elif test $bash_cv_termcap_lib = libtermcap; then +TERMCAP_LIB=-ltermcap +TERMCAP_DEP= +elif test $bash_cv_termcap_lib = libncurses; then +TERMCAP_LIB=-lncurses +TERMCAP_DEP= +else +TERMCAP_LIB=-lcurses +TERMCAP_DEP= +fi + +fi + + + +echo $ac_n "checking for default mail directory""... $ac_c" 1>&6 +echo "configure:5753: checking for default mail directory" >&5 +if eval "test \"`echo '$''{'bash_cv_mail_dir'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -d /var/mail; then + bash_cv_mail_dir=/var/mail + elif test -d /usr/mail; then + bash_cv_mail_dir=/usr/mail + elif test -d /usr/spool/mail; then + bash_cv_mail_dir=/usr/spool/mail + elif test -d /var/spool/mail; then + bash_cv_mail_dir=/var/spool/mail + else + bash_cv_mail_dir=unknown + fi + +fi + +echo "$ac_t""$bash_cv_mail_dir" 1>&6 +if test $bash_cv_mail_dir = "/var/mail"; then + cat >> confdefs.h <<\EOF +#define DEFAULT_MAIL_DIRECTORY "/var/mail" +EOF + +elif test $bash_cv_mail_dir = "/usr/mail"; then + cat >> confdefs.h <<\EOF +#define DEFAULT_MAIL_DIRECTORY "/usr/mail" +EOF + +elif test $bash_cv_mail_dir = "/var/spool/mail"; then + cat >> confdefs.h <<\EOF +#define DEFAULT_MAIL_DIRECTORY "/var/spool/mail" +EOF + +elif test $bash_cv_mail_dir = "/usr/spool/mail"; then + cat >> confdefs.h <<\EOF +#define DEFAULT_MAIL_DIRECTORY "/usr/spool/mail" +EOF + +else + cat >> confdefs.h <<\EOF +#define DEFAULT_MAIL_DIRECTORY "unknown" +EOF + +fi + + +if test "$bash_cv_job_control_missing" = missing; then + opt_job_control=no +fi + +if test "$opt_job_control" = yes; then +cat >> confdefs.h <<\EOF +#define JOB_CONTROL 1 +EOF + +JOBS_O=jobs.o +else +JOBS_O=nojobs.o +fi + + + + +case "$host_os" in +sysv4.2) cat >> confdefs.h <<\EOF +#define SVR4_2 1 +EOF + + cat >> confdefs.h <<\EOF +#define SVR4 1 +EOF + ;; +sysv4*) cat >> confdefs.h <<\EOF +#define SVR4 1 +EOF + ;; +hpux*) LOCAL_CFLAGS=-DHPUX ;; +dgux*) LOCAL_CFLAGS=-D_DGUX_SOURCE; LOCAL_LIBS=-ldgc ;; +isc*) LOCAL_CFLAGS=-Disc386;; +sco3.2v5*) LOCAL_CFLAGS="-DWAITPID_BROKEN -DNO_MEMSCRAMBLE -DPATH_MAX=1024" ;; +sco3.2v4*) LOCAL_CFLAGS="-DMUST_UNBLOCK_CHLD -DNO_MEMSCRAMBLE -DPATH_MAX=1024" ;; +sco3.2*) LOCAL_CFLAGS=-DMUST_UNBLOCK_CHLD ;; +sunos4*) LOCAL_CFLAGS=-DSunOS4;; +linux*) LOCAL_LDFLAGS=-rdynamic ;; # allow dynamic loading +aix4.2*) LOCAL_LDFLAGS="-bexpall -brtl";;# allow dynamic loading +esac + +case "$host_cpu" in +*cray*) LOCAL_CFLAGS="-DCRAY" ;; # shell var so config.h can use it +esac + +case "$host_cpu-$host_os" in +ibmrt-*bsd4*) LOCAL_CFLAGS="-ma -U__STDC__" ;; +esac + +case "$host_cpu-$host_vendor-$host_os" in +m88k-motorola-sysv3) LOCAL_CFLAGS=-DWAITPID_BROKEN ;; +mips-pyramid-sysv4) LOCAL_CFLAGS=-Xa ;; +esac + +# try to create a directory tree if the source is elsewhere +# this should be packaged into a script accessible via ${srcdir}/support +case "$srcdir" in +.) ;; +*) for d in doc tests support lib ; do # dirs + test -d $d || mkdir $d + done + for ld in readline glob tilde malloc termcap; do # libdirs + test -d lib/$ld || mkdir lib/$ld + done + ;; +esac + +BUILD_DIR=`pwd` + + + + + + + + + + + + + + + + + +trap '' 1 2 15 +cat > confcache <<\EOF +# This file is a shell script that caches the results of configure +# tests run on this system so they can be shared between configure +# scripts and configure runs. It is not useful on other systems. +# If it contains results you don't want to keep, you may remove or edit it. # -echo "Bash is configured to auto configure." +# By default, configure uses ./config.cache as the cache file, +# creating it if it does not exist already. You can give configure +# the --cache-file=FILE option to use a different cache file; that is +# what configure does when it calls configure scripts in +# subdirectories, so they share the cache. +# Giving --cache-file=/dev/null disables caching, for debugging configure. +# config.status only pays attention to the cache file if you give it the +# --recheck option to rerun configure. +# +EOF +# The following way of writing the cache mishandles newlines in values, +# but we know of no workaround that is simple, portable, and efficient. +# So, don't put newlines in cache variables' values. +# Ultrix sh set writes to stderr and can't be redirected directly, +# and sets the high bit in the cache file unless we assign to the vars. +(set) 2>&1 | + case `(ac_space=' '; set) 2>&1` in + *ac_space=\ *) + # `set' does not quote correctly, so add quotes (double-quote substitution + # turns \\\\ into \\, and sed turns \\ into \). + sed -n \ + -e "s/'/'\\\\''/g" \ + -e "s/^\\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\\)=\\(.*\\)/\\1=\${\\1='\\2'}/p" + ;; + *) + # `set' quotes correctly as required by POSIX, so do not add quotes. + sed -n -e 's/^\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\)=\(.*\)/\1=${\1=\2}/p' + ;; + esac >> confcache +if cmp -s $cache_file confcache; then + : +else + if test -w $cache_file; then + echo "updating cache $cache_file" + cat confcache > $cache_file + else + echo "not updating unwritable cache $cache_file" + fi +fi +rm -f confcache + +trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15 + +test "x$prefix" = xNONE && prefix=$ac_default_prefix +# Let make expand exec_prefix. +test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' + +# Any assignment to VPATH causes Sun make to only execute +# the first set of double-colon rules, so remove it if not needed. +# If there is a colon in the path, we need to keep it. +if test "x$srcdir" = x.; then + ac_vpsub='/^[ ]*VPATH[ ]*=[^:]*$/d' +fi + +trap 'rm -f $CONFIG_STATUS conftest*; exit 1' 1 2 15 + +DEFS=-DHAVE_CONFIG_H + +# Without the "./", some shells look in PATH for config.status. +: ${CONFIG_STATUS=./config.status} + +echo creating $CONFIG_STATUS +rm -f $CONFIG_STATUS +cat > $CONFIG_STATUS </dev/null | sed 1q`: +# +# $0 $ac_configure_args +# +# Compiler output produced by configure, useful for debugging +# configure, is in ./config.log if it exists. + +ac_cs_usage="Usage: $CONFIG_STATUS [--recheck] [--version] [--help]" +for ac_option +do + case "\$ac_option" in + -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) + echo "running \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion" + exec \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion ;; + -version | --version | --versio | --versi | --vers | --ver | --ve | --v) + echo "$CONFIG_STATUS generated by autoconf version 2.12" + exit 0 ;; + -help | --help | --hel | --he | --h) + echo "\$ac_cs_usage"; exit 0 ;; + *) echo "\$ac_cs_usage"; exit 1 ;; + esac +done + +ac_given_srcdir=$srcdir +ac_given_INSTALL="$INSTALL" + +trap 'rm -fr `echo "Makefile builtins/Makefile lib/readline/Makefile lib/glob/Makefile \ + lib/malloc/Makefile lib/termcap/Makefile lib/tilde/Makefile \ + doc/Makefile config.h" | sed "s/:[^ ]*//g"` conftest*; exit 1' 1 2 15 +EOF +cat >> $CONFIG_STATUS < conftest.subs <<\\CEOF +$ac_vpsub +$extrasub +s%@CFLAGS@%$CFLAGS%g +s%@CPPFLAGS@%$CPPFLAGS%g +s%@CXXFLAGS@%$CXXFLAGS%g +s%@DEFS@%$DEFS%g +s%@LDFLAGS@%$LDFLAGS%g +s%@LIBS@%$LIBS%g +s%@exec_prefix@%$exec_prefix%g +s%@prefix@%$prefix%g +s%@program_transform_name@%$program_transform_name%g +s%@bindir@%$bindir%g +s%@sbindir@%$sbindir%g +s%@libexecdir@%$libexecdir%g +s%@datadir@%$datadir%g +s%@sysconfdir@%$sysconfdir%g +s%@sharedstatedir@%$sharedstatedir%g +s%@localstatedir@%$localstatedir%g +s%@libdir@%$libdir%g +s%@includedir@%$includedir%g +s%@oldincludedir@%$oldincludedir%g +s%@infodir@%$infodir%g +s%@mandir@%$mandir%g +s%@host@%$host%g +s%@host_alias@%$host_alias%g +s%@host_cpu@%$host_cpu%g +s%@host_vendor@%$host_vendor%g +s%@host_os@%$host_os%g +s%@PURIFY@%$PURIFY%g +s%@MALLOC@%$MALLOC%g +s%@MALLOC_SRC@%$MALLOC_SRC%g +s%@READLINE_LIB@%$READLINE_LIB%g +s%@READLINE_DEP@%$READLINE_DEP%g +s%@HISTORY_LIB@%$HISTORY_LIB%g +s%@HISTORY_DEP@%$HISTORY_DEP%g +s%@CC@%$CC%g +s%@CPP@%$CPP%g +s%@INSTALL_PROGRAM@%$INSTALL_PROGRAM%g +s%@INSTALL_DATA@%$INSTALL_DATA%g +s%@AR@%$AR%g +s%@RANLIB@%$RANLIB%g +s%@YACC@%$YACC%g +s%@SET_MAKE@%$SET_MAKE%g +s%@ALLOCA@%$ALLOCA%g +s%@TERMCAP_LIB@%$TERMCAP_LIB%g +s%@TERMCAP_DEP@%$TERMCAP_DEP%g +s%@JOBS_O@%$JOBS_O%g +s%@incdir@%$incdir%g +s%@BUILD_DIR@%$BUILD_DIR%g +s%@LOCAL_LIBS@%$LOCAL_LIBS%g +s%@LOCAL_CFLAGS@%$LOCAL_CFLAGS%g +s%@LOCAL_LDFLAGS@%$LOCAL_LDFLAGS%g +s%@ALLOCA_SOURCE@%$ALLOCA_SOURCE%g +s%@ALLOCA_OBJECT@%$ALLOCA_OBJECT%g + +CEOF +EOF + +cat >> $CONFIG_STATUS <<\EOF + +# Split the substitutions into bite-sized pieces for seds with +# small command number limits, like on Digital OSF/1 and HP-UX. +ac_max_sed_cmds=90 # Maximum number of lines to put in a sed script. +ac_file=1 # Number of current file. +ac_beg=1 # First line for current file. +ac_end=$ac_max_sed_cmds # Line after last line for current file. +ac_more_lines=: +ac_sed_cmds="" +while $ac_more_lines; do + if test $ac_beg -gt 1; then + sed "1,${ac_beg}d; ${ac_end}q" conftest.subs > conftest.s$ac_file + else + sed "${ac_end}q" conftest.subs > conftest.s$ac_file + fi + if test ! -s conftest.s$ac_file; then + ac_more_lines=false + rm -f conftest.s$ac_file + else + if test -z "$ac_sed_cmds"; then + ac_sed_cmds="sed -f conftest.s$ac_file" + else + ac_sed_cmds="$ac_sed_cmds | sed -f conftest.s$ac_file" + fi + ac_file=`expr $ac_file + 1` + ac_beg=$ac_end + ac_end=`expr $ac_end + $ac_max_sed_cmds` + fi +done +if test -z "$ac_sed_cmds"; then + ac_sed_cmds=cat +fi +EOF + +cat >> $CONFIG_STATUS <> $CONFIG_STATUS <<\EOF +for ac_file in .. $CONFIG_FILES; do if test "x$ac_file" != x..; then + # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in". + case "$ac_file" in + *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'` + ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;; + *) ac_file_in="${ac_file}.in" ;; + esac + + # Adjust a relative srcdir, top_srcdir, and INSTALL for subdirectories. + + # Remove last slash and all that follows it. Not all systems have dirname. + ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'` + if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then + # The file is in a subdirectory. + test ! -d "$ac_dir" && mkdir "$ac_dir" + ac_dir_suffix="/`echo $ac_dir|sed 's%^\./%%'`" + # A "../" for each directory in $ac_dir_suffix. + ac_dots=`echo $ac_dir_suffix|sed 's%/[^/]*%../%g'` + else + ac_dir_suffix= ac_dots= + fi + + case "$ac_given_srcdir" in + .) srcdir=. + if test -z "$ac_dots"; then top_srcdir=. + else top_srcdir=`echo $ac_dots|sed 's%/$%%'`; fi ;; + /*) srcdir="$ac_given_srcdir$ac_dir_suffix"; top_srcdir="$ac_given_srcdir" ;; + *) # Relative path. + srcdir="$ac_dots$ac_given_srcdir$ac_dir_suffix" + top_srcdir="$ac_dots$ac_given_srcdir" ;; + esac + + case "$ac_given_INSTALL" in + [/$]*) INSTALL="$ac_given_INSTALL" ;; + *) INSTALL="$ac_dots$ac_given_INSTALL" ;; + esac + + echo creating "$ac_file" + rm -f "$ac_file" + configure_input="Generated automatically from `echo $ac_file_in|sed 's%.*/%%'` by configure." + case "$ac_file" in + *Makefile*) ac_comsub="1i\\ +# $configure_input" ;; + *) ac_comsub= ;; + esac + + ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"` + sed -e "$ac_comsub +s%@configure_input@%$configure_input%g +s%@srcdir@%$srcdir%g +s%@top_srcdir@%$top_srcdir%g +s%@INSTALL@%$INSTALL%g +" $ac_file_inputs | (eval "$ac_sed_cmds") > $ac_file +fi; done +rm -f conftest.s* + +# These sed commands are passed to sed as "A NAME B NAME C VALUE D", where +# NAME is the cpp macro being defined and VALUE is the value it is being given. +# +# ac_d sets the value in "#define NAME VALUE" lines. +ac_dA='s%^\([ ]*\)#\([ ]*define[ ][ ]*\)' +ac_dB='\([ ][ ]*\)[^ ]*%\1#\2' +ac_dC='\3' +ac_dD='%g' +# ac_u turns "#undef NAME" with trailing blanks into "#define NAME VALUE". +ac_uA='s%^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)' +ac_uB='\([ ]\)%\1#\2define\3' +ac_uC=' ' +ac_uD='\4%g' +# ac_e turns "#undef NAME" without trailing blanks into "#define NAME VALUE". +ac_eA='s%^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)' +ac_eB='$%\1#\2define\3' +ac_eC=' ' +ac_eD='%g' + +if test "${CONFIG_HEADERS+set}" != set; then +EOF +cat >> $CONFIG_STATUS <> $CONFIG_STATUS <<\EOF +fi +for ac_file in .. $CONFIG_HEADERS; do if test "x$ac_file" != x..; then + # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in". + case "$ac_file" in + *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'` + ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;; + *) ac_file_in="${ac_file}.in" ;; + esac + + echo creating $ac_file + + rm -f conftest.frag conftest.in conftest.out + ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"` + cat $ac_file_inputs > conftest.in + +EOF + +# Transform confdefs.h into a sed script conftest.vals that substitutes +# the proper values into config.h.in to produce config.h. And first: +# Protect against being on the right side of a sed subst in config.status. +# Protect against being in an unquoted here document in config.status. +rm -f conftest.vals +cat > conftest.hdr <<\EOF +s/[\\&%]/\\&/g +s%[\\$`]%\\&%g +s%#define \([A-Za-z_][A-Za-z0-9_]*\) *\(.*\)%${ac_dA}\1${ac_dB}\1${ac_dC}\2${ac_dD}%gp +s%ac_d%ac_u%gp +s%ac_u%ac_e%gp +EOF +sed -n -f conftest.hdr confdefs.h > conftest.vals +rm -f conftest.hdr + +# This sed command replaces #undef with comments. This is necessary, for +# example, in the case of _POSIX_SOURCE, which is predefined and required +# on some systems where configure will not decide to define it. +cat >> conftest.vals <<\EOF +s%^[ ]*#[ ]*undef[ ][ ]*[a-zA-Z_][a-zA-Z_0-9]*%/* & */% +EOF + +# Break up conftest.vals because some shells have a limit on +# the size of here documents, and old seds have small limits too. + +rm -f conftest.tail +while : +do + ac_lines=`grep -c . conftest.vals` + # grep -c gives empty output for an empty file on some AIX systems. + if test -z "$ac_lines" || test "$ac_lines" -eq 0; then break; fi + # Write a limited-size here document to conftest.frag. + echo ' cat > conftest.frag <> $CONFIG_STATUS + sed ${ac_max_here_lines}q conftest.vals >> $CONFIG_STATUS + echo 'CEOF + sed -f conftest.frag conftest.in > conftest.out + rm -f conftest.in + mv conftest.out conftest.in +' >> $CONFIG_STATUS + sed 1,${ac_max_here_lines}d conftest.vals > conftest.tail + rm -f conftest.vals + mv conftest.tail conftest.vals +done +rm -f conftest.vals + +cat >> $CONFIG_STATUS <<\EOF + rm -f conftest.frag conftest.h + echo "/* $ac_file. Generated automatically by configure. */" > conftest.h + cat conftest.in >> conftest.h + rm -f conftest.in + if cmp -s $ac_file conftest.h 2>/dev/null; then + echo "$ac_file is unchanged" + rm -f conftest.h + else + # Remove last slash and all that follows it. Not all systems have dirname. + ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'` + if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then + # The file is in a subdirectory. + test ! -d "$ac_dir" && mkdir "$ac_dir" + fi + rm -f $ac_file + mv conftest.h $ac_file + fi +fi; done + +EOF +cat >> $CONFIG_STATUS <> $CONFIG_STATUS <<\EOF + +# Makefile uses this timestamp file to record whether config.h is up to date. +echo timestamp > stamp-h + exit 0 +EOF +chmod +x $CONFIG_STATUS +rm -fr confdefs* $ac_clean_files +test "$no_create" = yes || ${CONFIG_SHELL-/bin/sh} $CONFIG_STATUS || exit 1 + diff --git a/configure.in b/configure.in new file mode 100644 index 0000000..62d1e51 --- /dev/null +++ b/configure.in @@ -0,0 +1,462 @@ +dnl +dnl Configure script for bash-2.0 +dnl +dnl report bugs to chet@po.cwru.edu +dnl +dnl Process this file with autoconf to produce a configure script. +dnl checks for version info +AC_REVISION([for Bash 2.0, version 1.14, from autoconf version] AC_ACVERSION)dnl + +AC_INIT(shell.h) +AC_CONFIG_HEADER(config.h) + +dnl make sure we are using a recent autoconf version +AC_PREREQ(2.8) + +dnl where to find install.sh, config.sub, and config.guess +AC_CONFIG_AUX_DIR(./support) + +dnl canonicalize the host and os so we can do some tricky things before +dnl parsing options +AC_CANONICAL_HOST + +dnl configure defaults +opt_gnu_malloc=yes +opt_glibc_malloc=no +opt_purify=no +opt_afs=no + +dnl some systems should be configured without gnu malloc by default +dnl and some need a special compiler or loader +dnl look in the NOTES file for more +case "${host_cpu}-${host_os}" in +alpha-*) opt_gnu_malloc=no ;; # alpha running osf/1 or linux +*cray*-*) opt_gnu_malloc=no ;; # Crays +*-osf1*) opt_gnu_malloc=no ;; # other osf/1 machines +sparc-svr4*) opt_gnu_malloc=no ;; # sparc SVR4, SVR4.2 +sparc-netbsd*) opt_gnu_malloc=no ;; # needs 8-byte alignment +sparc-linux*) opt_gnu_malloc=no ;; # sparc running linux; requires ELF +*-aix*) opt_gnu_malloc=no ;; # AIX machines +*-nextstep*) opt_gnu_malloc=no ;; # NeXT machines running NeXTstep +*-dgux*) opt_gnu_malloc=no ;; # DG/UX machines +*-qnx) opt_gnu_malloc=no ;; # QNX 4.2 +*-bsdi2.1) opt_gnu_malloc=no ; : ${CC:=shlicc2} ;; # for loadable builtins +esac + +dnl arguments to configure +dnl packages +AC_ARG_WITH(gnu-malloc, --with-gnu-malloc use the GNU version of malloc,opt_gnu_malloc=$withval) +AC_ARG_WITH(glibc-malloc, --with-glibc-malloc use the GNU C library version of malloc,opt_glibc_malloc=$withval) +AC_ARG_WITH(purify, --with-purify configure to postprocess with purify, opt_purify=$withval) +AC_ARG_WITH(afs, --with-afs if you are running AFS, opt_afs=$withval) + +dnl test for glibc malloc first because it can override the default +if test "$opt_glibc_malloc" = yes; then + MALLOC=gmalloc.o MALLOC_SRC='$(ALLOC_LIBSRC)/gmalloc.c' +elif test "$opt_gnu_malloc" = yes; then + MALLOC=malloc.o MALLOC_SRC='$(ALLOC_LIBSRC)/malloc.c' +else + MALLOC= MALLOC_SRC= +fi + +if test "$opt_purify" = yes; then + PURIFY=purify +else + PURIFY= +fi + +if test "$opt_afs" = yes; then + AC_DEFINE(AFS) +fi + +dnl optional shell features in config.h.in +opt_minimal_config=no + +opt_job_control=yes +opt_alias=yes +opt_readline=yes +opt_history=yes +opt_bang_history=yes +opt_dirstack=yes +opt_restricted=yes +opt_process_subst=yes +opt_prompt_decoding=yes +opt_select=yes +opt_help=yes +opt_array_variables=yes +opt_dparen_arith=yes +opt_brace_expansion=yes +opt_disabled_builtins=no +opt_command_timing=yes +opt_usg_echo=no + +dnl argument parsing for optional features +AC_ARG_ENABLE(minimal-config, --enable-minimal-config a minimal sh-like configuration, opt_minimal_config=$enableval) + +dnl a minimal configuration turns everything off, but features can be +dnl added individually +if test $opt_minimal_config = yes; then + opt_job_control=no opt_alias=no opt_readline=no + opt_history=no opt_bang_history=no opt_dirstack=no + opt_restricted=no opt_process_subst=no opt_prompt_decoding=no + opt_select=no opt_help=no opt_array_variables=no opt_dparen_arith=no + opt_brace_expansion=no opt_disabled_builtins=no opt_command_timing=no +fi + +AC_ARG_ENABLE(job-control, --enable-job-control enable job control features, opt_job_control=$enableval) +AC_ARG_ENABLE(alias, --enable-alias enable shell aliases, opt_alias=$enableval) +AC_ARG_ENABLE(readline, --enable-readline turn on command line editing, opt_readline=$enableval) +AC_ARG_ENABLE(history, --enable-history turn on command history, opt_history=$enableval) +AC_ARG_ENABLE(bang-history, --enable-bang-history turn on csh-style history substitution, opt_bang_history=$enableval) +AC_ARG_ENABLE(directory-stack, --enable-directory-stack enable builtins pushd/popd/dirs, opt_dirstack=$enableval) +AC_ARG_ENABLE(restricted, --enable-restricted enable a restricted shell, opt_restricted=$enableval) +AC_ARG_ENABLE(process-substitution, --enable-process-substitution enable process substitution, opt_process_subst=$enableval) +AC_ARG_ENABLE(prompt-string-decoding, --enable-prompt-string-decoding turn on escape character decoding in prompts, opt_prompt_decoding=$enableval) +AC_ARG_ENABLE(select, --enable-select include select command, opt_select=$enableval) +AC_ARG_ENABLE(help-builtin, --enable-help-builtin include the help builtin, opt_help=$enableval) +AC_ARG_ENABLE(array-variables, --enable-array-variables include shell array variables, opt_array_variables=$enableval) +AC_ARG_ENABLE(dparen-arithmetic, [--enable-dparen-arithmetic include ((...)) command], opt_dparen_arith=$enableval) +AC_ARG_ENABLE(brace-expansion, --enable-brace-expansion include brace expansion, opt_brace_expansion=$enableval) +AC_ARG_ENABLE(disabled-builtins, --enable-disabled-builtins allow disabled builtins to still be invoked, opt_disabled_builtins=$enableval) +AC_ARG_ENABLE(command-timing, --enable-command-timing enable the time reserved word and command timing, opt_command_timing=$enableval) +AC_ARG_ENABLE(usg-echo-default, --enable-usg-echo-default make the echo builtin expand escape sequences by default, opt_usg_echo=$enableval) + +dnl opt_job_control is handled later, after BASH_JOB_CONTROL_MISSING runs + +if test $opt_alias = yes; then +AC_DEFINE(ALIAS) +fi +if test $opt_readline = yes; then +AC_DEFINE(READLINE) +READLINE_LIB=-lreadline +READLINE_DEP='$(READLINE_LIBRARY)' +else +READLINE_LIB= READLINE_DEP= +fi +if test $opt_history = yes; then +AC_DEFINE(HISTORY) +HISTORY_LIB=-lhistory +HISTORY_DEP='$(HISTORY_LIBRARY)' +else +HISTORY_LIB= HISTORY_DEP= +fi +if test $opt_bang_history = yes; then +AC_DEFINE(BANG_HISTORY) +HISTORY_LIB=-lhistory +HISTORY_DEP='$(HISTORY_LIBRARY)' +else +HISTORY_LIB= HISTORY_DEP= +fi +if test $opt_dirstack = yes; then +AC_DEFINE(PUSHD_AND_POPD) +fi +if test $opt_restricted = yes; then +AC_DEFINE(RESTRICTED_SHELL) +fi +if test $opt_process_subst = yes; then +AC_DEFINE(PROCESS_SUBSTITUTION) +fi +if test $opt_prompt_decoding = yes; then +AC_DEFINE(PROMPT_STRING_DECODE) +fi +if test $opt_select = yes; then +AC_DEFINE(SELECT_COMMAND) +fi +if test $opt_help = yes; then +AC_DEFINE(HELP_BUILTIN) +fi +if test $opt_array_variables = yes; then +AC_DEFINE(ARRAY_VARS) +fi +if test $opt_dparen_arith = yes; then +AC_DEFINE(DPAREN_ARITHMETIC) +fi +if test $opt_brace_expansion = yes; then +AC_DEFINE(BRACE_EXPANSION) +fi +if test $opt_disabled_builtins = yes; then +AC_DEFINE(DISABLED_BUILTINS) +fi +if test $opt_command_timing = yes; then +AC_DEFINE(COMMAND_TIMING) +fi +if test $opt_usg_echo = yes ; then +AC_DEFINE(DEFAULT_ECHO_TO_USG) +fi + +dnl now substitute in the values generated by arguments +AC_SUBST(PURIFY) +AC_SUBST(MALLOC) +AC_SUBST(MALLOC_SRC) +AC_SUBST(READLINE_LIB) +AC_SUBST(READLINE_DEP) +AC_SUBST(HISTORY_LIB) +AC_SUBST(HISTORY_DEP) + +echo "Beginning configuration for bash-2.0" + +dnl compilation checks +AC_PROG_CC +AC_ISC_POSIX +AC_MINIX + +dnl See whether cc works at all +BASH_CC_WORKS + +dnl We want these before the checks, so the checks can modify their values. +test -z "$CFLAGS" && CFLAGS=-g auto_cflags=1 + +dnl If we're using gcc and the user hasn't specified CFLAGS, add -O2 to CFLAGS. +test -n "$GCC" && test -n "$auto_cflags" && CFLAGS="$CFLAGS -O2" + +AC_SUBST(CFLAGS) +AC_SUBST(CPPFLAGS) +AC_SUBST(LDFLAGS) + +AC_PROG_GCC_TRADITIONAL + +dnl programs needed by the build and install process +AC_PROG_INSTALL +AC_CHECK_PROG(AR, ar, ar) +AC_PROG_RANLIB +AC_PROG_YACC +AC_PROG_MAKE_SET + +dnl special checks for libc functions +AC_FUNC_ALLOCA +AC_FUNC_GETPGRP +AC_FUNC_SETVBUF_REVERSED +AC_FUNC_VPRINTF +AC_FUNC_WAIT3 +AC_FUNC_STRCOLL + +dnl if vprintf is not in libc, see if it's defined in stdio.h +if test "$ac_cv_func_vprintf" = no; then + AC_MSG_CHECKING(for declaration of vprintf in stdio.h) + AC_EGREP_HEADER([[int[ ]*vprintf[^a-zA-Z0-9]]],stdio.h,ac_cv_func_vprintf=yes) + AC_MSG_RESULT($ac_cv_func_vprintf) + if test $ac_cv_func_vprintf = yes; then + AC_DEFINE(HAVE_VPRINTF) + fi +fi + +dnl signal stuff +AC_RETSIGTYPE + +dnl checks for certain version-specific system calls and libc functions +AC_CHECK_FUNC(__setostype, AC_DEFINE(HAVE_SETOSTYPE)) +AC_CHECK_FUNC(wait3, AC_DEFINE(HAVE_WAIT3)) + +dnl checks for missing libc functions +AC_CHECK_FUNC(mkfifo,AC_DEFINE(HAVE_MKFIFO),AC_DEFINE(MKFIFO_MISSING)) + +dnl checks for system calls +AC_CHECK_FUNCS(dup2 select getdtablesize getgroups gethostname \ + setdtablesize getpagesize killpg lstat getpeername \ + getrlimit getrusage gettimeofday waitpid tcgetpgrp) + +dnl checks for c library functions +AC_CHECK_FUNCS(bcopy bzero confstr getcwd strcasecmp setenv putenv \ + setlinebuf setlocale strchr strerror tcgetattr uname \ + sysconf ulimit times tzset siginterrupt memmove) + +dnl checks for locale functions +AC_CHECK_HEADERS(libintl.h) +AC_CHECK_FUNCS(gettext textdomain bindtextdomain) + +dnl check for GNU libintl if gettext/textdomain/bindtextdomain +dnl are not found in libc +if test "$ac_cv_func_bindtextdomain" = "no"; then + AC_CHECK_LIB(intl,bindtextdomain) + if test "$ac_cv_lib_intl" = "yes"; then + AC_CHECK_FUNCS(gettext textdomain bindtextdomain) + fi +fi + +dnl checks for the dynamic loading library functions in libc and libdl +AC_CHECK_LIB(dl, dlopen) +AC_CHECK_FUNCS(dlopen dlclose dlsym) + +dnl this defines SYS_SIGLIST_DECLARED +AC_DECL_SYS_SIGLIST + +dnl header files +AC_HEADER_DIRENT +AC_HEADER_TIME + +AC_CHECK_HEADERS(unistd.h stdlib.h stdarg.h varargs.h limits.h string.h \ + memory.h locale.h termcap.h termio.h termios.h) +AC_CHECK_HEADERS(sys/ptem.h sys/pte.h sys/stream.h sys/select.h sys/file.h \ + sys/resource.h sys/param.h sys/socket.h \ + sys/time.h sys/times.h sys/wait.h) + +dnl libraries +dnl this is reportedly no longer necessary for irix[56].? +dnl AC_CHECK_LIB(sun, getpwent) +BASH_CHECK_SOCKLIB + +dnl system types +AC_TYPE_GETGROUPS +AC_TYPE_OFF_T +AC_TYPE_MODE_T +AC_TYPE_UID_T +AC_TYPE_PID_T +AC_TYPE_SIZE_T +AC_CHECK_TYPE(time_t, long) + +AC_TYPE_SIGNAL + +dnl structures +AC_HEADER_STAT +AC_HEADER_EGREP(struct timeval, sys/time.h, bash_cv_struct_timeval=yes, ) +if test -z "$bash_cv_struct_timeval"; then +AC_HEADER_EGREP(struct timeval, time.h, bash_cv_struct_timeval=yes, bash_cv_struct_timeval=no) +fi +if test $bash_cv_struct_timeval = yes; then +AC_DEFINE(HAVE_TIMEVAL) +fi + +dnl C compiler characteristics +AC_C_BIGENDIAN + +dnl system services +AC_SYS_INTERPRETER +if test $ac_cv_sys_interpreter = yes; then +AC_DEFINE(HAVE_HASH_BANG_EXEC) +fi +dnl we use NO_READ_RESTART_ON_SIGNAL +AC_SYS_RESTARTABLE_SYSCALLS + +dnl Miscellaneous Bash tests +if test "$ac_cv_func_lstat" = "no"; then +BASH_FUNC_LSTAT +fi + +BASH_DUP2_CLOEXEC_CHECK +BASH_PGRP_SYNC +BASH_SYS_ERRLIST +BASH_SYS_SIGLIST +BASH_UNDER_SYS_SIGLIST +BASH_SIGNAL_CHECK +BASH_TYPE_SIGHANDLER +BASH_CHECK_TYPE(clock_t, [#include ], long) +BASH_CHECK_TYPE(sigset_t, [#include ], int) +BASH_CHECK_TYPE(quad_t, , long, HAVE_QUAD_T) +BASH_RLIMIT_TYPE +BASH_STRUCT_TERMIOS_LDISC +BASH_STRUCT_TERMIO_LDISC +BASH_STRUCT_DIRENT_D_INO +BASH_FUNC_STRSIGNAL +BASH_FUNC_OPENDIR_CHECK +BASH_FUNC_PRINTF +BASH_FUNC_ULIMIT_MAXFDS +BASH_FUNC_GETENV +BASH_FUNC_GETCWD +BASH_FUNC_SBRK_DECLARED +BASH_FUNC_POSIX_SETJMP +BASH_REINSTALL_SIGHANDLERS +BASH_JOB_CONTROL_MISSING +BASH_SYS_NAMED_PIPES +BASH_HAVE_TIOCGWINSZ +BASH_HAVE_TIOCSTAT +BASH_HAVE_FIONREAD +BASH_CHECK_GETPW_FUNCS +BASH_CHECK_DEV_FD + +case "$host_os" in +hpux*) BASH_KERNEL_RLIMIT_CHECK ;; +esac + +if test "$opt_readline" = yes; then +BASH_CHECK_LIB_TERMCAP +fi +AC_SUBST(TERMCAP_LIB) +AC_SUBST(TERMCAP_DEP) + +dnl special checks +BASH_DEFAULT_MAIL_DIR + +if test "$bash_cv_job_control_missing" = missing; then + opt_job_control=no +fi + +if test "$opt_job_control" = yes; then +AC_DEFINE(JOB_CONTROL) +JOBS_O=jobs.o +else +JOBS_O=nojobs.o +fi + +AC_SUBST(JOBS_O) + +dnl use this section to possibly define more cpp variables, specify local +dnl libraries, and specify any additional local cc flags +dnl +dnl this should really go away someday + +case "$host_os" in +sysv4.2) AC_DEFINE(SVR4_2) + AC_DEFINE(SVR4) ;; +sysv4*) AC_DEFINE(SVR4) ;; +hpux*) LOCAL_CFLAGS=-DHPUX ;; +dgux*) LOCAL_CFLAGS=-D_DGUX_SOURCE; LOCAL_LIBS=-ldgc ;; +isc*) LOCAL_CFLAGS=-Disc386;; +sco3.2v5*) LOCAL_CFLAGS="-DWAITPID_BROKEN -DNO_MEMSCRAMBLE -DPATH_MAX=1024" ;; +sco3.2v4*) LOCAL_CFLAGS="-DMUST_UNBLOCK_CHLD -DNO_MEMSCRAMBLE -DPATH_MAX=1024" ;; +sco3.2*) LOCAL_CFLAGS=-DMUST_UNBLOCK_CHLD ;; +sunos4*) LOCAL_CFLAGS=-DSunOS4;; +linux*) LOCAL_LDFLAGS=-rdynamic ;; # allow dynamic loading +aix4.2*) LOCAL_LDFLAGS="-bexpall -brtl";;# allow dynamic loading +esac + +case "$host_cpu" in +*cray*) LOCAL_CFLAGS="-DCRAY" ;; # shell var so config.h can use it +esac + +case "$host_cpu-$host_os" in +ibmrt-*bsd4*) LOCAL_CFLAGS="-ma -U__STDC__" ;; +esac + +case "$host_cpu-$host_vendor-$host_os" in +m88k-motorola-sysv3) LOCAL_CFLAGS=-DWAITPID_BROKEN ;; +mips-pyramid-sysv4) LOCAL_CFLAGS=-Xa ;; +esac + +# try to create a directory tree if the source is elsewhere +# this should be packaged into a script accessible via ${srcdir}/support +case "$srcdir" in +.) ;; +*) for d in doc tests support lib ; do # dirs + test -d $d || mkdir $d + done + for ld in readline glob tilde malloc termcap; do # libdirs + test -d lib/$ld || mkdir lib/$ld + done + ;; +esac + +BUILD_DIR=`pwd` + +AC_SUBST(incdir) +AC_SUBST(BUILD_DIR) + +AC_SUBST(YACC) +AC_SUBST(AR) + +AC_SUBST(host_cpu) +AC_SUBST(host_os) + +AC_SUBST(LOCAL_LIBS) +AC_SUBST(LOCAL_CFLAGS) +AC_SUBST(LOCAL_LDFLAGS) + +AC_SUBST(ALLOCA_SOURCE) +AC_SUBST(ALLOCA_OBJECT) + +AC_OUTPUT([Makefile builtins/Makefile lib/readline/Makefile lib/glob/Makefile \ + lib/malloc/Makefile lib/termcap/Makefile lib/tilde/Makefile \ + doc/Makefile], +[ +# Makefile uses this timestamp file to record whether config.h is up to date. +echo timestamp > stamp-h +]) diff --git a/copy_cmd.c b/copy_cmd.c index 991bbc9..2ac2049 100644 --- a/copy_cmd.c +++ b/copy_cmd.c @@ -20,8 +20,14 @@ along with Bash; see the file COPYING. If not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include "config.h" + #include +#if defined (HAVE_UNISTD_H) +# include +#endif + #if defined (HAVE_STRING_H) # include #else /* !HAVE_STRING_H */ @@ -34,27 +40,28 @@ WORD_DESC * copy_word (word) WORD_DESC *word; { - WORD_DESC *new_word = (WORD_DESC *)xmalloc (sizeof (WORD_DESC)); + WORD_DESC *new_word; + + new_word = (WORD_DESC *)xmalloc (sizeof (WORD_DESC)); FASTCOPY ((char *)word, (char *)new_word, sizeof (WORD_DESC)); new_word->word = savestring (word->word); return (new_word); } -/* Copy the chain of words in LIST. Return a pointer to +/* Copy the chain of words in LIST. Return a pointer to the new chain. */ WORD_LIST * copy_word_list (list) WORD_LIST *list; { - WORD_LIST *new_list = NULL; + WORD_LIST *new_list, *temp; - while (list) + for (new_list = (WORD_LIST *)NULL; list; list = list->next) { - WORD_LIST *temp = (WORD_LIST *)xmalloc (sizeof (WORD_LIST)); + temp = (WORD_LIST *)xmalloc (sizeof (WORD_LIST)); temp->next = new_list; new_list = temp; new_list->word = copy_word (list->word); - list = list->next; } return (REVERSE_LIST (new_list, WORD_LIST *)); } @@ -63,7 +70,9 @@ static PATTERN_LIST * copy_case_clause (clause) PATTERN_LIST *clause; { - PATTERN_LIST *new_clause = (PATTERN_LIST *)xmalloc (sizeof (PATTERN_LIST)); + PATTERN_LIST *new_clause; + + new_clause = (PATTERN_LIST *)xmalloc (sizeof (PATTERN_LIST)); new_clause->patterns = copy_word_list (clause->patterns); new_clause->action = copy_command (clause->action); return (new_clause); @@ -73,14 +82,13 @@ static PATTERN_LIST * copy_case_clauses (clauses) PATTERN_LIST *clauses; { - PATTERN_LIST *new_list = (PATTERN_LIST *)NULL; + PATTERN_LIST *new_list, *new_clause; - while (clauses) + for (new_list = (PATTERN_LIST *)NULL; clauses; clauses = clauses->next) { - PATTERN_LIST *new_clause = copy_case_clause (clauses); + new_clause = copy_case_clause (clauses); new_clause->next = new_list; new_list = new_clause; - clauses = clauses->next; } return (REVERSE_LIST (new_list, PATTERN_LIST *)); } @@ -90,14 +98,16 @@ REDIRECT * copy_redirect (redirect) REDIRECT *redirect; { - REDIRECT *new_redirect = (REDIRECT *)xmalloc (sizeof (REDIRECT)); + REDIRECT *new_redirect; + + new_redirect = (REDIRECT *)xmalloc (sizeof (REDIRECT)); FASTCOPY ((char *)redirect, (char *)new_redirect, (sizeof (REDIRECT))); switch (redirect->instruction) { case r_reading_until: case r_deblank_reading_until: new_redirect->here_doc_eof = savestring (redirect->here_doc_eof); - /* There is NO BREAK HERE ON PURPOSE!!!! */ + /*FALLTHROUGH*/ case r_appending_to: case r_output_direction: case r_input_direction: @@ -107,34 +117,34 @@ copy_redirect (redirect) case r_output_force: case r_duplicating_input_word: case r_duplicating_output_word: - new_redirect->redirectee.filename = - copy_word (redirect->redirectee.filename); + new_redirect->redirectee.filename = copy_word (redirect->redirectee.filename); break; } return (new_redirect); } - + REDIRECT * copy_redirects (list) REDIRECT *list; { - REDIRECT *new_list = NULL; + REDIRECT *new_list, *temp; - while (list) + for (new_list = (REDIRECT *)NULL; list; list = list->next) { - REDIRECT *temp = copy_redirect (list); + temp = copy_redirect (list); temp->next = new_list; new_list = temp; - list = list->next; } return (REVERSE_LIST (new_list, REDIRECT *)); } - + static FOR_COM * copy_for_command (com) FOR_COM *com; { - FOR_COM *new_for = (FOR_COM *)xmalloc (sizeof (FOR_COM)); + FOR_COM *new_for; + + new_for = (FOR_COM *)xmalloc (sizeof (FOR_COM)); new_for->flags = com->flags; new_for->name = copy_word (com->name); new_for->map_list = copy_word_list (com->map_list); @@ -142,26 +152,13 @@ copy_for_command (com) return (new_for); } -#if defined (SELECT_COMMAND) -static SELECT_COM * -copy_select_command (com) - SELECT_COM *com; -{ - SELECT_COM *new_select = (SELECT_COM *)xmalloc (sizeof (SELECT_COM)); - new_select->flags = com->flags; - new_select->name = copy_word (com->name); - new_select->map_list = copy_word_list (com->map_list); - new_select->action = copy_command (com->action); - return (new_select); -} -#endif /* SELECT_COMMAND */ - static GROUP_COM * copy_group_command (com) GROUP_COM *com; { - GROUP_COM *new_group = (GROUP_COM *)xmalloc (sizeof (GROUP_COM)); + GROUP_COM *new_group; + new_group = (GROUP_COM *)xmalloc (sizeof (GROUP_COM)); new_group->command = copy_command (com->command); return (new_group); } @@ -170,8 +167,9 @@ static CASE_COM * copy_case_command (com) CASE_COM *com; { - CASE_COM *new_case = (CASE_COM *)xmalloc (sizeof (CASE_COM)); + CASE_COM *new_case; + new_case = (CASE_COM *)xmalloc (sizeof (CASE_COM)); new_case->flags = com->flags; new_case->word = copy_word (com->word); new_case->clauses = copy_case_clauses (com->clauses); @@ -182,8 +180,9 @@ static WHILE_COM * copy_while_command (com) WHILE_COM *com; { - WHILE_COM *new_while = (WHILE_COM *)xmalloc (sizeof (WHILE_COM)); + WHILE_COM *new_while; + new_while = (WHILE_COM *)xmalloc (sizeof (WHILE_COM)); new_while->flags = com->flags; new_while->test = copy_command (com->test); new_while->action = copy_command (com->action); @@ -194,8 +193,9 @@ static IF_COM * copy_if_command (com) IF_COM *com; { - IF_COM *new_if = (IF_COM *)xmalloc (sizeof (IF_COM)); + IF_COM *new_if; + new_if = (IF_COM *)xmalloc (sizeof (IF_COM)); new_if->flags = com->flags; new_if->test = copy_command (com->test); new_if->true_case = copy_command (com->true_case); @@ -220,8 +220,9 @@ static FUNCTION_DEF * copy_function_def (com) FUNCTION_DEF *com; { - FUNCTION_DEF *new_def = (FUNCTION_DEF *)xmalloc (sizeof (FUNCTION_DEF)); + FUNCTION_DEF *new_def; + new_def = (FUNCTION_DEF *)xmalloc (sizeof (FUNCTION_DEF)); new_def->name = copy_word (com->name); new_def->command = copy_command (com->command); return (new_def); @@ -234,72 +235,68 @@ COMMAND * copy_command (command) COMMAND *command; { - COMMAND *new_command = (COMMAND *)NULL; + COMMAND *new_command; - if (command) - { - new_command = (COMMAND *)xmalloc (sizeof (COMMAND)); - FASTCOPY ((char *)command, (char *)new_command, sizeof (COMMAND)); - new_command->flags = command->flags; - new_command->line = command->line; + if (command == NULL) + return (command); - if (command->redirects) - new_command->redirects = copy_redirects (command->redirects); + new_command = (COMMAND *)xmalloc (sizeof (COMMAND)); + FASTCOPY ((char *)command, (char *)new_command, sizeof (COMMAND)); + new_command->flags = command->flags; + new_command->line = command->line; - switch (command->type) - { - case cm_for: - new_command->value.For = copy_for_command (command->value.For); - break; + if (command->redirects) + new_command->redirects = copy_redirects (command->redirects); + + switch (command->type) + { + case cm_for: + new_command->value.For = copy_for_command (command->value.For); + break; #if defined (SELECT_COMMAND) - case cm_select: - new_command->value.Select = copy_select_command (command->value.Select); - break; + case cm_select: + new_command->value.Select = + (SELECT_COM *)copy_for_command ((FOR_COM *)command->value.Select); + break; #endif - case cm_group: - new_command->value.Group = copy_group_command (command->value.Group); - break; + case cm_group: + new_command->value.Group = copy_group_command (command->value.Group); + break; - case cm_case: - new_command->value.Case = copy_case_command (command->value.Case); - break; - - case cm_until: - case cm_while: - new_command->value.While = copy_while_command (command->value.While); - break; - - case cm_if: - new_command->value.If = copy_if_command (command->value.If); - break; - - case cm_simple: - new_command->value.Simple = copy_simple_command (command->value.Simple); - break; - - case cm_connection: - { - CONNECTION *new_connection; - - new_connection = (CONNECTION *)xmalloc (sizeof (CONNECTION)); - new_connection->connector = command->value.Connection->connector; - new_connection->first = - copy_command (command->value.Connection->first); - new_connection->second = - copy_command (command->value.Connection->second); - new_command->value.Connection = new_connection; - break; - } - - /* Pathological case. I'm not even sure that you can have a - function definition as part of a function definition. */ - case cm_function_def: - new_command->value.Function_def = - copy_function_def (command->value.Function_def); + case cm_case: + new_command->value.Case = copy_case_command (command->value.Case); + break; + + case cm_until: + case cm_while: + new_command->value.While = copy_while_command (command->value.While); + break; + + case cm_if: + new_command->value.If = copy_if_command (command->value.If); + break; + + case cm_simple: + new_command->value.Simple = copy_simple_command (command->value.Simple); + break; + + case cm_connection: + { + CONNECTION *new_connection; + + new_connection = (CONNECTION *)xmalloc (sizeof (CONNECTION)); + new_connection->connector = command->value.Connection->connector; + new_connection->first = copy_command (command->value.Connection->first); + new_connection->second = copy_command (command->value.Connection->second); + new_command->value.Connection = new_connection; break; } + + case cm_function_def: + new_command->value.Function_def = copy_function_def (command->value.Function_def); + break; } return (new_command); } diff --git a/cpp-Makefile b/cpp-Makefile deleted file mode 100644 index 9e1e2e8..0000000 --- a/cpp-Makefile +++ /dev/null @@ -1,1553 +0,0 @@ -/* This -*- C -*- file (cpp-Makefile) is run through the C preprocessor - to produce bash-Makefile which is machine specific. - - If you have Gcc and/or Bison, you might wish to mention that right - below here. - - Since this is to become a Makefile, blank lines which appear outside - of comments may not contain a TAB character. - - Copyright (C) 1987,1991 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 1, 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, 675 Mass Ave, Cambridge, MA 02139, USA. */ - -/**/# This Makefile is automagically made from cpp-Makefile. You should -/**/# not be editing this file; edit cpp-Makefile, machines.h, or -/**/# support/mksysdefs instead. Then, assuming the edits were required -/**/# to compile Bash on your system, mail the changes you had to make to -/**/# bash-maintainers@prep.ai.mit.edu. We will do our best to incorporate -/**/# them into the next release. - -/**/# Make sure the first target in the makefile is the right one -all: .made - -/* **************************************************************** */ -/* */ -/* Which compiler are you using? */ -/* */ -/* **************************************************************** */ - -/* Define HAVE_GCC if you have the GNU C compiler. */ -/* #define HAVE_GCC */ - -#if defined (__GNUC__) && !defined (HAVE_GCC) && !defined (GCC_STANDARD) -# define HAVE_GCC -#endif - -/* Undefine HAVE_FIXED_INCLUDES if you are not using GCC with the fixed - header files. */ -#if defined (HAVE_GCC) && !defined (HAVE_FIXED_INCLUDES) -# define HAVE_FIXED_INCLUDES -#endif /* HAVE_GCC && !HAVE_FIXED_INCLUDES */ - -/* Define HAVE_BISON if you have the GNU replacement for Yacc. */ -/**/# We would like you to use Bison instead of Yacc since some -/**/# versions of Yacc cannot handle reentrant parsing. Unfortunately, -/**/# this includes the Yacc currently being shipped with SunOS4.x. -/**/# If you do use Yacc, please make sure that any bugs in parsing -/**/# are not really manifestations of Yacc bugs before you report -/**/# them. -/* #define HAVE_BISON */ - -/* Include some boilerplate Gnu makefile definitions. */ -prefix = /usr/local - -exec_prefix = $(prefix) -bindir = $(exec_prefix)/bin -libdir = $(exec_prefix)/lib - -manroot = $(prefix)/man - -man1ext = 1 -man1dir = $(manroot)/man$(man1ext) -man3ext = 3 -man3dir = $(manroot)/man$(man3ext) -mandir = $(man1dir) -manext = $(man1ext) - -infodir = $(prefix)/info - -srcdir = . - -VPATH = .:$(srcdir) - -/* If you have purify, and want to use it, uncomment this definition or - run the make as `make -f bash-Makefile bash PURIFY=purify'. */ -PURIFY = # purify - -/* This includes the appropriate description for the machine that you are - using (we hope). If the compilation doesn't work correctly, then you - will have to edit the file `machines.h' to include a description for the - machine that your Cpp uniquely identifies this as. For example, Sun 4's - are recognized by the Cpp identifier `sparc', Vax is recognized with `vax', - etc. The order of these files is very important. Config.h must come last, - since it is capable of undef'ing various things. */ -#define BUILDING_MAKEFILE /* Tell config.h to avoid #including anything. */ -#include "sysdefs.h" -#include "machines.h" -#include "config.h" - -/* Can't use the Gnu malloc library without saying we want the Gnu malloc. */ -#if !defined (USE_GNU_MALLOC) -# undef USE_GNU_MALLOC_LIBRARY -#endif /* !USE_GNU_MALLOC */ - -.SUFFIXES: .aux -/**/# Here is a rule for making .o files from .c files that does not -/**/# force the type of the machine (like -M_MACHINE) into the flags. -.c.o: - $(RM) $@ - $(CC) $(CCFLAGS) $(CPPFLAGS) -c $< - -.c.aux: - $(RM) $@ - $(CC) $(CCFLAGS) $(CPPFLAGS) -o $@ $< - -#if defined (HAVE_BISON) -BISON = bison -y -#else -BISON = yacc -#endif - -#if defined (HAVE_GCC) -# if defined (GCC_FLAGS) -GCC_EXTRAS = GCC_FLAGS -# endif /* GCC_FLAGS */ -# if !defined (HAVE_FIXED_INCLUDES) -/* This is guaranteed to work, even if you have the fixed includes! - (Unless, of course, you have the fixed include files installed in - /usr/include. Then it will break.) */ -CC = gcc -traditional -I/usr/include $(GCC_EXTRAS) -# else /* HAVE_FIXED_INCLUDES */ -CC = gcc $(GCC_EXTRAS) -# endif /* HAVE_FIXED_INCLUDES */ -#else /* !HAVE_GCC */ -CC = CPP_CC -#endif /* !HAVE_GCC */ - -/**/# If the user has specified a Make shell, then use that. -#if defined (MAKE_SHELL) -SHELL = MAKE_SHELL -#else -SHELL=/bin/sh -#endif /* MAKE_SHELL */ - -CP = cp -RM = rm -f -AR = ar - -INSTALL = $(SUPPORT_SRC)install.sh -INSTALL_PROGRAM = $(INSTALL) -c -INSTALL_DATA = $(INSTALL) -c -m 644 - -COMPRESS = gzip -COMPRESS_EXT = .gz - -Machine = M_MACHINE -OS = M_OS - -/**/# PROFILE_FLAGS is either -pg, to generate profiling info for use -/**/# with gprof, or nothing (the default). -PROFILE_FLAGS= - -#if defined (SYSDEP_CFLAGS) -/**/# This system has some peculiar flags that must be passed to the -/**/# the C compiler (or to cpp). -SYSDEP = SYSDEP_CFLAGS -#endif /* SYSDEP_CFLAGS */ - -#if defined (SYSDEP_LDFLAGS) -/**/# This system has some peculiar flags that must be passed to the -/**/# link editor (ld). -SYSDEP_LD = SYSDEP_LDFLAGS -#endif /* SYSDEP_LDFLAGS */ - -#if defined (HAVE_SETLINEBUF) -/**/# This system has the setlinebuf () call. -LINEBUF = -DHAVE_SETLINEBUF -#endif - -#if defined (HAVE_VFPRINTF) -/**/# This system has the vprintf () and vfprintf () calls. -VPRINTF = -DHAVE_VFPRINTF -#endif /* HAVE_VFPRINTF */ - -#if defined (USE_VFPRINTF_EMULATION) -VPRINTF = -DHAVE_VFPRINTF -VPRINT_OBJ = vprint.o -#endif /* USE_VFPRINTF_EMULATION */ - -#if defined (HAVE_SYS_STREAM_H) -/**/# This system has -STREAM = -DHAVE_SYS_STREAM_H -#endif /* HAVE_SYS_STREAM_H */ - -#if defined (HAVE_SYS_PTEM_H) -/**/# This system has -PTEM = -DHAVE_SYS_PTEM_H -#endif /* HAVE_SYS_PTEM_H */ - -#if defined (HAVE_SYS_PTE_H) -/**/# This system has -PTE = -DHAVE_SYS_PTE_H -#endif /* HAVE_SYS_PTE_H */ - -/**/# This system has . -#if defined (HAVE_UNISTD_H) -UNISTD = -DHAVE_UNISTD_H -#endif - -/**/# This system has -#if defined (HAVE_STDLIB_H) -STDLIB = -DHAVE_STDLIB_H -#endif - -/**/# This system has -#if defined (HAVE_LIMITS_H) -LIMITSH = -DHAVE_LIMITS_H -#endif - -#if defined (HAVE_GETGROUPS) -/**/# This system has multiple groups. -GROUPS = -DHAVE_GETGROUPS -#endif - -#if defined (HAVE_RESOURCE) -/**/# This system has -RESOURCE = -DHAVE_RESOURCE -#endif - -#if defined (HAVE_SYS_PARAM) -/**/# This system has -PARAM = -DHAVE_SYS_PARAM -#endif - -#if defined (VOID_SIGHANDLER) -/**/# The signal () call provided by the system returns a pointer to -/**/# a function returning void. The signal handlers themselves are -/**/# thus void functions. -SIGHANDLER = -DVOID_SIGHANDLER -#endif - -#if defined (HAVE_STRERROR) -/**/# This system has the strerror () function. -STRERROR = -DHAVE_STRERROR -#endif - -#if defined (HAVE_WAIT_H) -/**/# This system has -WAITH = -DHAVE_WAIT_H -#endif - -#if defined (HAVE_GETWD) -/**/# This system has the getwd () call. -GETWD = -DHAVE_GETWD -#endif - -#if defined (HAVE_DUP2) -/**/# This system has a working version of dup2 (). -DUP2 = -DHAVE_DUP2 -#endif /* HAVE_DUP2 */ - -#if defined (HAVE_DIRENT) -/**/# This system uses struct dirent for reading directories with readdir. -DIRENT = -DHAVE_DIRENT -#endif /* HAVE_DIRENT */ - -#if defined (HAVE_DIRENT_H) -/**/# This system has /usr/include/dirent.h -DIRENTH = -DHAVE_DIRENT_H -#endif /* HAVE_DIRENT_H */ - -#if defined (HAVE_STRING_H) -/**/# This system has /usr/include/string.h -STRINGH = -DHAVE_STRING_H -#endif /* HAVE_STRING_H */ - -#if defined (HAVE_VARARGS_H) -/**/# This system has /usr/include/varargs.h -VARARGSH = -DHAVE_VARARGS_H -#endif /* HAVE_VARARGS_H */ - -#if defined (HAVE_STRCHR) -/**/# This system has strchr () and strrchr () string functions. -STRCHR = -DHAVE_STRCHR -#endif /* HAVE_STRCHR */ - -#if defined (HAVE_STRCASECMP) -STRCASE = -DHAVE_STRCASECMP -#endif /* HAVE_STRCASECMP */ - -#if defined (HAVE_DEV_FD) -/**/# This system has the /dev/fd directory for naming open files. -DEVFD = -DHAVE_DEV_FD -#endif /* HAVE_DEV_FD */ - -/**/# The GNU coding standards don't recognize the possibility that -/**/# other information besides optimization and debugging might be -/**/# passed to cc. A different name should have been used. -CFLAGS = -O -g - -SYSTEM_FLAGS = $(LINEBUF) $(VPRINTF) $(UNISTD) $(STDLIB) $(LIMITSH) \ - $(GROUPS) $(RESOURCE) $(PARAM) $(SIGHANDLER) $(SYSDEP) $(WAITH) \ - $(GETWD) $(DUP2) $(STRERROR) $(DIRENT) $(DIRENTH) $(STRINGH) \ - $(VARARGSH) $(STRCHR) $(STRCASE) $(DEVFD) \ - -D$(Machine) -D$(OS) -LDFLAGS = $(NOSHARE) $(SYSDEP_LD) $(EXTRA_LD_PATH) $(PROFILE_FLAGS) $(CFLAGS) -CCFLAGS = $(PROFILE_FLAGS) $(SYSTEM_FLAGS) -DSHELL $(ALLOCA_CFLAGS) \ - $(MALLOC_CFLAGS) $(CFLAGS) -CPPFLAGS= -I. -I$(srcdir) -I$(LIBSRC) -GCC_LINT_FLAGS = -ansi -Wall -Wshadow -Wpointer-arith -Wcast-qual \ - -Wwrite-strings -Werror -Wstrict-prototypes \ - -Wmissing-prototypes -GCC_LINT_CFLAGS = $(PROFILE_FLAGS) $(CFLAGS) $(SYSTEM_FLAGS) -DSHELL $(ALLOCA_CFLAGS) \ - $(MALLOC_CFLAGS) $(GCC_LINT_FLAGS) - -/* It is conceivable that you wish to edit some things beyond this point, - but I guess that it is highly unlikely, and may give you a headache. */ - -/* **************************************************************** */ -/* */ -/* How to Build the support libraries. */ -/* */ -/* **************************************************************** */ - -/**/# The location of sources for the support libraries. -LIBPATH = ./lib/ -LIBSRC = $(srcdir)/$(LIBPATH) - -/**/# Preface building with the full path of the current library source. -LIBINC_DECL = topdir=`sh $(srcdir)/support/srcdir $(srcdir)`; export topdir -LIBINC_USAGE = "-I$${topdir} -I$${topdir}/$(LIBPATH) -I$(LIBSRC)" - -/* Defines used when building libraries. */ -#define LIB_CFLAGS_DECL CFLAGS='$(LIBRARY_CFLAGS) '$(LIBINC_USAGE) -#define LIB_CPPFLAGS_DECL CPPFLAGS='$(CPPFLAGS)' -#define LIB_LDFLAGS_DECL LDFLAGS='$(LDFLAGS)' -#define LIBMAKE_FLAGS LIB_CFLAGS_DECL LIB_CPPFLAGS_DECL LIB_LDFLAGS_DECL \ - RANLIB='$(RANLIB)' AR='$(AR)' CC='$(CC)' RM='$(RM)' \ - -/* Macro used to build a library. */ -#define build_lib_in_dir(directory, target, srcdef, makefile) \ - @echo "Building in " directory "..."; \ - sh $(SUPPORT_SRC)mkdirs directory ; \ - ($(LIBINC_DECL); cd directory; \ - if [ ! -f Makefile ]; then cp makefile Makefile; fi; \ - $(MAKE) target $(MFLAGS) LIBMAKE_FLAGS srcdef) - -/* The builtins are somewhat special in that more information is needed - to compile them correctly. */ -#define build_builtins(target) \ - @sh $(SUPPORT_SRC)mkdirs $(DEFDIR) ; \ - ($(LIBINC_DECL); cd $(DEFDIR); \ - if [ ! -f Makefile ]; then \ - cp $(BUILTIN_ABSSRC)/Makefile Makefile; \ - fi; \ - $(MAKE) $(MFLAGS) target \ - srcdir=$(BUILTIN_ABSSRC) CPPFLAGS='$(CPPFLAGS)' \ - CFLAGS='$(CCFLAGS) '$(LIBINC_USAGE)' -I. -I$(BUILTIN_ABSSRC)' \ - LDFLAGS='$(LDFLAGS)' RANLIB='$(RANLIB)' AR='$(AR)' CC='$(CC)' \ - RM='$(RM)' RL_LIBSRC='$(RL_ABSSRC)' \ - DIRECTDEFINE='-D '$(srcdir)/$(DEFDIR)) - -/**/# Flags used when building libraries. -LIBRARY_CFLAGS = $(PROFILE_FLAGS) $(CFLAGS) $(SIGHANDLER) $(ALLOCA_CFLAGS) \ - $(SYSDEP) $(DIRENT) $(DIRENTH) $(STRINGH) $(VARARGSH) \ - $(PTEM) $(PTE) $(STREAM) $(STRERROR) $(RESOURCE) \ - $(STRCHR) -D$(Machine) -D$(OS) $(UNISTD) $(LIMITSH) \ - $(STRCASE) $(STDLIB) -DSHELL - -/**/# These are required for sending bug reports. -SYSTEM_NAME = $(Machine) -OS_NAME = $(OS) - -/**/# The name of this program. -Program = bash - -/**/# The type of machine and OS Bash is being compiled on. -HOSTTYPE_DECL = -DHOSTTYPE='$(SYSTEM_NAME)' -DOSTYPE='$(OS_NAME)' - -/**/# The group of configuration flags. These are for shell.c -CFG_FLAGS = -DOS_NAME='$(OS_NAME)' -DSYSTEM_NAME='$(SYSTEM_NAME)' \ - $(SIGLIST_FLAG) - -/* **************************************************************** */ -/* */ -/* Support for desired libraries. */ -/* This includes Termcap, Glob, Tilde, History, and Readline. */ -/* */ -/* **************************************************************** */ - -/* Does this machine's linker need a space after -L? */ -#if defined (HAVE_GCC) -# undef SEARCH_LIB_NEEDS_SPACE -#endif /* HAVE_GCC */ - -#if defined (SEARCH_LIB_NEEDS_SPACE) -/**/# The native compiler for this machines requires a space after '-L'. -SEARCH_LIB = -L $(UNSET_VARIABLE_CREATES_SPACE) -#else -/**/# The compiler being used to build Bash can handle -L/library/path. -SEARCH_LIB = -L -#endif /* !SEARCH_LIB_NEEDS_SPACE */ - -#if defined (EXTRA_LIB_SEARCH_PATH) -/**/# Additional instructions to the linker telling it how to find libraries. -LOCAL_LD_PATH = EXTRA_LIB_SEARCH_PATH -EXTRA_LD_PATH = $(SEARCH_LIB)$(LOCAL_LD_PATH) -#endif /* EXTRA_LIB_SEARCH_PATH */ - -/* Right now we assume that you have the full source code to Bash. If - you simply have the library and header files installed, then - undefine HAVE_READLINE_SOURCE. */ -#define HAVE_READLINE_SOURCE - -#if defined (HAVE_READLINE_SOURCE) - -RL_LIBSRC = $(LIBSRC)readline/ -RL_LIBDOC = $(RL_LIBSRC)doc/ -RL_LIBDIR = $(LIBPATH)readline/ -RL_ABSSRC = $${topdir}/$(RL_LIBDIR) - -READLINE_LIBRARY = $(RL_LIBDIR)libreadline.a - -/**/# The source, object and documentation of the GNU Readline library. -READLINE_SOURCE = $(RL_LIBSRC)rldefs.h $(RL_LIBSRC)rlconf.h \ - $(RL_LIBSRC)readline.h \ - $(RL_LIBSRC)chardefs.h $(RL_LIBSRC)keymaps.h \ - $(RL_LIBSRC)funmap.c $(RL_LIBSRC)emacs_keymap.c \ - $(RL_LIBSRC)search.c $(RL_LIBSRC)vi_keymap.c \ - $(RL_LIBSRC)keymaps.c $(RL_LIBSRC)parens.c \ - $(RL_LIBSRC)vi_mode.c $(RL_LIBSRC)history.c \ - $(RL_LIBSRC)readline.c $(RL_LIBSRC)tilde.c \ - $(RL_LIBSRC)rltty.c $(RL_LIBSRC)complete.c \ - $(RL_LIBSRC)bind.c $(RL_LIBSRC)isearch.c \ - $(RL_LIBSRC)display.c $(RL_LIBSRC)signals.c \ - $(RL_LIBSRC)posixstat.h $(RL_LIBSRC)tilde.h \ - $(RL_LIBSRC)xmalloc.c - -READLINE_OBJ = $(RL_LIBDIR)readline.o $(RL_LIBDIR)funmap.o \ - $(RL_LIBDIR)parens.o $(RL_LIBDIR)search.o \ - $(RL_LIBDIR)keymaps.o $(RL_LIBDIR)history.o \ - $(RL_LIBDIR)rltty.o $(RL_LIBDIR)complete.o \ - $(RL_LIBDIR)bind.o $(RL_LIBDIR)isearch.o \ - $(RL_LIBDIR)display.o $(RL_LIBDIR)signals.o \ - $(RL_LIBDIR)tilde.o $(RL_LIBDIR)xmalloc.o - -READLINE_DOC = $(RL_LIBDOC)rlman.texinfo $(RL_LIBDOC)rluser.texinfo \ - $(RL_LIBDOC)rltech.texinfo - -READLINE_DOC_SUPPORT = $(RL_LIBDOC)Makefile $(RL_LIBDOC)readline.dvi \ - $(RL_LIBDOC)readline.info - -/**/# This has to be written funny to avoid looking like a C comment starter. -READLINE_EXAMPLES = $(RL_LIBSRC)examples/[a-zA-Z]*.[ch] \ - $(RL_LIBSRC)examples/Makefile $(RL_LIBSRC)examples/Inputrc - -/**/# Support files for GNU Readline. -READLINE_SUPPORT = $(RL_LIBSRC)Makefile $(RL_LIBSRC)ChangeLog \ - $(RL_LIBSRC)COPYING $(READLINE_EXAMPLES) \ - $(READLINE_DOC_SUPPORT) - -#else /* !HAVE_READLINE_SOURCE */ - -# if defined (READLINE) -READLINE_LIBRARY = -lreadline -# endif /* READLINE */ -RL_LIBDIR = $(srcdir)/$(LIBSRC)readline/ - -#endif /* !HAVE_READLINE_SOURCE */ - -/* Right now we assume that you have the full source code to Bash, - including the source code to the history library. If you only have - the library and header files installed, then you can undefine - HAVE_HISTORY_SOURCE. */ -#define HAVE_HISTORY_SOURCE - -#if defined (READLINE) && !defined (HISTORY) -# define HISTORY -#endif /* READLINE && !HISTORY */ - -# if defined (HISTORY) && !defined (READLINE) -/**/# You are compiling with history features but without line editing. -HISTORY_LIB = -lhistory -# endif /* HISTORY && !READLINE */ - -#if defined (HISTORY) -HIST_SUPPORT_SRC = bashhist.c -HIST_SUPPORT_OBJ = bashhist.o -#endif /* HISTORY */ - -#if defined (HAVE_HISTORY_SOURCE) - -HIST_LIBSRC = $(LIBSRC)readline/ -HIST_LIBDOC = $(HIST_LIBSRC)doc/ -HIST_LIBDIR = $(LIBPATH)readline/ -HIST_ABSSRC = $${topdir}/$(HIST_LIBDIR)/ - -/* If you are building with readline, then you do not explicitly need the - history library. */ -# if defined (READLINE) -HISTORY_LIBRARY = -# else -HISTORY_LIBRARY = $(HIST_LIBDIR)libhistory.a -# endif /* !READLINE */ - -/**/# The source, object and documentation of the history library. -HISTORY_SOURCE = $(HIST_LIBSRC)history.c $(HIST_LIBSRC)history.h -HISTORY_OBJ = $(HIST_LIBDIR)history.o -HISTORY_DOC = $(HIST_LIBDOC)hist.texinfo $(HIST_LIBDOC)hsuser.texinfo \ - $(HIST_LIBDOC)hstech.texinfo - -/**/# Directory list for -L so that the link editor (ld) can find -lhistory. -# if defined (HISTORY) && !defined (READLINE) -# if !defined (LD_HAS_NO_DASH_L) -HISTORY_LDFLAGS = $(SEARCH_LIB)$(HIST_LIBDIR) -# endif /* LD_HAS_NO_DASH_L */ -# endif /* HISTORY && !READLINE */ -#else /* !HAVE_HISTORY_SOURCE */ -# if defined (HISTORY) && !defined (READLINE) -HISTORY_LIBRARY = -lhistory -HISTORY_LDFLAGS = $(SEARCH_LIB)$(libdir) $(SEARCH_LIB)/usr/local/lib -# endif /* HISTORY && !READLINE */ -#endif /* !HAVE_HISTORY_SOURCE */ - -#if defined (USE_GNU_TERMCAP) -# define HAVE_TERMCAP_SOURCE -TERM_LIBSRC = $(LIBSRC)termcap/ -TERM_LIBDIR = $(LIBPATH)termcap/ -TERM_ABSSRC = $${topdir}/$(TERM_LIBDIR) - -/**/# The source, object and documentation for the GNU Termcap library. -TERMCAP_LIBRARY = $(TERM_LIBDIR)libtermcap.a - -TERMCAP_SOURCE = $(TERM_LIBSRC)termcap.c $(TERM_LIBSRC)tparam.c -TERMCAP_OBJ = $(TERM_LIBDIR)termcap.o $(TERM_LIBDIR)tparam.o -TERMCAP_DOC = $(TERM_LIBSRC)termcap.texinfo -TERMCAP_SUPPORT = $(TERM_LIBSRC)Makefile $(TERM_LIBSRC)ChangeLog - -# if !defined (LD_HAS_NO_DASH_L) -TERMCAP_LDFLAGS = $(SEARCH_LIB)$(TERM_LIBDIR) -# endif /* !LD_HAS_NO_DASH_L */ -#else /* !USE_GNU_TERMCAP */ - -/* Guessed at symbol for LIBRARIES, below. */ -# if defined (USE_TERMCAP_EMULATION) -TERMCAP_LIBRARY = -lcurses -# else /* !USE_TERMCAP_EMULATION */ -TERMCAP_LIBRARY = -ltermcap -# endif /* !USE_TERMCAP_EMULATION */ -#endif /* !USE_GNU_TERMCAP */ - -/* The glob library is always used. */ -#define USE_GLOB_LIBRARY - -#if defined (USE_GLOB_LIBRARY) -GLOB_LIBSRC = $(LIBSRC)glob/ -GLOB_LIBDIR = $(LIBPATH)glob/ -GLOB_ABSSRC = $${topdir}/$(GLOB_LIBDIR) - -GLOB_LIBRARY = $(GLOB_LIBDIR)libglob.a - -GLOB_SOURCE = $(GLOB_LIBSRC)glob.c $(GLOB_LIBSRC)fnmatch.c \ - $(GLOB_LIBSRC)fnmatch.h -GLOB_OBJ = $(GLOB_LIBDIR)glob.o $(GLOB_LIBDIR)fnmatch.o -GLOB_DOC = $(GLOB_LIBSRC)doc/glob.texi $(GLOB_LIBSRC)doc/Makefile -GLOB_SUPPORT= $(GLOB_LIBSRC)Makefile $(GLOB_LIBSRC)ChangeLog - -# if !defined (LD_HAS_NO_DASH_L) -GLOB_LDFLAGS = $(SEARCH_LIB)$(GLOB_LIBDIR) -# endif /* !LD_HAS_NO_DASH_L */ -GLOB_LIB = -lglob -#endif /* USE_GLOB_LIBRARY */ - -/* The source code for the tilde expansion library. */ -#if defined (HAVE_READLINE_SOURCE) -# define HAVE_TILDE_SOURCE -#endif /* HAVE_READLINE_SOURCE */ - -#if defined (HAVE_TILDE_SOURCE) -/**/# The source, object and documentation for the GNU Tilde library. -TILDE_LIBSRC = $(LIBSRC)tilde/ -TILDE_LIBDIR = $(LIBPATH)tilde/ -TILDE_ABSSRC = $${topdir}/$(TILDE_LIBDIR) - -TILDE_LIBRARY = $(TILDE_LIBDIR)libtilde.a - -TILDE_SOURCE = $(TILDE_LIBSRC)tilde.c $(TILDE_LIBSRC)tilde.h -TILDE_OBJ = $(TILDE_LIBDIR)tilde.o -TILDE_DOC = $(TILDE_LIBSRC)doc/tilde.texi $(TILDE_LIBSRC)doc/Makefile -TILDE_SUPPORT = $(TILDE_LIBSRC)Makefile $(TILDE_LIBSRC)ChangeLog - -TILDE_LIB = -ltilde - -# if !defined (LD_HAS_NO_DASH_L) -TILDE_LDFLAGS = $(SEARCH_LIB)$(TILDE_LIBDIR) -# endif /* !LD_HAS_NO_DASH_L */ - -#else /* !HAVE_TILDE_SOURCE */ -/**/# Guessed at location of the tilde -TILDE_LIBRARY = $(libdir)/libtilde.a -#endif /* !HAVE_TILDE_SOURCE */ - -#if defined (USE_GNU_MALLOC_LIBRARY) -/**/# Our malloc library. -MALLOC_LIBSRC = $(LIBSRC)malloclib/ -MALLOC_LIBDIR = $(LIBPATH)malloclib/ -MALLOC_ABSSRC = $${topdir}/$(MALLOC_LIBDIR) - -MALLOC_LIBRARY = $(MALLOC_LIBDIR)libmalloc.a - -MALLOC_SOURCE = $(MALLOC_LIBSRC)calloc.c $(MALLOC_LIBSRC)cfree.c \ - $(MALLOC_LIBSRC)free.c $(MALLOC_LIBSRC)malloc.c \ - $(MALLOC_LIBSRC)mcheck.c $(MALLOC_LIBSRC)memalign.c \ - $(MALLOC_LIBSRC)morecore.c $(MALLOC_LIBSRC)mstats.c \ - $(MALLOC_LIBSRC)mtrace.c $(MALLOC_LIBSRC)realloc.c \ - $(MALLOC_LIBSRC)valloc.c -MALLOC_OBJ = $(MALLOC_LIBDIR)calloc.c $(MALLOC_LIBDIR)cfree.c \ - $(MALLOC_LIBDIR)free.c $(MALLOC_LIBDIR)malloc.c \ - $(MALLOC_LIBDIR)mcheck.c $(MALLOC_LIBDIR)memalign.c \ - $(MALLOC_LIBDIR)morecore.c $(MALLOC_LIBDIR)mstats.c \ - $(MALLOC_LIBDIR)mtrace.c $(MALLOC_LIBDIR)realloc.c \ - $(MALLOC_LIBDIR)valloc.c - -MALLOC_SUPPORT= $(MALLOC_LIBSRC)Makefile -MALLOC_CFLAGS = -DUSE_GNU_MALLOC_LIBRARY - -# if !defined (LD_HAS_NO_DASH_L) -MALLOC_LDFLAGS = $(SEARCH_LIB)$(MALLOC_LIBDIR) -# endif /* !LD_HAS_NO_DASH_L */ -MALLOC_LIB = -lmalloc - -MALLOC_DEP = $(MALLOC_LIBRARY) -#else -MALLOC_LIBRARY = -#endif /* USE_GNU_MALLOC_LIBRARY */ - -BASHPOSIX_LIB = $(LIBSRC)posixheaders/ -BASHPOSIX_SUPPORT = $(BASHPOSIX_LIB)posixstat.h $(BASHPOSIX_LIB)ansi_stdlib.h \ - $(BASHPOSIX_LIB)memalloc.h $(BASHPOSIX_LIB)stdc.h - -/**/# Declare all of the sources for the libraries that we have. -LIBRARY_SOURCE = $(READLINE_SOURCE) $(HISTORY_SOURCE) $(TERMCAP_SOURCE) \ - $(GLOB_SOURCE) $(TILDE_SOURCE) $(MALLOC_SOURCE) -LIBRARY_DOC = $(READLINE_DOC) $(HISTORY_DOC) $(TERMCAP_DOC) $(GLOB_DOC) \ - $(TILDE_DOC) $(MALLOC_DOC) -LIBRARY_SUPPORT = $(READLINE_SUPPORT) $(HISTORY_SUPPORT) $(TERMCAP_SUPPORT) \ - $(GLOB_SUPPORT) $(TILDE_SUPPORT) $(MALLOC_SUPPORT) -LIBRARY_TAR = $(LIBRARY_SOURCE) $(LIBRARY_DOC) $(LIBRARY_SUPPORT) - -#if defined (READLINE) -/**/# You wish to compile with the line editing features installed. -READLINE_LIB = -lreadline - -/**/# You only need termcap (or curses) if you are linking with GNU Readline. -# if defined (USE_TERMCAP_EMULATION) -TERMCAP_LIB = -lcurses -# else /* !USE_TERMCAP_EMULATION */ -TERMCAP_LIB = -ltermcap -# endif /* !USE_TERMCAP_EMULATION */ - -/**/# Directory list for -L so that the link editor (ld) can find -lreadline. -# if !defined (LD_HAS_NO_DASH_L) -# if defined (HAVE_READLINE_SOURCE) -READLINE_LDFLAGS = $(SEARCH_LIB)$(RL_LIBDIR) $(TERMCAP_LDFLAGS) -# else -READLINE_LDFLAGS = $(TERMCAP_LDFLAGS) $(SEARCH_LIB)$(libdir) \ - $(SEARCH_LIB)/usr/local/lib -# endif /* HAVE_READLINE_SOURCE */ -# endif /* LD_HAS_NO_DASH_L */ - -/**/# The source and object of the bash<->readline interface code. -RL_SUPPORT_SRC = bashline.c bracecomp.c -RL_SUPPORT_OBJ = bashline.o $(BRACECOMP_OBJECT) -#endif /* READLINE */ - -/**/# The order is important. Most dependent first. -#if defined (LD_HAS_NO_DASH_L) -/**/# This linker does not know how to grok the -l flag, or perhaps how -/**/# to grok the -L flag, or both. -LIBRARIES = $(READLINE_LIBRARY) $(HISTORY_LIBRARY) $(TERMCAP_LIBRARY) \ - $(GLOB_LIBRARY) $(TILDE_LIBRARY) $(MALLOC_LIBRARY) $(LOCAL_LIBS) -#else /* !LD_HAS_NO_DASH_L */ -LIBRARIES = $(READLINE_LIB) $(HISTORY_LIB) $(TERMCAP_LIB) $(GLOB_LIB) \ - $(TILDE_LIB) $(MALLOC_LIB) $(LOCAL_LIBS) -#endif /* !LD_HAS_NO_DASH_L */ - -#if defined (READLINE) -# if defined (HAVE_TERMCAP_SOURCE) -TERMCAP_DEP = $(TERMCAP_LIBRARY) -# endif /* HAVE_TERMCAP_SOURCE */ -# if defined (HAVE_READLINE_SOURCE) -READLINE_DEP = $(READLINE_LIBRARY) -# endif /* HAVE_READLINE_SOURCE */ -#endif /* READLINE */ - -#if defined (HISTORY) && defined (HAVE_HISTORY_SOURCE) && !defined (READLINE) -HISTORY_DEP = $(HISTORY_LIBRARY) -#endif - -#if defined (USE_GLOB_LIBRARY) -GLOB_DEP = $(GLOB_LIBRARY) -#else -GLOBC = glob.c fnmatch.c -GLOBO = glob.o fnmatch.o -#endif /* USE_GLOB_LIBRARY */ - -#if defined (HAVE_TILDE_SOURCE) -TILDE_DEP = $(TILDE_LIBRARY) -#endif - -/**/# Source files for libraries that Bash depends on. -LIBDEP = $(READLINE_DEP) $(TERMCAP_DEP) $(GLOB_DEP) $(HISTORY_DEP) $(TILDE_DEP) $(MALLOC_DEP) - -/**/# Rules for cleaning the readline and termcap sources. -#if defined (HAVE_READLINE_SOURCE) -CLEAN_READLINE = (cd $(RL_LIBDIR); $(MAKE) $(MFLAGS) $@) -#else -CLEAN_READLINE = : -#endif /* !HAVE_READLINE_SOURCE */ - -#if defined (HAVE_HISTORY_SOURCE) -# if !defined (READLINE) -CLEAN_HISTORY = (cd $(HIST_LIBDIR); $(MAKE) $(MFLAGS) $@) -# else -CLEAN_HISTORY = : -# endif /* READLINE */ -#endif /* !HAVE_HISTORY_SOURCE */ - -#if defined (HAVE_TERMCAP_SOURCE) -CLEAN_TERMCAP = (cd $(TERM_LIBDIR); $(MAKE) $(MFLAGS) $@) -#else -CLEAN_TERMCAP = : -#endif /* !HAVE_TERMCAP_SOURCE */ - -#if defined (USE_GLOB_LIBRARY) -CLEAN_GLOB = (cd $(GLOB_LIBDIR); $(MAKE) $(MFLAGS) $@) -#else -CLEAN_GLOB = : -#endif /* !USE_GLOB_LIBRARY */ - -#if defined (HAVE_TILDE_SOURCE) -CLEAN_TILDE = (cd $(TILDE_LIBDIR); $(MAKE) $(MFLAGS) $@) -#else -CLEAN_TILDE = : -#endif /* !HAVE_TILDE_SOURCE */ - -#if defined (USE_GNU_MALLOC_LIBRARY) -CLEAN_MALLOC = (cd $(MALLOC_LIBDIR); $(MAKE) $(MFLAGS) $@) -#else -CLEAN_MALLOC = : -#endif /* !USE_GNU_MALLOC_LIBRARY */ - -LIBRARY_LDFLAGS = $(READLINE_LDFLAGS) $(HISTORY_LDFLAGS) $(TILDE_LDFLAGS) \ - $(GLOB_LDFLAGS) $(MALLOC_LDFLAGS) - -/**/# The directory which contains the source for malloc. The name must -/**/# end in a slash, as in "./lib/malloc/". -ALLOC_LIBSRC = $(LIBSRC)malloc/ -ALLOC_LIBDIR = $(LIBPATH)malloc/ -ALLOC_ABSSRC = $${topdir}/$(ALLOC_LIBDIR) - -/**/# Our malloc. -#if defined (USE_GNU_MALLOC) && !defined (USE_GNU_MALLOC_LIBRARY) - -MALLOC_OBJ = $(ALLOC_LIBDIR)malloc.o -MALLOC_SRC = $(ALLOC_LIBSRC)malloc.c -MALLOC_DEP = $(MALLOC_SRC) $(ALLOC_LIBSRC)getpagesize.h -MALLOC_FLAGS = -Drcheck -Dbotch=programming_error - -MALLOC_LIBRARY = - -#endif /* USE_GNU_MALLOC && !USE_GNU_MALLOC_LIBRARY */ - -/* If this user doesn't have alloca (), then we must try to supply them - with a working one. */ -#if !defined (HAVE_ALLOCA) -ALLOCA = $(ALLOC_LIBDIR)alloca.o -# if defined (ALLOCA_ASM) -ALLOCA_SOURCE = ALLOCA_ASM -ALLOCA_OBJECT = ALLOCA_OBJ -# else -ALLOCA_SOURCE = alloca.c -ALLOCA_OBJECT = alloca.o -# endif /* ALLOCA_ASM */ -ALLOCA_DEP = $(ALLOC_LIBSRC)$(ALLOCA_SOURCE) -#endif /* !HAVE_ALLOCA */ - -/* Compilation flags to use in the shell directory and to pass to builds - in subdirectories (readline, termcap) to ensure that alloca is treated - in a consistent fashion. */ -#if defined (HAVE_ALLOCA_H) -ALLOCA_H_DEFINE = -DHAVE_ALLOCA_H -#else -ALLOCA_H_DEFINE = -#endif /* HAVE_ALLOCA_H */ - -#if defined (HAVE_ALLOCA) -ALLOCA_DEFINE = -DHAVE_ALLOCA -#else -ALLOCA_DEFINE = -#endif /* HAVE_ALLOCA */ - -ALLOCA_CFLAGS = $(ALLOCA_DEFINE) $(ALLOCA_H_DEFINE) - -/* Protect the `i386' used in the definition of ALLOC_FILES. */ -#if defined (i386) -# undef i386 -# define i386_defined -#endif /* i386 */ - -ALLOC_HEADERS = $(ALLOC_LIBSRC)getpagesize.h -ALLOC_FILES = $(ALLOC_LIBSRC)malloc.c $(ALLOC_LIBSRC)alloca.c \ - $(ALLOC_LIBSRC)i386-alloca.s $(ALLOC_LIBSRC)x386-alloca.s \ - $(ALLOC_LIBSRC)xmalloc.c - -/* Perhaps restore the `i386' define. */ -#if defined (i386_defined) -# define i386 -# undef i386_defined -#endif /* i386_defined */ - -#if defined (USE_GNU_MALLOC) && !defined (USE_GNU_MALLOC_LIBRARY) -$(MALLOC_OBJ): $(MALLOC_DEP) - @sh $(SUPPORT_SRC)mkdirs $(ALLOC_LIBDIR) - @$(RM) $@ - @($(LIBINC_DECL); cd $(ALLOC_LIBDIR) ; \ - if [ ! -f Makefile ]; then cp $(ALLOC_ABSSRC)Makefile Makefile ; fi; \ - $(MAKE) $(MFLAGS) \ - CFLAGS='$(LIBRARY_CFLAGS) $(MALLOC_FLAGS)' \ - CPPFLAGS='$(CPPFLAGS)' MALLOC_SOURCE=$(MALLOC_SRC) \ - srcdir=$(ALLOC_ABSSRC) malloc.o ) -#endif /* USE_GNU_MALLOC && !USE_GNU_MALLOC_LIBRARY */ - -#if !defined (HAVE_ALLOCA) -$(ALLOCA): $(ALLOCA_DEP) - @sh $(SUPPORT_SRC)mkdirs $(ALLOC_LIBDIR) - @$(RM) $@ - @($(LIBINC_DECL); cd $(ALLOC_LIBDIR) ; \ - if [ ! -f Makefile ]; then cp $(ALLOC_ABSSRC)Makefile Makefile ; fi; \ - $(MAKE) $(MFLAGS) CC='$(CC)' \ - CFLAGS='$(LIBRARY_CFLAGS) $(MALLOC_FLAGS)' \ - CPPFLAGS='$(CPPFLAGS)' ALLOCA_SOURCE=$(ALLOCA_SOURCE) \ - ALLOCA_OBJECT=$(ALLOCA_OBJECT) \ - srcdir=$(ALLOC_ABSSRC) alloca.o ) -#endif /* !HAVE_ALLOCA */ - -/**/# The location of ranlib on your system. -#if defined (RANLIB_LOCATION) -RANLIB = RANLIB_LOCATION -#else -RANLIB = ranlib -#endif /* RANLIB_LOCATION */ - -/* **************************************************************** */ -/* */ -/* Support for optional object files */ -/* */ -/* **************************************************************** */ -#if !defined (HAVE_SYS_SIGLIST) -/**/# Since this system does not have sys_siglist, we define SIGLIST -/**/# as siglist.o. -SIGLIST = siglist.o -SIGLIST_FLAG=-DINITIALIZE_SIGLIST -#endif /* HAVE_SYS_SIGLIST */ - -#if !defined (HAVE_GETCWD) -/**/# Since this system does not have a correctly working getcwd (), -/**/# we define GETCWD as getcwd.o. -GETCWD = getcwd.o -#endif /* !HAVE_GETCWD */ - -/**/# The source and object of the curly brace expansion and completion code. -BRACES_SOURCE = braces.c -BRACECOMP_SOURCE = bracecomp.c -#if defined (BRACE_EXPANSION) -BRACES_OBJECT = braces.o -# if defined (READLINE) -BRACECOMP_OBJECT = bracecomp.o -# endif /* READLINE */ -#endif /* BRACE_EXPANSION */ - -#if defined (REQUIRED_LIBRARIES) -/**/# Locally required libraries. -LOCAL_LIBS = REQUIRED_LIBRARIES -#endif /* REQUIRED_LIBRARIES */ - -BUILTINS_LIB = builtins/libbuiltins.a - -/**/# The main source code for the Bourne Again SHell. -CSOURCES = shell.c parse.y general.c make_cmd.c print_cmd.c y.tab.c \ - dispose_cmd.c execute_cmd.c variables.c $(GLOBC) version.c \ - expr.c copy_cmd.c flags.c subst.c hash.c mailcheck.c \ - test.c trap.c jobs.c nojobs.c $(ALLOC_FILES) $(BRACES_SOURCE) \ - vprint.c input.c bashhist.c \ - unwind_prot.c siglist.c getcwd.c $(RL_SUPPORT_SRC) error.c - -HSOURCES = shell.h flags.h trap.h hash.h jobs.h builtins.h alias.c y.tab.h \ - general.h variables.h config.h $(ALLOC_HEADERS) alias.h maxpath.h \ - quit.h machines.h posixstat.h filecntl.h unwind_prot.h parser.h \ - command.h input.h error.h bashansi.h dispose_cmd.h make_cmd.h \ - subst.h externs.h siglist.h bashhist.h bashtypes.h - -SOURCES = $(CSOURCES) $(HSOURCES) $(BUILTIN_DEFS) - -/**/# Matching object files. -OBJECTS = shell.o y.tab.o general.o make_cmd.o print_cmd.o $(GLOBO) \ - dispose_cmd.o execute_cmd.o variables.o copy_cmd.o error.o \ - expr.o flags.o jobs.o subst.o hash.o mailcheck.o test.o \ - trap.o alias.o $(MALLOC_OBJ) $(ALLOCA) $(BRACES_OBJECT) \ - unwind_prot.o $(VPRINT_OBJ) input.o $(HIST_SUPPORT_OBJ) \ - $(SIGLIST) $(GETCWD) version.o $(RL_SUPPORT_OBJ) $(BUILTINS_LIB) - -/**/# Where the source code of the shell builtins resides. -BUILTIN_SRCDIR=$(srcdir)/builtins/ -/**/# The trailing slash was left off this definition on purpose -BUILTIN_ABSSRC=$${topdir}/builtins -DEFDIR = builtins/ -BUILTIN_DEFS = $(DEFDIR)alias.def $(DEFDIR)bind.def $(DEFDIR)break.def \ - $(DEFDIR)builtin.def $(DEFDIR)cd.def $(DEFDIR)colon.def \ - $(DEFDIR)command.def $(DEFDIR)declare.def $(LOAD_DEF) \ - $(DEFDIR)echo.def $(DEFDIR)enable.def $(DEFDIR)eval.def \ - $(DEFDIR)exec.def $(DEFDIR)exit.def $(DEFDIR)fc.def \ - $(DEFDIR)fg_bg.def $(DEFDIR)hash.def $(DEFDIR)help.def \ - $(DEFDIR)history.def $(DEFDIR)jobs.def $(DEFDIR)kill.def \ - $(DEFDIR)let.def $(DEFDIR)read.def $(DEFDIR)return.def \ - $(DEFDIR)set.def $(DEFDIR)setattr.def $(DEFDIR)shift.def \ - $(DEFDIR)source.def $(DEFDIR)suspend.def $(DEFDIR)test.def \ - $(DEFDIR)times.def $(DEFDIR)trap.def $(DEFDIR)type.def \ - $(DEFDIR)ulimit.def $(DEFDIR)umask.def $(DEFDIR)wait.def \ - $(DEFDIR)getopts.def $(DEFDIR)reserved.def -BUILTIN_C_SRC = $(DEFDIR)mkbuiltins.c $(DEFDIR)common.c \ - $(DEFDIR)hashcom.h $(DEFDIR)/bashgetopt.c $(GETOPT_SOURCE) -BUILTIN_C_OBJ = $(GETOPTS_OBJ) $(DEFDIR)common.o $(DEFDIR)bashgetopt.o -BUILTIN_OBJS = $(DEFDIR)alias.o $(DEFDIR)bind.o $(DEFDIR)break.o \ - $(DEFDIR)builtin.o $(DEFDIR)cd.o $(DEFDIR)colon.o \ - $(DEFDIR)command.o $(DEFDIR)declare.o $(LOAD_OBJ) \ - $(DEFDIR)echo.o $(DEFDIR)enable.o $(DEFDIR)eval.o \ - $(DEFDIR)exec.o $(DEFDIR)exit.o $(DEFDIR)fc.o \ - $(DEFDIR)fg_bg.o $(DEFDIR)hash.o $(DEFDIR)help.o \ - $(DEFDIR)history.o $(DEFDIR)jobs.o $(DEFDIR)kill.o \ - $(DEFDIR)let.o $(DEFDIR)read.o $(DEFDIR)return.o \ - $(DEFDIR)set.o $(DEFDIR)setattr.o $(DEFDIR)shift.o \ - $(DEFDIR)source.o $(DEFDIR)suspend.o $(DEFDIR)test.o \ - $(DEFDIR)times.o $(DEFDIR)trap.o $(DEFDIR)type.o \ - $(DEFDIR)ulimit.o $(DEFDIR)umask.o $(DEFDIR)wait.o \ - $(BUILTIN_C_OBJ) -#if defined (GETOPTS_BUILTIN) -GETOPTS_OBJ = $(DEFDIR)getopts.o -#endif -GETOPT_SOURCE = $(DEFDIR)getopt.c $(DEFDIR)getopt.h -PSIZE_SOURCE = $(DEFDIR)psize.sh $(DEFDIR)psize.c -BUILTIN_SUPPORT = $(DEFDIR)Makefile $(DEFDIR)ChangeLog $(PSIZE_SOURCE) \ - $(BUILTIN_C_SRC) - -/**/# Documentation for the shell. -DOCDIR = $(srcdir)/documentation/ -BASH_TEXINFO = $(DOCDIR)*.texi $(DOCDIR)*.tex \ - $(DOCDIR)*.dvi $(DOCDIR)Makefile -BASH_MAN = $(DOCDIR)bash.1 -BASHDOCS = $(BASH_TEXINFO) $(BASH_MAN) INSTALL README RELEASE -DOCUMENTATION = $(BASHDOCS) $(LIBRARY_DOC) - -/**/# Some example files demonstrating use of the shell. -/* This has to be written funny to avoid looking like a comment starter. */ -EXAMPLES = examples/[a-zA-Z]* - -ENDIAN_SUPPORT = endian.c -#if !defined (HAVE_WAIT_H) -ENDIAN_HEADER = bash_endian.h -#else -ENDIAN_HEADER = -#endif -ENDIAN_OUTPUT = endian.aux $(ENDIAN_HEADER) - -SIGNAMES_SUPPORT = signames.c -SIGNAMES_OUTPUT = signames.aux signames.h - -SUPPORT_SRC = $(srcdir)/support/ -SDIR = ./support/ -MKTARFILE = $(SDIR)mktarfile -SCRIPTS_SUPPORT = $(SUPPORT_SRC)mksysdefs $(SUPPORT_SRC)cppmagic \ - $(SUPPORT_SRC)cat-s $(MKTARFILE) $(SUPPORT_SRC)mail-shell \ - $(SUPPORT_SRC)inform $(SUPPORT_SRC)/fixdist \ - $(SUPPORT_SRC)mklinks $(SUPPORT_SRC)PORTING \ - $(SUPPORT_SRC)/clone.bash -FAQ = $(SUPPORT_SRC)FAQ - -TEST_SUITE = ./test-suite/ -TEST_SUITE_SUPPORT = $(TEST_SUITE)[a-zA-Z0-9]* $(SUPPORT_SRC)recho.c - -CREATED_SUPPORT = $(ENDIAN_OUTPUT) $(SIGNAMES_OUTPUT) sysdefs.h \ - $(SDIR)getcppsyms recho tests/recho tests/printenv - -SUPPORT = configure $(ENDIAN_SUPPORT) $(SIGNAMES_SUPPORT) $(SCRIPTS_SUPPORT) \ - $(BUILTIN_SUPPORT) COPYING Makefile cpp-Makefile ChangeLog \ - .distribution newversion.c $(EXAMPLES) $(SUPPORT_SRC)bash.xbm \ - $(FAQ) $(SUPPORT_SRC)getcppsyms.c $(TEST_SUITE_SUPPORT) - -/**/# BAGGAGE consists of things that you want to keep with the shell for some -/**/# reason, but do not actually use; old source code, etc. -BAGGAGE = - -/**/# Things that the world at large needs. -THINGS_TO_TAR = $(SOURCES) $(LIBRARY_TAR) $(BASHDOCS) $(SUPPORT) $(BAGGAGE) - -/**/# Keep GNU Make from exporting the entire environment for small machines. -.NOEXPORT: - -.made: $(Program) bashbug - cp .machine .made - -$(Program): .build $(OBJECTS) $(LIBDEP) $(srcdir)/.distribution - $(RM) $@ - $(PURIFY) $(CC) $(LDFLAGS) $(LIBRARY_LDFLAGS) -o $(Program) $(OBJECTS) $(LIBRARIES) - ls -l $(Program) - size $(Program) - -.build: $(SOURCES) cpp-Makefile newversion.aux - if ./newversion.aux -dir $(srcdir) -build; then mv -f newversion.h version.h; fi - @echo - @echo " ***************************************************" - @echo " * *" - @echo " * Making Bash-`cat $(srcdir)/.distribution`.`cat $(srcdir)/.patchlevel` for a $(Machine) running $(OS)" - @echo " * *" - @echo " ***************************************************" - @echo - @echo "$(Program) last made for a $(Machine) running $(OS)" >.machine - -bashbug: $(SUPPORT_SRC)bashbug.sh cpp-Makefile newversion.aux - @sed -e "s:@MACHINE@:$(Machine):" -e "s:@OS@:$(OS):" \ - -e "s:@CFLAGS@:$(CCFLAGS):" -e "s:@CC@:$(CC):" \ - -e "s:@RELEASE@:`cat $(srcdir)/.distribution`:" \ - -e "s:@PATCHLEVEL@:`cat $(srcdir)/.patchlevel`:" \ - $(SUPPORT_SRC)bashbug.sh > $@ - @chmod a+rx bashbug - -version.h: newversion.aux - if ./newversion.aux -dir $(srcdir) -build; then mv -f newversion.h version.h; fi - -y.tab.c: parser-built -y.tab.h: parser-built -parser-built: parse.y parser.h command.h stdc.h input.h - $(RM) $@ - -if test -f y.tab.h; then mv -f y.tab.h old-y.tab.h; fi - @echo expect 66 shift/reduce conflicts - $(BISON) -d $(srcdir)/parse.y - -if cmp -s old-y.tab.h y.tab.h; then mv old-y.tab.h y.tab.h; fi - touch $@ - -#if defined (READLINE) && defined (HAVE_READLINE_SOURCE) -$(READLINE_LIBRARY): $(READLINE_SOURCE) - build_lib_in_dir ($(RL_LIBDIR), libreadline.a, srcdir=$(RL_ABSSRC), $(RL_ABSSRC)Makefile) -#endif /* READLINE && HAVE_READLINE_SOURCE */ - -#if defined (HISTORY) && defined (HAVE_HISTORY_SOURCE) && !defined (READLINE) -$(HISTORY_LIBRARY): $(HISTORY_SOURCE) - build_lib_in_dir ($(HIST_LIBDIR), libhistory.a, srcdir=$(HIST_ABSSRC), $(HIST_ABSSRC)Makefile) -#endif /* HISTORY && HAVE_HISTORY_SOURCE && !READLINE */ - -#if defined (HAVE_TERMCAP_SOURCE) -$(TERMCAP_LIBRARY): $(TERMCAP_SOURCE) - build_lib_in_dir ($(TERM_LIBDIR), libtermcap.a, srcdir=$(TERM_ABSSRC), $(TERM_ABSSRC)Makefile) -#endif /* HAVE_TERMCAP_SOURCE */ - -#if defined (USE_GLOB_LIBRARY) -$(GLOB_LIBRARY): $(GLOB_SOURCE) - build_lib_in_dir ($(GLOB_LIBDIR), libglob.a, srcdir=$(GLOB_ABSSRC), $(GLOB_ABSSRC)Makefile) -#endif /* USE_GLOB_LIBRARY */ - -#if defined (HAVE_TILDE_SOURCE) -$(TILDE_LIBRARY): $(TILDE_SOURCE) - build_lib_in_dir ($(TILDE_LIBDIR), libtilde.a, srcdir=$(TILDE_ABSSRC), $(TILDE_ABSSRC)Makefile) -#endif /* HAVE_TILDE_SOURCE */ - -#if defined (USE_GNU_MALLOC) && defined (USE_GNU_MALLOC_LIBRARY) -$(MALLOC_LIBRARY): $(MALLOC_SOURCE) - build_lib_in_dir ($(MALLOC_LIBDIR), libmalloc.a, srcdir=$(MALLOC_ABSSRC), $(MALLOC_ABSSRC)Makefile) -#endif /* USE_GNU_MALLOC && USE_GNU_MALLOC_LIBRARY */ - -version.o: version.c version.h - -shell.o: shell.c shell.h flags.h shell.c posixstat.h filecntl.h stdc.h $(ENDIAN_HEADER) parser.h - $(RM) $@ - $(CC) $(CFG_FLAGS) $(CCFLAGS) $(CPPFLAGS) -c $(srcdir)/shell.c - -#if !defined (HAVE_WAIT_H) -$(ENDIAN_HEADER): endian.aux - $(RM) $@ - ./endian.aux $@ -#endif - -signames.h: signames.aux - $(RM) $@ - ./signames.aux $@ - -variables.o: variables.c shell.h hash.h flags.h variables.h - $(RM) $@ - $(CC) -c $(CCFLAGS) $(HOSTTYPE_DECL) $(CPPFLAGS) $(srcdir)/variables.c - -builtins/libbuiltins.a: $(BUILTIN_OBJS) config.h memalloc.h - build_builtins (libbuiltins.a) - -#if 0 -/* This is a nice idea, but it does not work right, and the syntax is - not universally available. */ -$(BUILTIN_OBJS): $(BUILTIN_DEFS) - build_builtins ($(@F)) -#endif - -builtins/common.o: $(BUILTIN_SRCDIR)common.c - build_builtins (common.o) -builtins/bashgetopt.o: $(BUILTIN_SRCDIR)bashgetopt.c - build_builtins (bashgetopt.o) - -builtins/builtext.h: builtins/libbuiltins.a - -/* Dependencies for the main bash source. */ -copy_cmd.o: shell.h command.h stdc.h hash.h -copy_cmd.o: general.h variables.h config.h memalloc.h quit.h -copy_cmd.o: dispose_cmd.h make_cmd.h subst.h externs.h -dispose_cmd.o: shell.h command.h stdc.h -dispose_cmd.o: general.h variables.h config.h memalloc.h quit.h -dispose_cmd.o: dispose_cmd.h make_cmd.h subst.h externs.h -error.o: error.h -execute_cmd.o: shell.h command.h stdc.h y.tab.h posixstat.h flags.h jobs.h -execute_cmd.o: general.h variables.h config.h memalloc.h quit.h hash.h -execute_cmd.o: unwind_prot.h siglist.h builtins/builtext.h -execute_cmd.o: dispose_cmd.h make_cmd.h subst.h externs.h bashtypes.h -expr.o: shell.h command.h stdc.h hash.h -expr.o: general.h variables.h config.h memalloc.h quit.h -expr.o: dispose_cmd.h make_cmd.h subst.h externs.h -flags.o: flags.h stdc.h config.h memalloc.h general.h quit.h -general.o: shell.h command.h stdc.h maxpath.h -general.o: general.h variables.h config.h memalloc.h quit.h machines.h -general.o: dispose_cmd.h make_cmd.h subst.h externs.h stdc.h -hash.o: shell.h command.h stdc.h hash.h -hash.o: general.h variables.h config.h memalloc.h quit.h -hash.o: dispose_cmd.h make_cmd.h subst.h externs.h stdc.h -jobs.o: shell.h command.h stdc.h hash.h trap.h jobs.h siglist.h -jobs.o: general.h variables.h config.h memalloc.h quit.h -jobs.o: dispose_cmd.h make_cmd.h subst.h externs.h builtins/builtext.h -mailcheck.o: posixstat.h maxpath.h variables.h -mailcheck.o: hash.h quit.h -make_cmd.o: shell.h command.h stdc.h flags.h input.h bashtypes.h -make_cmd.o: general.h variables.h config.h memalloc.h quit.h -make_cmd.o: dispose_cmd.h make_cmd.h subst.h externs.h -y.tab.o: shell.h command.h stdc.h flags.h maxpath.h alias.h -y.tab.o: general.h variables.h config.h memalloc.h quit.h -y.tab.o: dispose_cmd.h make_cmd.h subst.h externs.h bashtypes.h -print_cmd.o: shell.h command.h stdc.h y.tab.h -print_cmd.o: general.h variables.h config.h memalloc.h quit.h -print_cmd.o: dispose_cmd.h make_cmd.h subst.h externs.h -shell.o: shell.h command.h stdc.h flags.h machines.h -shell.o: general.h variables.h config.h memalloc.h quit.h -shell.o: dispose_cmd.h make_cmd.h subst.h externs.h -shell.o: posixstat.h filecntl.h jobs.h input.h -subst.o: shell.h command.h stdc.h flags.h jobs.h siglist.h bashtypes.h -subst.o: general.h variables.h config.h memalloc.h quit.h -subst.o: dispose_cmd.h make_cmd.h subst.h externs.h execute_cmd.h -test.o: posixstat.h -trap.o: trap.h shell.h command.h stdc.h hash.h unwind_prot.h signames.h -trap.o: general.h variables.h config.h memalloc.h quit.h -trap.o: dispose_cmd.h make_cmd.h subst.h externs.h -unwind_prot.o: config.h memalloc.h general.h unwind_prot.h -variables.o: shell.h command.h stdc.h hash.h flags.h -variables.o: config.h memalloc.h general.h variables.h quit.h -variables.o: execute_cmd.h dispose_cmd.h make_cmd.h subst.h externs.h -version.o: version.h .build - -alias.o: ansi_stdlib.h -bashline.o: ansi_stdlib.h -variables.o: ansi_stdlib.h -shell.o: ansi_stdlib.h -error.o: ansi_stdlib.h -hash.o: ansi_stdlib.h -signames.o: ansi_stdlib.h -expr.o: ansi_stdlib.h -general.o: ansi_stdlib.h -input.o: ansi_stdlib.h - -#if !defined (JOB_CONTROL) -jobs.o: nojobs.c -#endif /* !JOB_CONTROL */ - -#if defined (BRACE_EXPANSION) -braces.o: general.h shell.h variables.h quit.h config.h memalloc.h -braces.o: dispose_cmd.h make_cmd.h subst.h externs.h -braces.o: maxpath.h unwind_prot.h command.h stdc.h -# if defined (READLINE) -bracecomp.o: bracecomp.c -bracecomp.o: shell.h command.h hash.h builtins.h general.h variables.h -bracecomp.o: quit.h alias.h -bracecomp.o: dispose_cmd.h make_cmd.h subst.h externs.h stdc.h -# if defined (HAVE_READLINE_SOURCE) -bracecomp.o: $(RL_LIBSRC)readline.h -# endif /* HAVE_READLINE_SOURCE */ -# endif /* READLINE */ -#endif /* BRACE_EXPANSION */ - -#if defined (READLINE) -bashline.o: shell.h command.h stdc.h hash.h builtins.h execute_cmd.h -bashline.o: general.h variables.h config.h memalloc.h quit.h alias.h -bashline.o: dispose_cmd.h make_cmd.h subst.h externs.h -#endif /* READLINE */ - -/* Dependencies which rely on the user using the source to READLINE. */ -#if defined (READLINE) && defined (HAVE_READLINE_SOURCE) -bashline.o: $(RL_LIBSRC)chardefs.h $(RL_LIBSRC)readline.h $(RL_LIBSRC)keymaps.h -y.tab.o: $(RL_LIBSRC)keymaps.h $(RL_LIBSRC)chardefs.h $(RL_LIBSRC)readline.h -#endif /* READLINE && HAVE_READLINE_SOURCE */ - -#if defined (HISTORY) && defined (HAVE_HISTORY_SOURCE) -subst.o: $(HIST_LIBSRC)history.h -bashline.o: $(HIST_LIBSRC)history.h -y.tab.o: $(HIST_LIBSRC)history.h -#endif /* HISTORY && HAVE_HISTORY_SOURCE */ - -#if defined (USE_GLOB_LIBRARY) -subst.o: $(GLOB_LIBSRC)fnmatch.h -execute_cmd.o: $(GLOB_LIBSRC)fnmatch.h -#endif /* USE_GLOB_LIBRARY */ - -#if defined (HAVE_TILDE_SOURCE) -execute_cmd.o: $(TILDE_LIBSRC)tilde.h -general.o: $(TILDE_LIBSRC)tilde.h -mailcheck.o: $(TILDE_LIBSRC)tilde.h -shell.o: $(TILDE_LIBSRC)tilde.h -subst.o: $(TILDE_LIBSRC)tilde.h -variables.o: $(TILDE_LIBSRC)tilde.h -#endif /* HAVE_TILDE_SOURCE */ - -/* Dependencies for the shell builtins. */ -builtins/common.o: shell.h command.h config.h memalloc.h general.h error.h -builtins/common.o: variables.h input.h $(DEFDIR)hashcom.h siglist.h -builtins/common.o: quit.h unwind_prot.h maxpath.h jobs.h builtins.h -builtins/common.o: dispose_cmd.h make_cmd.h subst.h externs.h bashhist.h -builtins/common.o: execute_cmd.h stdc.h -builtins/alias.o: command.h config.h memalloc.h error.h general.h maxpath.h -builtins/alias.o: quit.h builtins/common.h -builtins/alias.o: shell.h command.h stdc.h unwind_prot.h variables.h -builtins/alias.o: dispose_cmd.h make_cmd.h subst.h externs.h -builtins/bind.o: command.h config.h memalloc.h error.h general.h maxpath.h -builtins/bind.o: dispose_cmd.h make_cmd.h subst.h externs.h stdc.h -builtins/bind.o: shell.h unwind_prot.h variables.h quit.h -builtins/bind.o: $(DEFDIR)bashgetopt.h -builtins/break.o: command.h config.h memalloc.h error.h general.h maxpath.h -builtins/break.o: shell.h unwind_prot.h variables.h quit.h -builtins/break.o: dispose_cmd.h make_cmd.h subst.h externs.h stdc.h -builtins/builtin.o: command.h config.h memalloc.h error.h general.h maxpath.h -builtins/builtin.o: quit.h $(DEFDIR)common.h -builtins/builtin.o: shell.h unwind_prot.h variables.h -builtins/builtin.o: dispose_cmd.h make_cmd.h subst.h externs.h stdc.h -builtins/cd.o: command.h config.h memalloc.h error.h general.h maxpath.h quit.h -builtins/cd.o: shell.h unwind_prot.h variables.h $(DEFDIR)common.h -builtins/cd.o: dispose_cmd.h make_cmd.h subst.h externs.h stdc.h -builtins/command.o: command.h config.h memalloc.h error.h general.h maxpath.h -builtins/command.o: quit.h $(DEFDIR)bashgetopt.h -builtins/command.o: shell.h unwind_prot.h variables.h -builtins/command.o: dispose_cmd.h make_cmd.h subst.h externs.h stdc.h -builtins/declare.o: command.h config.h memalloc.h error.h general.h maxpath.h -builtins/declare.o: shell.h unwind_prot.h variables.h quit.h -builtins/declare.o: dispose_cmd.h make_cmd.h subst.h externs.h stdc.h -builtins/echo.o: command.h config.h memalloc.h error.h general.h maxpath.h -builtins/echo.o: shell.h unwind_prot.h variables.h quit.h -builtins/echo.o: dispose_cmd.h make_cmd.h subst.h externs.h stdc.h -builtins/enable.o: command.h config.h memalloc.h error.h general.h maxpath.h -builtins/enable.o: shell.h unwind_prot.h variables.h quit.h -builtins/enable.o: dispose_cmd.h make_cmd.h subst.h externs.h stdc.h -builtins/eval.o: command.h config.h memalloc.h error.h general.h maxpath.h quit.h -builtins/eval.o: shell.h unwind_prot.h variables.h -builtins/eval.o: dispose_cmd.h make_cmd.h subst.h externs.h stdc.h -builtins/exec.o: command.h config.h memalloc.h error.h general.h maxpath.h quit.h -builtins/exec.o: shell.h unwind_prot.h variables.h $(DEFDIR)common.h stdc.h -builtins/exec.o: dispose_cmd.h make_cmd.h subst.h externs.h execute_cmd.h -builtins/exec.o: flags.h -builtins/exit.o: command.h config.h memalloc.h error.h general.h maxpath.h -builtins/exit.o: shell.h unwind_prot.h variables.h quit.h -builtins/exit.o: dispose_cmd.h make_cmd.h subst.h externs.h stdc.h -builtins/fc.o: builtins.h command.h stdc.h -builtins/fc.o: command.h config.h memalloc.h error.h general.h maxpath.h quit.h -builtins/fc.o: flags.h unwind_prot.h variables.h shell.h -builtins/fc.o: dispose_cmd.h make_cmd.h subst.h externs.h stdc.h -builtins/fc.o: $(DEFDIR)bashgetopt.h bashhist.h -builtins/fg_bg.o: command.h config.h memalloc.h error.h general.h maxpath.h -builtins/fg_bg.o: shell.h unwind_prot.h variables.h quit.h -builtins/fg_bg.o: dispose_cmd.h make_cmd.h subst.h externs.h stdc.h -builtins/getopts.o: command.h config.h memalloc.h error.h general.h maxpath.h -builtins/getopts.o: shell.h unwind_prot.h variables.h quit.h -builtins/getopts.o: dispose_cmd.h make_cmd.h subst.h externs.h stdc.h -builtins/hash.o: builtins.h command.h execute_cmd.h stdc.h -builtins/hash.o: command.h config.h memalloc.h error.h general.h maxpath.h -builtins/hash.o: shell.h unwind_prot.h variables.h $(DEFDIR)common.h quit.h -builtins/help.o: command.h config.h memalloc.h error.h general.h maxpath.h -builtins/help.o: dispose_cmd.h make_cmd.h subst.h externs.h stdc.h -builtins/help.o: shell.h unwind_prot.h variables.h quit.h -builtins/history.o: command.h config.h memalloc.h error.h general.h maxpath.h -builtins/history.o: quit.h dispose_cmd.h make_cmd.h subst.h externs.h stdc.h -builtins/history.o: filecntl.h shell.h unwind_prot.h variables.h -builtins/history.o: bashhist.h -builtins/inlib.o: command.h config.h memalloc.h error.h general.h maxpath.h -builtins/inlib.o: shell.h unwind_prot.h variables.h quit.h -builtins/inlib.o: dispose_cmd.h make_cmd.h subst.h externs.h stdc.h -builtins/jobs.o: command.h config.h memalloc.h error.h general.h maxpath.h -builtins/jobs.o: quit.h $(DEFDIR)bashgetopt.h -builtins/jobs.o: shell.h unwind_prot.h variables.h -builtins/jobs.o: dispose_cmd.h make_cmd.h subst.h externs.h stdc.h -builtins/kill.o: command.h config.h memalloc.h error.h general.h maxpath.h -builtins/kill.o: quit.h dispose_cmd.h make_cmd.h subst.h externs.h stdc.h -builtins/kill.o: shell.h trap.h unwind_prot.h variables.h -builtins/let.o: command.h config.h memalloc.h error.h general.h maxpath.h -builtins/let.o: quit.h dispose_cmd.h make_cmd.h subst.h externs.h stdc.h -builtins/let.o: shell.h unwind_prot.h variables.h -builtins/read.o: command.h config.h memalloc.h error.h general.h maxpath.h -builtins/read.o: quit.h dispose_cmd.h make_cmd.h subst.h externs.h stdc.h -builtins/read.o: shell.h unwind_prot.h variables.h -builtins/return.o: command.h config.h memalloc.h error.h general.h maxpath.h -builtins/return.o: quit.h dispose_cmd.h make_cmd.h subst.h externs.h stdc.h -builtins/return.o: shell.h unwind_prot.h variables.h -builtins/set.o: command.h config.h memalloc.h error.h general.h maxpath.h -builtins/set.o: quit.h dispose_cmd.h make_cmd.h subst.h externs.h -builtins/set.o: shell.h unwind_prot.h variables.h flags.h stdc.h -builtins/setattr.o: command.h config.h memalloc.h error.h general.h maxpath.h -builtins/setattr.o: quit.h $(DEFDIR)common.h $(DEFDIR)bashgetopt.h -builtins/setattr.o: shell.h unwind_prot.h variables.h -builtins/setattr.o: dispose_cmd.h make_cmd.h subst.h externs.h stdc.h -builtins/shift.o: command.h config.h memalloc.h error.h general.h maxpath.h -builtins/shift.o: quit.h dispose_cmd.h make_cmd.h subst.h externs.h stdc.h -builtins/shift.o: shell.h unwind_prot.h variables.h -builtins/shift.o: dispose_cmd.h make_cmd.h subst.h externs.h stdc.h -builtins/source.o: command.h config.h memalloc.h error.h general.h maxpath.h -builtins/source.o: quit.h dispose_cmd.h make_cmd.h subst.h externs.h stdc.h -builtins/source.o: shell.h unwind_prot.h variables.h -builtins/suspend.o: command.h config.h memalloc.h error.h general.h maxpath.h -builtins/suspend.o: quit.h dispose_cmd.h make_cmd.h subst.h externs.h stdc.h -builtins/suspend.o: shell.h unwind_prot.h variables.h -builtins/test.o: command.h config.h memalloc.h error.h general.h maxpath.h -builtins/test.o: quit.h dispose_cmd.h make_cmd.h subst.h externs.h stdc.h -builtins/test.o: shell.h unwind_prot.h variables.h -builtins/times.o: command.h config.h memalloc.h error.h general.h maxpath.h -builtins/times.o: quit.h dispose_cmd.h make_cmd.h subst.h externs.h stdc.h -builtins/times.o: shell.h unwind_prot.h variables.h -builtins/trap.o: command.h config.h memalloc.h error.h general.h maxpath.h -builtins/trap.o: quit.h $(DEFDIR)common.h -builtins/trap.o: shell.h unwind_prot.h variables.h -builtins/trap.o: dispose_cmd.h make_cmd.h subst.h externs.h stdc.h -builtins/type.o: command.h config.h memalloc.h error.h general.h maxpath.h -builtins/type.o: quit.h $(DEFDIR)common.h -builtins/type.o: shell.h unwind_prot.h variables.h execute_cmd.h -builtins/type.o: dispose_cmd.h make_cmd.h subst.h externs.h stdc.h -builtins/ulimit.o: command.h config.h memalloc.h error.h general.h maxpath.h -builtins/ulimit.o: quit.h dispose_cmd.h make_cmd.h subst.h externs.h stdc.h -builtins/ulimit.o: shell.h unwind_prot.h variables.h -builtins/umask.o: command.h config.h memalloc.h error.h general.h maxpath.h -builtins/umask.o: quit.h dispose_cmd.h make_cmd.h subst.h externs.h stdc.h -builtins/umask.o: shell.h unwind_prot.h variables.h -builtins/wait.o: command.h config.h memalloc.h error.h general.h maxpath.h -builtins/wait.o: quit.h dispose_cmd.h make_cmd.h subst.h externs.h stdc.h -builtins/wait.o: shell.h unwind_prot.h variables.h - -builtins/bashgetopt.o: bashansi.h ansi_stdlib.h -builtins/mkbuiltins.o: bashansi.h ansi_stdlib.h -builtins/fc.o: bashansi.h ansi_stdlib.h - -#if defined (READLINE) && defined (HAVE_READLINE_SOURCE) -builtins/bind.o: $(RL_LIBSRC)chardefs.h $(RL_LIBSRC)readline.h $(RL_LIBSRC)keymaps.h -#endif /* READLINE && HAVE_READLINE_SOURCE */ - -#if defined (HISTORY) && defined (HAVE_HISTORY_SOURCE) -builtins/bind.o: $(HIST_LIBSRC)history.h -builtins/fc.o: $(HIST_LIBSRC)history.h -builtins/history.o: $(HIST_LIBSRC)history.h -#endif /* HISTORY && HAVE_HISTORY_SOURCE */ - -#if defined (HAVE_TILDE_SOURCE) -builtins/common.o: $(TILDE_LIBSRC)tilde.h -builtins/cd.o: $(TILDE_LIBSRC)tilde.h -#endif /* HAVE_TILDE_SOURCE */ - -builtins/alias.o: builtins/alias.def -builtins/bind.o: builtins/bind.def -builtins/break.o: builtins/break.def -builtins/builtin.o: builtins/builtin.def -builtins/cd.o: builtins/cd.def -builtins/colon.o: builtins/colon.def -builtins/command.o: builtins/command.def -builtins/declare.o: builtins/declare.def -builtins/echo.o: builtins/echo.def -builtins/enable.o: builtins/enable.def -builtins/eval.o: builtins/eval.def -builtins/exec.o: builtins/exec.def -builtins/exit.o: builtins/exit.def -builtins/fc.o: builtins/fc.def -builtins/fg_bg.o: builtins/fg_bg.def -builtins/getopts.o: builtins/getopts.def -builtins/hash.o: builtins/hash.def -builtins/help.o: builtins/help.def -builtins/histctl.o: builtins/histctl.def -builtins/history.o: builtins/history.def -builtins/inlib.o: builtins/inlib.def -builtins/jobs.o: builtins/jobs.def -builtins/kill.o: builtins/kill.def -builtins/let.o: builtins/let.def -builtins/read.o: builtins/read.def -builtins/reserved.o: builtins/reserved.def -builtins/return.o: builtins/return.def -builtins/set.o: builtins/set.def -builtins/setattr.o: builtins/setattr.def -builtins/shift.o: builtins/shift.def -builtins/source.o: builtins/source.def -builtins/suspend.o: builtins/suspend.def -builtins/test.o: builtins/test.def -builtins/times.o: builtins/times.def -builtins/trap.o: builtins/trap.def -builtins/type.o: builtins/type.def -builtins/ulimit.o: builtins/ulimit.def -builtins/umask.o: builtins/umask.def -builtins/wait.o: builtins/wait.def - -$(Program).tar: $(THINGS_TO_TAR) .distribution - @$(MKTARFILE) $(Program) `cat .distribution` $(THINGS_TO_TAR) - -$(Program).tar$(COMPRESS_EXT): $(Program).tar - $(COMPRESS) < $(Program).tar > $@ - -clone: $(THINGS_TO_TAR) - @$(MKTARFILE) +notar $(Machine) $(OS) $(THINGS_TO_TAR) - -installdirs: - @${SHELL} $(SUPPORT_SRC)mkdirs $(bindir) - @${SHELL} $(SUPPORT_SRC)mkdirs $(mandir) $(man3dir) - @${SHELL} $(SUPPORT_SRC)mkdirs $(infodir) - -install: .made installdirs documentation - -if [ -f $(bindir)/$(Program) ]; then \ - rm -f $(bindir)/$(Program).old ;\ - ln $(bindir)/$(Program) $(bindir)/$(Program).old; \ - fi - $(INSTALL_PROGRAM) $(Program) $(bindir)/$(Program) - -if [ -f $(bindir)/bashbug ]; \ - then mv $(bindir)/bashbug $(bindir)/bashbug.old; \ - fi - $(INSTALL_PROGRAM) bashbug $(bindir)/bashbug - ( cd $(DOCDIR) ; $(MAKE) $(MFLAGS) mandir=$(mandir) \ - man3dir=$(man3dir) infodir=$(infodir) $@ ) - -uninstall: .made - $(RM) $(bindir)/$(Program) installed-$(Program) $(bindir)/bashbug - ( cd $(DOCDIR) ; $(MAKE) $(MFLAGS) mandir=$(mandir) man3dir=$(man3dir) infodir=$(infodir) $@ ) - -.distribution: - ./newversion.aux -dir $(srcdir) -dist `$(Program) -c 'echo $$BASH_VERSION'` - -distribution: $(Program) $(Program).tar$(COMPRESS_EXT) .distribution - @echo cp $(Program).tar$(COMPRESS_EXT) \ - $(Program)-`cat .distribution`.tar$(COMPRESS_EXT) - @cp $(Program).tar$(COMPRESS_EXT) \ - $(Program)-`cat .distribution`.tar$(COMPRESS_EXT) - -mailable: distribution - /bin/rm -rf uuencoded - mkdir uuencoded - $(SHELL) -c 'f=$(Program)-`cat .distribution`.tar.Z;uuencode $$f $$f | split -800 - uuencoded/$$f.uu.' - -newversion.aux: newversion.c - $(CC) $(CCFLAGS) -o $@ $(srcdir)/newversion.c - -newversion: newversion.aux - $(RM) .build - ./newversion.aux -dir $(srcdir) -dist - mv -f newversion.h version.h - $(MAKE) -f $(srcdir)/Makefile $(MFLAGS) srcdir=$(srcdir) - -documentation: force - (cd $(DOCDIR); $(MAKE) $(MFLAGS)) - -force: - -tags: $(SOURCES) $(BUILTIN_C_SRC) $(LIBRARY_SOURCE) - etags $(SOURCES) $(BUILTIN_C_SRC) $(LIBRARY_SOURCE) - -TAGS: $(SOURCES) $(BUILTIN_C_SRC) $(LIBRARY_SOURCE) - ctags -x $(SOURCES) $(BUILTIN_C_SRC) $(LIBRARY_SOURCE) > $@ - -basic-clean: - $(RM) $(OBJECTS) $(Program) bashbug ansi-Makefile *.aux - $(RM) .build .made .machine version.h - $(RM) $(CREATED_SUPPORT) - $(RM) tags TAGS - -mostlyclean: - $(RM) $(OBJECTS) $(Program) bashbug - $(RM) .build .made .machine version.h - $(RM) tags TAGS - (cd $(DOCDIR) && $(MAKE) $(MFLAGS) $@ ) - (cd builtins && $(MAKE) $(MFLAGS) $@ ) - $(CLEAN_READLINE) ; - $(CLEAN_HISTORY) ; - $(CLEAN_TERMCAP) ; - $(CLEAN_GLOB) ; - $(CLEAN_TILDE) ; - $(CLEAN_MALLOC) ; - -distclean clean: basic-clean - (cd $(DOCDIR) && $(MAKE) $(MFLAGS) $@ ) - (cd builtins && $(MAKE) $(MFLAGS) $@ ) - $(CLEAN_READLINE) ; - $(CLEAN_HISTORY) ; - $(CLEAN_TERMCAP) ; - $(CLEAN_GLOB) ; - $(CLEAN_TILDE) ; - $(CLEAN_MALLOC) ; - $(RM) bash-Makefile - -realclean maintainer-clean: basic-clean - $(RM) y.tab.c y.tab.h parser-built - (cd $(DOCDIR) && $(MAKE) $(MFLAGS) $@ ) - (cd builtins && $(MAKE) $(MFLAGS) $@ ) - $(CLEAN_READLINE) ; - $(CLEAN_HISTORY) ; - $(CLEAN_TERMCAP) ; - $(CLEAN_GLOB) ; - $(CLEAN_TILDE) ; - $(CLEAN_MALLOC) ; - $(RM) bash-Makefile - -recho: $(SUPPORT_SRC)recho.c - @$(CC) -o $@ $(SUPPORT_SRC)recho.c - -tests check: force $(Program) recho - @cp recho $(SUPPORT_SRC)printenv tests - ( cd tests ; sh run-all ) - -/**/# Here is a convenient rule when you arrive at a new site and wish to -/**/# install bash on several different architectures. It creates a new -/**/# directory to hold the results of compilation. The directory is -/**/# named Machine-OS. -architecture: $(Machine)-$(OS)/$(Program) - -$(Machine)-$(OS): - -mkdir $(Machine)-$(OS) - -$(Machine)-$(OS)/$(Program): $(Machine)-$(OS) $(Program) - mv $(Program) $(Machine)-$(OS) - mv sysdefs.h $(Machine)-$(OS) - mv $(SDIR)getcppsyms $(Machine)-$(OS) - $(MAKE) $(MFLAGS) clean - -DEFINES: config.h memalloc.h cpp-Makefile sysdefs.h - echo $(CCFLAGS) $(CPPFLAGS) >DEFINES diff --git a/dispose_cmd.c b/dispose_cmd.c index f420fe1..86443f1 100644 --- a/dispose_cmd.c +++ b/dispose_cmd.c @@ -18,6 +18,13 @@ along with Bash; see the file COPYING. If not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include "config.h" + +#if defined (HAVE_UNISTD_H) +# include +#endif + +#include "bashansi.h" #include "shell.h" /* Dispose of the command structure passed. */ @@ -25,7 +32,8 @@ void dispose_command (command) COMMAND *command; { - if (!command) return; + if (command == 0) + return; if (command->redirects) dispose_redirects (command->redirects); @@ -33,27 +41,24 @@ dispose_command (command) switch (command->type) { case cm_for: - { - register FOR_COM *c = command->value.For; - dispose_word (c->name); - dispose_words (c->map_list); - dispose_command (c->action); - free (c); - break; - } - #if defined (SELECT_COMMAND) case cm_select: +#endif { - register SELECT_COM *c = command->value.Select; + register FOR_COM *c; +#if defined (SELECT_COMMAND) + if (command->type == cm_select) + c = (FOR_COM *)command->value.Select; + else +#endif + c = command->value.For; dispose_word (c->name); dispose_words (c->map_list); dispose_command (c->action); free (c); break; } -#endif - + case cm_group: { dispose_command (command->value.Group->command); @@ -63,12 +68,13 @@ dispose_command (command) case cm_case: { - register CASE_COM *c = command->value.Case; - PATTERN_LIST *t, *p = c->clauses; + register CASE_COM *c; + PATTERN_LIST *t, *p; + c = command->value.Case; dispose_word (c->word); - while (p) + for (p = c->clauses; p; ) { dispose_words (p->patterns); dispose_command (p->action); @@ -83,8 +89,9 @@ dispose_command (command) case cm_until: case cm_while: { - register WHILE_COM *c = command->value.While; + register WHILE_COM *c; + c = command->value.While; dispose_command (c->test); dispose_command (c->action); free (c); @@ -93,7 +100,9 @@ dispose_command (command) case cm_if: { - register IF_COM *c = command->value.If; + register IF_COM *c; + + c = command->value.If; dispose_command (c->test); dispose_command (c->true_case); dispose_command (c->false_case); @@ -103,7 +112,9 @@ dispose_command (command) case cm_simple: { - register SIMPLE_COM *c = command->value.Simple; + register SIMPLE_COM *c; + + c = command->value.Simple; dispose_words (c->words); dispose_redirects (c->redirects); free (c); @@ -112,7 +123,9 @@ dispose_command (command) case cm_connection: { - register CONNECTION *c = command->value.Connection; + register CONNECTION *c; + + c = command->value.Connection; dispose_command (c->first); dispose_command (c->second); free (c); @@ -121,7 +134,9 @@ dispose_command (command) case cm_function_def: { - register FUNCTION_DEF *c = command->value.Function_def; + register FUNCTION_DEF *c; + + c = command->value.Function_def; dispose_word (c->name); dispose_command (c->command); free (c); @@ -129,7 +144,7 @@ dispose_command (command) } default: - report_error ("Attempt to free unknown command type `%d'.\n", command->type); + programming_error ("dispose_command: bad command type `%d'", command->type); break; } free (command); @@ -140,8 +155,7 @@ void dispose_word (word) WORD_DESC *word; { - if (word->word) - free (word->word); + FREE (word->word); free (word); } @@ -151,6 +165,7 @@ dispose_words (list) WORD_LIST *list; { WORD_LIST *t; + while (list) { t = list; @@ -189,7 +204,7 @@ dispose_redirects (list) case r_reading_until: case r_deblank_reading_until: free (t->here_doc_eof); - /* ... */ + /*FALLTHROUGH*/ case r_output_direction: case r_input_direction: case r_inputa_direction: @@ -200,6 +215,8 @@ dispose_redirects (list) case r_duplicating_input_word: case r_duplicating_output_word: dispose_word (t->redirectee.filename); + /* FALLTHROUGH */ + default: break; } free (t); diff --git a/doc/FAQ b/doc/FAQ new file mode 100644 index 0000000..2723f8f --- /dev/null +++ b/doc/FAQ @@ -0,0 +1,1098 @@ +This is the Bash FAQ, version 2.1, for Bash version 2.0. + +This document contains a set of frequently-asked questions concerning +Bash, the GNU Bourne-Again Shell. Bash is a freely-available command +interpreter with advanced features for both interactive use and shell +programming. + +Another good source of basic information about shells is the collection +of FAQ articles periodically posted to comp.unix.shell. + +Questions and comments concerning this document should be sent to +chet@po.cwru.edu. + +This document is available for anonymous FTP with the URL + +ftp://slc2.ins.cwru.edu/pub/bash/FAQ + +---------- +Contents: + +Section A: The Basics + +1) What is it? +2) What's the latest version? +3) Where can I get it? +4) On what machines will bash run? +5) How can I build bash with gcc? +6) How can I make bash my login shell? +7) I just changed my login shell to bash, and now I can't FTP into my + machine. Why not? +8) What's the `POSIX 1003.2 standard'? +9) What is the bash `posix mode'? + +Section B: The latest version + +10) What's new in version 2.0? +11) Are there any user-visible incompatibilities between bash-2.0 and + bash-1.14.7? + +Section C: Differences from other Unix shells + +12) How does bash differ from sh, the Bourne shell? +13) How does bash differ from the Korn shell, version ksh88? +14) Which new features in ksh-93 are not in bash, and which are? + +Section D: Why does bash do some things differently than other Unix shells? + +15) Why does bash run a different version of `command' than + `which command' says it will? +16) Why doesn't bash treat brace expansions exactly like csh? +17) Why doesn't bash have csh variable modifiers? +18) How can I make my csh aliases work when I convert to bash? +19) How can I pipe standard output and standard error from one command to + another, like csh does with `|&'? +20) Now that I've converted from ksh to bash, are there equivalents to + ksh features like autoloaded functions and the `whence' command? + +Section E: How can I get bash to do certain things, and why does bash do + things the way it does? + +21) Why is the bash builtin `test' slightly different from /bin/test? +22) Why does bash sometimes say `Broken pipe'? +23) How can I get bash to read and display eight-bit characters? +24) How do I write a function `x' to replace builtin command `x', but + still invoke the command from within the function? +25) When I have terminal escape sequences in my prompt, why does bash + wrap lines at the wrong column? +26) How can I find the value of a shell variable whose name is the value + of another shell variable? +27) If I pipe the output of a command into `read variable', why doesn't + the output show up in $variable when the read command finishes? +28) I have a bunch of shell scripts that use backslash-escaped characters + in arguments to `echo'. Bash doesn't interpret these characters. Why + not, and how can I make it understand them? +29) Why doesn't a while or for loop get suspended when I type ^Z? +30) How can I make the bash `time' reserved word print timing output that + looks like the output from my system's /usr/bin/time? + +Section F: Things to watch out for on certain Unix versions + +31) Why can't I use command line editing in my `cmdtool'? +32) I built bash on Solaris 2. Why do globbing expansions and filename + completion chop off the first few characters of each filename? +33) Why does bash dump core after I interrupt username completion or + `~user' tilde expansion on a machine running NIS? +34) I'm running SVR4.2. Why is the line erased every time I type `@'? +35) Why does bash report syntax errors when my C News scripts use a + redirection before a subshell command? + +Section G: Where do I go from here? + +36) How do I report bugs in bash, and where should I look for fixes and + advice? +37) What kind of bash documentation is there? +38) What's coming in future versions? +39) What's on the bash `wish list'? +40) When will the next release appear? + +---------- +Section A: The Basics + +1) What is it? + +Bash is a Unix command interpreter (shell). It is an implementation of +the Posix 1003.2 shell standard, and resembles the Korn and System V +shells. + +Bash contains a number of enhancements over those shells, both +for interactive use and shell programming. Features geared +toward interactive use include command line editing, command +history, job control, aliases, and prompt expansion. Programming +features include additional variable expansions, shell +arithmetic, and a number of variables and options to control +shell behavior. + +Bash was originally written by Brian Fox of the Free Software +Foundation. The current developer and maintainer is Chet Ramey +of Case Western Reserve University. + +2) What's the latest version? + +The latest version is 2.0, first made available on December 23, 1996. + +3) Where can I get it? + +Bash is the GNU project's shell, and so is available from the +master GNU archive site, prep.ai.mit.edu, and its mirrors. The +latest version is also available for FTP from slc2.ins.cwru.edu, +the maintainer's machine. The following URLs tell how to get +version 2.0: + +ftp://prep.ai.mit.edu/pub/gnu/bash-2.0.tar.gz +ftp://slc2.ins.cwru.edu/pub/dist/bash-2.0.tar.gz + +Formatted versions of the documentation are available with the URLs: + +ftp://prep.ai.mit.edu/pub/gnu/bash-doc-2.0.tar.gz +ftp://slc2.ins.cwru.edu/pub/dist/bash-doc-2.0.tar.gz + +4) On what machines will bash run? + +Bash has been ported to nearly every version of UNIX. All you +should have to do to build it on a machine for which a port +exists is to type `configure' and then `make'. The build process +will attempt to discover the version of UNIX you have and tailor +itself accordingly, using a script created by GNU autoconf. + +More information appears in the file `INSTALL' in the distribution. + +5) How can I build bash with gcc? + +Bash configures to use gcc by default if it is available. Read the +file INSTALL in the distribution for more information. + +6) How can I make bash my login shell? + +Some machines let you use `chsh' to change your login shell. Other +systems use `passwd -s'. If one of these works for you, that's all +you need. Note that many systems require the full pathname to a shell +to appear in /etc/shells before you can make it your login shell. For +this, you may need the assistance of your friendly local system +administrator. + +If you cannot do this, you can still use bash as your login shell, but +you need to perform some tricks. The basic idea is to add a command +to your login shell's startup file to replace your login shell with +bash. + +For example, if your login shell is csh or tcsh, and you have installed +bash in /usr/gnu/bin/bash, add the following line to ~/.login: + + if ( -f /usr/gnu/bin/bash ) exec /usr/gnu/bin/bash --login + +(the `--login' tells bash that it is a login shell). + +It's not a good idea to put this command into ~/.cshrc, because every +csh you run without the `-f' option, even ones started to run csh scripts, +reads that file. If you must put the command in ~/.cshrc, use something +like + + if ( $?prompt ) exec /usr/gnu/bin/bash --login + +to ensure that bash is exec'd only when the csh is interactive. + +If your login shell is sh or ksh, you have to do two things. First, add +a line similar to the above to ~/.profile: + + [ -f /usr/gnu/bin/bash ] && exec /usr/gnu/bin/bash --login + +Next, create an empty file in your home directory named `.bash_profile'. +The existence of this file will prevent the exec'd bash from trying to +read ~/.profile, and re-execing itself over and over again. ~/.bash_profile +is the file bash tries to read initialization commands from when it is +invoked as a login shell. + +7) I just changed my login shell to bash, and now I can't FTP into my + machine. Why not? + +You must add the full pathname to bash to the file /etc/shells. As +noted in the answer to the previous question, many systems require +this before you can make bash your login shell. + +Most versions of ftpd use this file to prohibit `special' users +such as `uucp' and `news' from using FTP. + +8) What's the `POSIX 1003.2 standard'? + +POSIX is a name originally coined by Richard Stallman for a +family of open system standards based on UNIX. There are a +number of aspects of UNIX under consideration for +standardization, from the basic system services at the system +call and C library level to applications and tools to system +administration and management. Each area of standardization is +assigned to a working group in the 1003 series. + +The POSIX Shell and Utilities standard has been developed by IEEE +Working Group 1003.2 (POSIX.2). It concentrates on the command +interpreter interface and utility programs commonly executed from +the command line or by other programs. An initial version of the +standard has been approved and published by the IEEE, and work is +currently underway to update it. + +Bash is concerned with the aspects of the shell's behavior +defined by POSIX.2. The shell command language has of course +been standardized, including the basic flow control and program +execution constructs, I/O redirection and pipelining, argument +handling, variable expansion, and quoting. + +The `special' builtins, which must be implemented as part of the +shell to provide the desired functionality, are specified as +being part of the shell; examples of these are `eval' and +`export'. Other utilities appear in the sections of POSIX.2 not +devoted to the shell which are commonly (and in some cases must +be) implemented as builtin commands, such as `read' and `test'. +POSIX.2 also specifies aspects of the shell's interactive +behavior as part of the UPE, including job control and command +line editing. Only vi-style line editing commands have been +standardized; emacs editing commands were left out due to +objections. + +9) What is the bash `posix mode'? + +Although bash is an implementation of the POSIX.2 shell +specification, there are areas where the bash default behavior +differs from that spec. The bash `posix mode' changes the bash +behavior in these areas so that it obeys the spec more closely. + +Posix mode is entered by starting bash with the --posix option or +executing `set -o posix' after bash is running. + +The specific aspects of bash which change when posix mode is +active are listed in the file CWRU/POSIX.NOTES in the bash +distribution. They are also listed in a section in the Bash +Reference Manual. + +Section B: The latest version + +10) What's new in version 2.0? + +This version contains extensive changes and new features. Here's a +short list: + +new `time' reserved word to time pipelines, shell builtins, and + shell functions +one-dimensional arrays with a new compound assignment statement, + appropriate expansion constructs and modifications to some + of the builtins (read, declare, etc.) to use them +new quoting syntaxes for ANSI-C string expansion and locale-specific + string translation +new expansions to do substring extraction, pattern replacement, and + indirect variable expansion +new builtins: `disown' and `shopt' +new variables: HISTIGNORE, SHELLOPTS, PIPESTATUS, DIRSTACK, GLOBIGNORE, + MACHTYPE, BASH_VERSINFO +special handling of many unused or redundant variables removed + (e.g., $notify, $glob_dot_filenames, $no_exit_on_failed_exec) +dynamic loading of new builtin commands; many loadable examples provided +new prompt expansions: \a, \e, \n, \H, \T, \@, \v, \V +history and aliases available in shell scripts +new readline variables: enable-keypad, mark-directories, input-meta, + visible-stats, disable-completion, comment-begin +new readline commands to manipulate the mark and operate on the region +new readline emacs mode commands and bindings for ksh-88 compatibility +updated and extended builtins +new DEBUG trap +expanded (and now documented) restricted shell mode + +implementation stuff: +autoconf-based configuration +nearly all of the bugs reported since version 1.14 have been fixed +most builtins converted to use builtin `getopt' for consistency +most builtins use -p option to display output in a reusable form + (for consistency) +grammar tighter and smaller (66 reduce-reduce conflicts gone) +lots of code now smaller and faster +test suite greatly expanded + +11) Are there any user-visible incompatibilities between bash-2.0 and + bash-1.14.7? + +There are a few incompatibilities between version 1.14.7 and version 2.0. +They are detailed in the file COMPAT in the bash-2.0 distribution. + +Section C: Differences from other Unix shells + +12) How does bash differ from sh, the Bourne shell? + +This is a non-comprehensive list of features that differentiate bash +from the SVR4.2 shell. The bash manual page explains these more +completely. + +Things bash has that sh does not: + long invocation options + `!' reserved word to invert pipeline return value + `time' reserved word to time pipelines and shell builtins + the `function' reserved word + the select compound command and reserved word + new $'...' and $"..." quoting + the $(...) form of command substitution + the ${#param} parameter value length operator + the ${!param} indirect parameter expansion operator + the ${param:length[:offset]} parameter substring operator + the ${param/pat[/string]} parameter pattern substitution operator + expansions to perform substring removal (${p%[%]w}, ${p#[#]w}) + expansion of positional parameters beyond $9 with ${num} + variables: BASH, BASH_VERSION, BASH_VERSINFO, UID, EUID, REPLY, + TIMEFORMAT, PPID, PWD, OLDPWD, SHLVL, RANDOM, SECONDS, + LINENO, HISTCMD, HOSTTYPE, OSTYPE, MACHTYPE, HOSTNAME, + ENV, PS3, PS4, DIRSTACK, PIPESTATUS, HISTSIZE, HISTFILE, + HISTFILESIZE, HISTCONTROL, HISTIGNORE, GLOBIGNORE, + PROMPT_COMMAND, FCEDIT, FIGNORE, IGNOREEOF, INPUTRC, + SHELLOPTS, OPTERR, HOSTFILE, TMOUT, histchars, auto_resume + DEBUG trap + variable arrays with new compound assignment syntax + redirections: <>, &>, >| + prompt string special char translation and variable expansion + auto-export of modified values of variables in initial environment + command search finds functions before builtins + bash return builtin will exit a file sourced with `.' + builtins: cd -/-L/-P, exec -l/-c/-a, echo -e/-E, hash -p. + export -n/-f/-p/name=value, pwd -L/-P, read -e/-p/-a, + readonly -a/-f/name=value, trap -l, set +o, + set -b/-m/-o option/-h/-p/-B/-C/-H/-P, + unset -f/-v, ulimit -m/-p/-u, + type -a/-p/-t, suspend -f, kill -n, + test -o optname/s1 == s2/s1 < s2/s1 > s2/-nt/-ot/-ef/-O/-G/-S + bash reads ~/.bashrc for interactive shells, $ENV for non-interactive + bash restricted shell mode is more extensive + bash allows functions and variables with the same name + brace expansion + tilde expansion + arithmetic expansion with $((...)) and `let' builtin + process substitution + aliases and alias/unalias builtins + local variables in functions and `local' builtin + readline and command-line editing + command history and history/fc builtins + csh-like history expansion + other new bash builtins: bind, command, builtin, declare/typeset, + dirs, enable, fc, help, history, logout, + popd, pushd, disown, shopt + exported functions + filename generation when using output redirection (command >a*) + variable assignments preceding commands affect only that command, + even for builtins and functions + posix mode + +Things sh has that bash does not: + uses variable SHACCT to do shell accounting + includes `stop' builtin (bash can use alias stop='kill -s STOP') + `newgrp' builtin + turns on job control if called as `jsh' + ulimit attempts to set both soft & hard limits if -S/-H not given + $TIMEOUT (like bash $TMOUT) + `^' is a synonym for `|' + new SVR4.2 sh builtins: mldmode, priv + +Implementation differences: + redirection to/from compound commands causes sh to create a subshell + bash does not allow unbalanced quotes; sh silently inserts them at EOF + bash does not mess with signal 11 + sh sets (euid, egid) to (uid, gid) if -p not supplied and uid < 100 + bash splits only the results of expansions on IFS, using POSIX.2 + field splitting rules; sh splits all words on IFS + sh does not allow MAILCHECK to be unset (?) + sh does not allow traps on SIGALRM or SIGCHLD + bash allows multiple option arguments when invoked (e.g. -x -v); + sh allows only a single option argument (`sh -x -v' attempts + to open a file named `-v', and, on SunOS 4.1.4, dumps core) + sh exits a script if any builtin fails; bash exits only if one of + the POSIX.2 `special' builtins fails + +13) How does bash differ from the Korn shell, version ksh88? + +Things bash has or uses that ksh88 does not: + long invocation options + `!' reserved word + posix mode and posix conformance + command hashing + tilde expansion for assignment statements that look like $PATH + process substitution with named pipes if /dev/fd is not available + the ${!param} indirect parameter expansion operator + the ${param:length[:offset]} parameter substring operator + the ${param/pat[/string]} parameter pattern substitution operator + variables: BASH, BASH_VERSION, BASH_VERSINFO, UID, EUID, SHLVL, + TIMEFORMAT, HISTCMD, HOSTTYPE, OSTYPE, MACHTYPE, + HISTFILESIZE, HISTIGNORE, HISTCONTROL, PROMPT_COMMAND, + IGNOREEOF, FIGNORE, INPUTRC, HOSTFILE, DIRSTACK, + PIPESTATUS, HOSTNAME, OPTERR, SHELLOPTS, GLOBIGNORE, + histchars, auto_resume + prompt expansion with backslash escapes and command substitution + redirection: &> (stdout and stderr) + more extensive and extensible editing and completion + builtins: bind, builtin, command, declare, dirs, echo -e/-E, enable, + exec -l/-c/-a, fc -s, export -n/-f/-p, hash, help, history, + jobs -x/-r/-s, kill -s/-n/-l, local, logout, popd, pushd, + read -e/-p/-a, readonly -a/-n/-f/-p, set -o braceexpand/ + -o histexpand/-o interactive-comments/-o notify/-o physical/ + -o posix/-o hashall/-o onecmd/-h/-B/-C/-b/-H/-P, set +o, + suspend, trap -l, type, typeset -a/-F/-p, ulimit -u, + umask -S, alias -p, shopt, disown + `!' csh-style history expansion + +Things ksh88 has or uses that bash does not: + new version of test: [[...]] + tracked aliases + $(&p, <&p) + weirdly-scoped functions + typeset +f to list all function names without definitions + text of command history kept in a file, not memory + builtins: alias -x, cd old new, fc -e -, newgrp, print, + read -p/-s/-u/var?prompt, set -A/-o gmacs/ + -o bgnice/-o markdirs/-o nolog/-o trackall/-o viraw/-s, + typeset -H/-L/-R/-A/-ft/-fu/-fx/-l/-u/-t, whence + +Implementation differences: + ksh runs last command of a pipeline in parent shell context + ksh ulimit sets hard and soft limits by default + bash has brace expansion by default (ksh88 compile-time option) + bash has fixed startup file for all interactive shells; ksh reads $ENV + bash has exported functions + bash command search finds functions before builtins + +14) Which new features in ksh-93 are not in bash, and which are? + +New things in ksh-93 not in bash-2.0: + associative arrays + floating point arithmetic + ++, --, comma arithmetic operators + math library functions + ${!name[sub]} name of subscript for associative array + ${!prefix*} and {!prefix@} variable name prefix expansions + `.' is allowed in variable names to create a hierarchical namespace + more extensive compound assignment syntax + discipline functions + `sleep' and `getconf' builtins (bash has loadable versions) + typeset -n and `nameref' variables + KEYBD trap + variables: .sh.edchar, .sh.edmode, .sh.edcol, .sh.edtext, HISTEDIT, + .sh.version, .sh.name, .sh.subscript, .sh.value + backreferences in pattern matching + print -f and printf (bash has loadable versions) + `fc' has been renamed to `hist' + read -t/-d + `.' can execute shell functions + ENV processed only for interactive shells + +New things in ksh-93 present in bash-2.0: + ?: arithmetic operator + expansions: ${!param}, ${param:len[:offset]}, ${param/pat[/str]} + compound array assignment + the `!' reserved word + loadable builtins -- but ksh uses `builtin' while bash uses `enable' + `command', `builtin', `disown' builtins + new $'...' and $"..." quoting + FIGNORE (but bash uses GLOBIGNORE), HISTCMD + set -o notify/-C + changes to kill builtin + read -A (bash uses read -a) + trap -p + exec -c/-a + `.' restores the positional parameters when it completes + POSIX.2 `test' + umask -S + unalias -a + command and arithmetic substitution performed on PS1, PS4, and ENV + command name completion + +Section D: Why does bash do some things differently than other Unix shells? + +15) Why does bash run a different version of `command' than + `which command' says it will? + +`which' is actually a csh script that assumes you're running csh. +It reads the csh startup files from your home directory and uses +those to determine which `command' will be invoked. Since bash +doesn't use any of those startup files, there's a good chance +that your bash environment differs from your csh environment. + +16) Why doesn't bash treat brace expansions exactly like csh? + +The only difference between bash and csh brace expansion is that +bash requires a brace expression to contain at least one unquoted +comma if it is to be expanded. Any brace-surrounded word not +containing an unquoted comma is left unchanged by the brace +expansion code. This affords the greatest degree of sh +compatibility. + +Bash, ksh, zsh, and pd-ksh all implement brace expansion this way. + +17) Why doesn't bash have csh variable modifiers? + +Posix has specified a more powerful, albeit somewhat more cryptic, +mechanism cribbed from ksh, and bash implements it. + +${parameter%word} + Remove smallest suffix pattern. The WORD is expanded to produce + a pattern. It then expands to the value of PARAMETER, with the + smallest portion of the suffix matched by the pattern deleted. + + x=file.c + echo ${x%.c}.o + -->file.o + +${parameter%%word} + + Remove largest suffix pattern. The WORD is expanded to produce + a pattern. It then expands to the value of PARAMETER, with the + largest portion of the suffix matched by the pattern deleted. + + x=posix/src/std + echo ${x%%/*} + -->posix + +${parameter#word} + Remove smallest prefix pattern. The WORD is expanded to produce + a pattern. It then expands to the value of PARAMETER, with the + smallest portion of the prefix matched by the pattern deleted. + + x=$HOME/src/cmd + echo ${x#$HOME} + -->/src/cmd + +${parameter##word} + Remove largest prefix pattern. The WORD is expanded to produce + a pattern. It then expands to the value of PARAMETER, with the + largest portion of the prefix matched by the pattern deleted. + + x=/one/two/three + echo ${x##*/} + -->three + + +Given + a=/a/b/c/d + b=b.xxx + + csh bash result + --- ---- ------ + $a:h ${a%/*} /a/b/c + $a:t ${a##*/} d + $b:r ${b%.*} b + $b:e ${b##*.} xxx + + +18) How can I make my csh aliases work when I convert to bash? + +Bash uses a different syntax to support aliases than csh does. +The details can be found in the documentation. We have provided +a shell script which does most of the work of conversion for you; +this script can be found in ./examples/misc/alias-conv.sh. Here is +how you use it: + +Start csh in the normal way for you. (e.g., `csh') + +Pipe the output of `alias' through `alias-conv.sh', saving the +results into `bash_aliases': + + alias | alias-conv.sh >bash_aliases + +Edit `bash_aliases', carefully reading through any created +functions. You will need to change the names of some csh specific +variables to the bash equivalents. The script converts $cwd to +$PWD, $term to $TERM, $home to $HOME, $user to $USER, and $prompt +to $PS1. You may also have to add quotes to avoid unwanted +expansion. + +For example, the csh alias: + + alias cd 'cd \!*; echo $cwd' + +is converted to the bash function: + + cd () { command cd "$@"; echo $PWD ; } + +The only thing that needs to be done is to quote $PWD: + + cd () { command cd "$@"; echo "$PWD" ; } + +Merge the edited file into your ~/.bashrc. + +There is an additional, more ambitious, script in +examples/misc/cshtobash that attempts to convert your entire csh +environment to its bash equivalent. This script can be run as +simply `cshtobash' to convert your normal interactive +environment, or as `cshtobash ~/.login' to convert your login +environment. + +19) How can I pipe standard output and standard error from one command to + another, like csh does with `|&'? + +Use + command 2>&1 | command2 + +The key is to remember that piping is performed before redirection, so +file descriptor 1 points to the pipe when it is duplicated onto file +descriptor 2. + +20) Now that I've converted from ksh to bash, are there equivalents to + ksh features like autoloaded functions and the `whence' command? + +There are features in ksh-88 that do not have direct bash equivalents. +Most, however, can be emulated with very little trouble. + +ksh-88 feature Bash equivalent +-------------- --------------- +[[...]] can usually use [...]; minor differences (no + pattern matching, for one) +compiled-in aliases set up aliases in .bashrc; some ksh aliases are + bash builtins (hash, history, type) +$( $@ + +.1.0: + $(RM) $@ + -${NROFF} -man $< > $@ + +.ms.ps: + $(RM) $@ + -${GROFF} -ms $< > $@ + +.ms.txt: + $(RM) $@ + -${NROFF} -ms $< > $@ + +.3.ps: + $(RM) $@ + -${GROFF} -man $< > $@ + +.3.0: + $(RM) $@ + -${NROFF} -man $< > $@ + +all: ps info dvi text html +nodvi: ps info text html + +ps: bash.ps bashbug.ps readline.ps article.ps builtins.ps +dvi: bashref.dvi bashref.ps +info: bashref.info +text: bash.0 bashbug.0 builtins.0 readline.0 +html: bashref.html + +bashref.dvi: $(srcdir)/bashref.texi $(HSUSER) $(RLUSER) + TEXINPUTS=.:$(TEXINPUTDIR):$$TEXINPUTS $(TEXI2DVI) $(srcdir)/bashref.texi + +bashref.ps: bashref.dvi + $(RM) $@ + $(DVIPS) bashref.dvi + +bashref.info: $(srcdir)/bashref.texi $(HSUSER) $(RLUSER) + $(MAKEINFO) --no-split -I$(TEXINPUTDIR) $(srcdir)/bashref.texi + +bashref.html: bashref.texi $(HSUSER) $(RLUSER) + $(TEXI2HTML) -I $(TEXINPUTDIR) $(srcdir)/bashref.texi + +bash.dvi: bash.texinfo $(HSUSER) $(RLUSER) + TEXINPUTS=.:$(TEXINPUTDIR):$$TEXINPUTS $(TEXI2DVI) bash.texinfo + +bashman.ps: bash.dvi + $(RM) $@ + $(DVIPS) bash.dvi + +bash.txt: bash.1 +bash.ps: bash.1 +bashbug.ps: bashbug.1 +builtins.ps: builtins.1 bash.1 +bash.0: bash.1 +bashbug.0: bashbug.1 +builtins.0: builtins.1 bash.1 +readline.0: readline.3 +readline.ps: readline.3 +article.ps: article.ms + +faq: faq.news faq.news2 faq.mail faq.version + +faq.version: FAQ.version FAQ + sh mkfaqvers FAQ.version > $@ + +faq.news: FAQ FAQ.headers.news faq.version + $(RM) $@ + cat FAQ.headers.news faq.version FAQ > $@ + +faq.news2: FAQ FAQ.headers.news2 faq.version + $(RM) $@ + cat FAQ.headers.news2 faq.version FAQ > $@ + +faq.mail: FAQ FAQ.headers.mail faq.version + $(RM) $@ + cat FAQ.headers.mail faq.version FAQ > $@ + +clean: + $(RM) *.aux *.cp *.fn *.ky *.log *.pg *.toc *.tp *.vr *.cps \ + *.pgs *.bt *.bts *.rw *.rws *.fns *.kys *.tps *.vrs *.o \ + core rluser.texinfo hsuser.texinfo + +distclean mostlyclean: clean + $(RM) Makefile + +maintainer-clean: clean + $(RM) *.0 *.ps *.dvi *.info *.txt + $(RM) Makefile + +installdirs: + -test -d $(man1dir) || $(SHELL) ${MKDIRS} $(man1dir) + -test -d $(man3dir) || $(SHELL) ${MKDIRS} $(man3dir) + -test -d $(infodir) || $(SHELL) ${MKDIRS} $(infodir) + +install: info installdirs + -$(INSTALL_DATA) $(srcdir)/bash.1 $(man1dir)/bash.${man1ext} + -$(INSTALL_DATA) $(srcdir)/bashbug.1 $(man1dir)/bashbug.${man1ext} + -$(INSTALL_DATA) $(srcdir)/readline.3 $(man3dir)/readline.${man3ext} + -$(INSTALL_DATA) $(srcdir)/bashref.info $(infodir)/bash.info +# uncomment the next line to install the builtins man page +# $(INSTALL_DATA) builtins.1 $(man1dir)/bash_builtins.${man1ext} + +uninstall: + $(RM) $(man1dir)/bash.${man1ext} $(man1dir)/bashbug.${man1ext} + $(RM) $(man3dir)/readline.${man3ext} $(infodir)/bash.info + +# for use by chet +inst: bashref.texi + $(SHELL) ./mkinstall + cmp -s INSTALL ../INSTALL || mv INSTALL ../INSTALL + $(RM) INSTALL + +posix: bashref.texi + $(SHELL) ./mkposix + cmp -s POSIX.NOTES ../CWRU/POSIX.NOTES || mv POSIX.NOTES ../CWRU/POSIX.NOTES + $(RM) POSIX.NOTES diff --git a/documentation/README b/doc/README similarity index 66% rename from documentation/README rename to doc/README index c20007d..932bf7f 100644 --- a/documentation/README +++ b/doc/README @@ -4,11 +4,14 @@ FAQ - a set of frequently-asked questions about Bash with answers article.ms - an article I wrote about bash for The Linux Journal bash.1 - the bash man page builtins.1 - a man page that documents the builtins, extracted from bash.1 -features.texi - the `bash features' document, suitable for an info tree +features.texi - the `bash reference manual' +features.info - the `bash reference manual' processed by `makeinfo' readline.3 - the readline man page -The `.ps' files are postscript versions of the above. The `.txt' versions -are ascii -- the output of `nroff'. +The `.ps' files are postscript versions of the above. The `.html' +files are HTML versions of the man page and reference manual. The +`.0' files are formatted manual pages. The `.txt' versions are +ascii -- the output of `groff -Tascii'. The rest of this file explains how to use the `builtins.1' man page. diff --git a/documentation/article.ms b/doc/article.ms similarity index 99% rename from documentation/article.ms rename to doc/article.ms index 027f876..517155a 100644 --- a/documentation/article.ms +++ b/doc/article.ms @@ -999,7 +999,7 @@ these proposals, feel free to send me electronic mail. Reflections and Lessons Learned .PP The lesson that has been repeated most often during Bash -development is that there are dark corners in the Bourne Shell, +development is that there are dark corners in the Bourne shell, and people use all of them. In the original description of the Bourne shell, quoting and the shell grammar are both poorly specified and incomplete; subsequent descriptions have not helped diff --git a/documentation/bash.1 b/doc/bash.1 similarity index 63% rename from documentation/bash.1 rename to doc/bash.1 index 9a04b1a..68ace07 100644 --- a/documentation/bash.1 +++ b/doc/bash.1 @@ -6,11 +6,11 @@ .\" Case Western Reserve University .\" chet@ins.CWRU.Edu .\" -.\" Last Change: Fri May 5 10:44:39 EDT 1995 +.\" Last Change: Mon Nov 25 15:36:20 EST 1996 .\" .\" bash_builtins, strip all but Built-Ins section .if \n(zZ=1 .ig zZ -.TH BASH 1 "1995 May 5" GNU +.TH BASH 1 "1996 Nov 25" GNU .\" .\" There's some problem with having a `@' .\" in a tagged paragraph with the BSD man macros. @@ -44,17 +44,17 @@ \fI\|\\$1\|\fP .. .SH NAME -bash \- GNU Bourne\-Again SHell +bash \- GNU Bourne-Again SHell .SH SYNOPSIS .B bash [options] [file] .SH COPYRIGHT -.if n Bash is Copyright (C) 1989, 1991 by the Free Software Foundation, Inc. -.if t Bash is Copyright \(co 1989, 1991 by the Free Software Foundation, Inc. +.if n Bash is Copyright (C) 1989, 1991, 1993, 1995, 1996 by the Free Software Foundation, Inc. +.if t Bash is Copyright \(co 1989, 1991, 1993, 1995, 1996 by the Free Software Foundation, Inc. .SH DESCRIPTION .B Bash -is an \fBsh\fR\-compatible command language interpreter that +is an \fBsh\fR-compatible command language interpreter that executes commands read from the standard input or from a file. .B Bash also incorporates useful features from the \fIKorn\fP and \fIC\fP @@ -62,16 +62,16 @@ shells (\fBksh\fP and \fBcsh\fP). .PP .B Bash is ultimately intended to be a conformant implementation of the IEEE -Posix Shell and Tools specification (IEEE Working Group 1003\.2). +POSIX Shell and Tools specification (IEEE Working Group 1003\.2). .SH OPTIONS -In addition to the single\-character shell options documented in the +In addition to the single-character shell options documented in the description of the \fBset\fR builtin command, \fBbash\fR interprets the following flags when it is invoked: .PP .PD 0 .TP 10 .BI \-c "\| string\^" -If the +If the .B \-c flag is present, then commands are read from .IR string . @@ -80,6 +80,16 @@ If there are arguments after the they are assigned to the positional parameters, starting with .BR $0 . .TP +.B \-r +If the +.B \-r +flag is present, the shell becomes +.I restricted +(see +.SM +.B "RESTRICTED SHELL" +below). +.TP .B \-i If the .B \-i @@ -94,33 +104,53 @@ processing, then commands are read from the standard input. This option allows the positional parameters to be set when invoking an interactive shell. .TP -.B \- -A single -.B \- +.B \-D +A list of all double-quoted strings preceded by \fB$\fP +is printed on the standard ouput. +These are the strings that +are subject to language translation when the current locale +is not C or POSIX. +This implies the \fB\-n\fP option; no commands will be executed. +.TP +.B \-\- +A +.B \-\- signals the end of options and disables further option processing. Any arguments after the -.B \- -are treated as filenames and arguments. An argument of .B \-\- -is equivalent to an argument of \fB\-\fP. +are treated as filenames and arguments. An argument of +.B \- +is equivalent to \fB\-\-\fP. .PD .PP .B Bash -also interprets a number of multi\-character options. These options must -appear on the command line before the single\-character options to be -recognized. +also interprets a number of multi-character options. +These options must appear on the command line before the +single-character options in order for them to be recognized. .PP .PD 0 -.TP 10 -.B \-norc -Do not read and execute the personal initialization file -.I ~/.bashrc -if the shell is interactive. -This option is on by default if the shell is invoked as -.BR sh . .TP -.B \-noprofile -Do not read either the system\-wide startup file +.B \-\-dump\-strings +Equivalent to \fB\-D\fP. +.TP +.B \-\-help +Display a usage message on standard output and exit successfully. +.TP +.B \-\-login +Make +.B bash +act as if it had been invoked as a login shell (see +.SM +.B INVOCATION +below). +.TP +.B \-\-noediting +Do not use the GNU +.B readline +library to read command lines if interactive. +.TP +.B \-\-noprofile +Do not read either the system-wide startup file .FN /etc/profile or any of the personal initialization files .IR ~/.bash_profile , @@ -129,48 +159,45 @@ or .IR ~/.profile . By default, .B bash -normally reads these files when it is invoked as a login shell (see +reads these files when it is invoked as a login shell (see .SM .B INVOCATION below). .TP -\fB\-rcfile\fP \fIfile\fP +.B \-\-norc +Do not read and execute the personal initialization file +.I ~/.bashrc +if the shell is interactive. +This option is on by default if the shell is invoked as +.BR sh . +.TP +.B \-\-posix +Change the behavior of \fBbash\fP where the default operation differs +from the POSIX 1003.2 standard to match the standard. +.TP +\fB\-\-rcfile\fP \fIfile\fP Execute commands from .I file instead of the standard personal initialization file -.IR ~/.bashrc , +.I ~/.bashrc if the shell is interactive (see .SM .B INVOCATION below). .TP -.B \-version -Show the version number of this instance of -.B bash -when starting. -.TP -.B \-quiet -Do not be verbose when starting up (do not show the shell version or any -other information). This is the default. -.TP -.B \-login -Make -.B bash -act as if it had been invoked as a login shell. -.TP -.B \-nobraceexpansion -Do not perform curly brace expansion (see -.B Brace Expansion +.B \-\-restricted +The shell becomes restricted (see +.SM +.B "RESTRICTED SHELL" below). .TP -.B \-nolineediting -Do not use the GNU -.I readline -library to read command lines if interactive. +.B \-\-verbose +Equivalent to \fB\-v\fP. .TP -.B \-posix -Change the behavior of bash where the default operation differs -from the Posix 1003.2 standard to match the standard +.B \-\-version +Show version information for this instance of +.B bash +on the standard output and exit successfully. .PD .SH ARGUMENTS If arguments remain after option processing, and neither the @@ -178,7 +205,8 @@ If arguments remain after option processing, and neither the nor the .B \-s option has been supplied, the first argument is assumed to -be the name of a file containing shell commands. If +be the name of a file containing shell commands. +If .B bash is invoked in this fashion, .B $0 @@ -186,10 +214,167 @@ is set to the name of the file, and the positional parameters are set to the remaining arguments. .B Bash reads and executes commands from this file, then exits. -.B Bash's -exit status is the exit status of the last command executed -in the script. +\fBBash\fP's exit status is the exit status of the last command +executed in the script. +If no commands are executed, the exit status is 0. +.SH INVOCATION +A \fIlogin shell\fP is one whose first character of argument zero is a +.BR \- , +or one started with the +.B \-\-login +option. +.PP +An \fIinteractive\fP shell is one whose standard input and output are +both connected to terminals (as determined by +.IR isatty (3)), +or one started with the +.B \-i +option. +.SM +.B PS1 +is set and +.B $\- +includes +.B i +if +.B bash +is interactive, +allowing a shell script or a startup file to test this state. +.PP +The following paragraphs describe how +.B bash +executes its startup files. +If any of the files exist but cannot be read, +.B bash +reports an error. +Tildes are expanded in file names as described below under +.B "Tilde Expansion" +in the +.SM +.B EXPANSION +section. +.PP +When +.B bash +is invoked as a login shell, it first reads and executes commands +from the file \fI/etc/profile\fP, if that file exists. +After reading that file, it looks for \fI~/.bash_profile\fP, +\fI~/.bash_login\fP, and \fI~/.profile\fP, in that order, and reads +and executes commands from the first one that exists and is readable. +The +.B \-\-noprofile +option may be used when the shell is started to inhibit this behavior. +.PP +When a login shell exits, +.B bash +reads and executes commands from the file \fI~/.bash_logout\fP, if it +exists. +.PP +When an interactive shell that is not a login shell is started, +.B bash +reads and executes commands from \fI~/.bashrc\fP, if that file exists. +This may be inhibited by using the +.B \-\-norc +option. +The \fB\-\-rcfile\fP \fIfile\fP option will force +.B bash +to read and execute commands from \fIfile\fP instead of \fI~/.bashrc\fP. +.PP +When +.B bash +is started non-interactively, to run a shell script, for example, it +looks for the variable +.SM +.B BASH_ENV +in the environment, expands its value if it appears there, and uses the +expanded value as the name of a file to read and execute. +.B Bash +behaves as if the following command were executed: +.sp .5 +.RS +\f(CWif [ \-n "$BASH_ENV" ]; then . "$BASH_ENV"; fi\fP +.RE +.sp .5 +but the value of the +.SM +.B PATH +variable is not used to search for the file name. +.PP +If +.B bash +is invoked with the name +.BR sh , +it tries to mimic the startup behavior of historical versions of +.B sh +as closely as possible, +while conforming to the POSIX standard as well. +When invoked as a login shell, it first attempts to read and execute +commands from +.I /etc/profile +and +.IR ~/.profile , +in that order. +The +.B \-\-noprofile +option may be used to inhibit this behavior. +When invoked as an interactive shell with the name +.BR sh , +.B bash +looks for the variable +.SM +.BR ENV , +expands its value if it is defined, and uses the +expanded value as the name of a file to read and execute. +Since a shell invoked as +.B sh +does not attempt to read and execute commands from any other startup +files, the +.B \-\-rcfile +option has no effect. +A non-interactive shell invoked with the name +.B sh +does not attempt to read any startup files. +When invoked as +.BR sh , +.B bash +enters +.I posix +mode after the startup files are read. +.PP +When +.B bash +is started in +.I posix +mode, as with the +.B \-\-posix +command line option, it follows the POSIX standard for startup files. +In this mode, the +.SM +.B ENV +variable is expanded and commands are read and executed from the file +whose name is the expanded value. +No other startup files are read. +This is done by interactive shells only. +.PP +.B Bash +attempts to determine when it is being run by the remote shell +daemon, usually \fIrshd\fP. +If +.B bash +determines it is being run by \fIrshd\fP, it reads and executes +commands from \fI~/.bashrc\fP, if that file exists and is readable. +It will not do this if invoked as \fBsh\fP. +The +.B \-\-norc +option may be used to inhibit this behavior, and the +.B \-\-rcfile +option may be used to force another file to be read, but +\fIrshd\fP does not generally invoke the shell with those options +or allow them to be specified. .SH DEFINITIONS +.PP +The following definitions are used throughout the rest of this +document. .PD 0 .TP .B blank @@ -223,7 +408,7 @@ A \fItoken\fP that performs a control function. It is one of the following symbols: .RS .PP -.if t \fB\(bv\|\(bv & && ; ;; ( ) | \fP +.if t \fB\(bv\(bv & && ; ;; ( ) | \fP .if n \fB|| & && ; ;; ( ) | \fP .RE .PD @@ -241,15 +426,15 @@ command: .if t .RS .PP .B -.if n ! case do done elif else esac fi for function if in select then until while { } -.if t ! case do done elif else esac fi for function if in select then until while { } +.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 A \fIsimple command\fP is a sequence of optional variable assignments -followed by \fIblank\fP\-separated words and redirections, and +followed by \fBblank\fP-separated words and redirections, and terminated by a \fIcontrol operator\fP. The first word specifies the command to be executed. The remaining words are passed as arguments to the invoked command. @@ -265,7 +450,7 @@ the character The format for a pipeline is: .RS .PP -[ ! ] \fIcommand\fP [ \fB|\fP \fIcommand2\fP ... ] +[\fBtime\fP [\fB\-p\fP]] [ ! ] \fIcommand\fP [ \fB|\fP \fIcommand2\fP ... ] .RE .PP The standard output of @@ -283,9 +468,27 @@ If the reserved word 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 +command. +The shell waits for all commands in the pipeline to terminate before returning a value. .PP +If the +.B time +reserved word precedes a pipeline, the elapsed as well as user and +system time consumed by its execution are reported when the pipeline +terminates. +The \fB\-p\fP option changes the output format to that specified by POSIX. +The +.SM +.B TIMEFORMAT +variable may be set to a format string that specifies how the timing +information should be displayed; see the description of +.SM +.B TIMEFORMAT +under +.B "Shell Variables" +below. +.PP Each command in a pipeline is executed as a separate process (i.e., in a subshell). .SS Lists @@ -296,8 +499,8 @@ of the operators .BR & , .BR && , or -.BR \(bv\|\(bv , -and terminated by one of +.BR \(bv\(bv , +and optionally terminated by one of .BR ; , .BR & , or @@ -306,7 +509,7 @@ or Of these list operators, .B && and -.B \(bv\|\(bv +.B \(bv\(bv have equal precedence, followed by .B ; and @@ -326,7 +529,7 @@ exit status of the last command executed. The control operators .B && and -.B \(bv\|\(bv +.B \(bv\(bv denote AND lists and OR lists, respectively. An AND list has the form .RS @@ -342,14 +545,14 @@ returns an exit status of zero. An OR list has the form .RS .PP -\fIcommand\fP \fB\(bv\|\(bv\fP \fIcommand2\fP +\fIcommand\fP \fB\(bv\(bv\fP \fIcommand2\fP .PP .RE .PP .I command2 is executed if and only if .I command -returns a non\-zero exit status. The return status of +returns a non-zero exit status. The return status of AND and OR lists is the exit status of the last command executed in the list. .SS Compound Commands @@ -363,10 +566,21 @@ after the command completes. The return status is the exit status of \fIlist\fP. .TP { \fIlist\fP; } -\fIlist\fP is simply executed in the current shell environment. This is -known as a \fIgroup command\fP. The return status is the exit status of +\fIlist\fP is simply executed in the current shell environment. +\fIlist\fP must be terminated with a newline or semicolon. +This is known as a \fIgroup command\fP. +The return status is the exit status of \fIlist\fP. .TP +((\fIexpression\fP)) +The \fIexpression\fP is evaluated according to the rules described +below under +.SM +.BR "ARITHMETIC EVALUATION" . +If the value of the expression is non-zero, the return status is 0; +otherwise the return status is 1. This is exactly equivalent to +\fBlet "\fIexpression\fP"\fR. +.TP \fBfor\fP \fIname\fP [ \fBin\fP \fIword\fP; ] \fBdo\fP \fIlist\fP ; \fBdone\fP The list of words following \fBin\fP is expanded, generating a list of items. The variable \fIname\fP is set to each element of this list @@ -387,7 +601,7 @@ error, each preceded by a number. If the \fBin\fP below). The .B PS3 prompt is then displayed and a line read from the standard input. -If the line consists of the number corresponding to one of +If the line consists of a number corresponding to one of the displayed words, then the value of .I name is set to that word. If the line is empty, the words and prompt @@ -418,12 +632,12 @@ as for pathname expansion (see 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 -patterns are matches. Otherwise, it is the exit status of the +pattern matches. Otherwise, it is the exit status of the last command executed in \fIlist\fP. .TP -\fBif\fP \fIlist\fP \fBthen\fP \fIlist\fP \ -[ \fBelif\fP \fIlist\fP \fBthen\fP \fIlist\fP ] ... \ -[ \fBelse\fP \fIlist\fP ] \fBfi\fP +\fBif\fP \fIlist\fP; \fBthen\fP \fIlist;\fP \ +[ \fBelif\fP \fIlist\fP; \fBthen\fP \fIlist\fP; ] ... \ +[ \fBelse\fP \fIlist\fP; ] \fBfi\fP The .B if .I list @@ -436,9 +650,9 @@ executed, if present. The exit status is the exit status of the last command executed, or zero if no condition tested true. .TP .PD 0 -\fBwhile\fP \fIlist\fP \fBdo\fP \fIlist\fP \fBdone\fP +\fBwhile\fP \fIlist\fP; \fBdo\fP \fIlist\fP; \fBdone\fP .TP -\fBuntil\fP \fIlist\fP \fBdo\fP \fIlist\fP \fBdone\fP +\fBuntil\fP \fIlist\fP; \fBdo\fP \fIlist\fP; \fBdone\fP .PD The \fBwhile\fP command continuously executes the \fBdo\fP \fIlist\fP as long as the last command in \fIlist\fP returns @@ -449,7 +663,7 @@ the .I list is executed as long as the last command in .I list -returns a non\-zero exit status. +returns a non-zero exit status. 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 @@ -467,14 +681,22 @@ the exit status of the last command executed in the body. (See .B FUNCTIONS below.) .SH COMMENTS -In a non\-interactive shell, or an interactive shell in which the -.B -o interactive\-comments -option to the \fBset\fP builtin is enabled, a word beginning with +In a non-interactive shell, or an interactive shell in which the +.B interactive_comments +option to the +.B shopt +builtin is enabled (see +.SM +.B "SHELL BUILTIN COMMANDS" +below), a word beginning with .B # causes that word and all remaining characters on that line to be ignored. An interactive shell without the -.B -o interactive\-comments -option enabled does not allow comments. +.B interactive_comments +.B shopt +option enabled does not allow comments. The +.B interactive_comments +option is on by default in interactive shells. .SH QUOTING \fIQuoting\fP is used to remove the special meaning of certain characters or words to the shell. Quoting can be used to @@ -532,11 +754,60 @@ quotes (see .SM .B PARAMETERS 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 specifed by the ANSI C standard. Backslash escape sequences, if +present, are decoded as follows: +.RS +.PD 0 +.TP +.B \ea +alert (bell) +.TP +.B \eb +backspace +.TP +.B \ee +an escape character +.TP +.B \ef +form feed +.TP +.B \en +new line +.TP +.B \er +carriage return +.TP +.B \et +horizontal tab +.TP +.B \ev +vertical tab +.TP +.B \e\e +backslash +.TP +.B \e\fInnn\fP +the character whose ASCII code is \fInnn\fP (octal) +.PD +.RE +.LP +The translated result is single-quoted, as if the dollar sign had +not been present. +.PP +A double-quoted string preceded by a dollar sign (\fB$\fP) will cause +the string to be translated according to the current locale. +If the current locale is \fBC\fP or \fBPOSIX\fP, the dollar sign +is ignored. +If the string is translated and replaced, the replacement is +double-quoted. .SH PARAMETERS A .I parameter -is an entity that stores values, somewhat like a -variable in a conventional programming language. It can be a +is an entity that stores values. +It can be a .IR name , a number, or one of the special characters listed below under .BR "Special Parameters" . @@ -566,9 +837,12 @@ If .I value is not given, the variable is assigned the null string. All .I values -undergo tilde expansion, parameter and variable expansion, command -substitution, arithmetic expansion, and quote removal. If -the variable has its +undergo tilde expansion, parameter and variable expansion, string +expansion, command substitution, arithmetic expansion, and quote +removal (see +.SM +.B EXPANSION +below). If the variable has its .B \-i attribute set (see .B declare @@ -577,8 +851,11 @@ below in .BR "SHELL BUILTIN COMMANDS" ) then .I value -is subject to arithmetic expansion even if the $[...] syntax does -not appear. Word splitting is not performed, with the exception +is subject to arithmetic expansion even if the $((...)) syntax does +not appear (see +.B "Arithmetic Expansion" +below). +Word splitting is not performed, with the exception of \fB"$@"\fP as explained below under .BR "Special Parameters" . Pathname expansion is not performed. @@ -677,14 +954,19 @@ option, then .B $0 is set to the first argument after the string to be executed, if one is present. Otherwise, it is set -to the pathname used to invoke +to the file name used to invoke .BR bash , as given by argument zero. .TP .B _ -Expands to the last argument to the previous command, after expansion. -Also set to the full pathname of each command executed and placed in +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 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 .SS Shell Variables .PP @@ -718,20 +1000,50 @@ Expands to the effective user ID of the current user, initialized at shell startup. .TP .B BASH -Expands to the full pathname used to invoke this instance of +Expands to the full file name used to invoke this instance of .BR bash . .TP .B BASH_VERSION -Expands to the version number of this instance of +Expands to a string describing the version of this instance of .BR bash . .TP +.B BASH_VERSINFO +An array variable whose members hold version information for this +instance of +.BR bash . +The values assigned to the array members are as follows: +.sp .5 +.RS +.PD 0 +.TP 24 +.B BASH_VERSINFO[\fR0\fP] +The major version number (the \fIrelease\fP). +.TP +.B BASH_VERSINFO[\fR1\fP] +The minor version number (the \fIversion\fP). +.TP +.B BASH_VERSINFO[\fR2\fP] +The patch level. +.TP +.B BASH_VERSINFO[\fR3\fP] +The build version. +.TP +.B BASH_VERSINFO[\fR4\fP] +The release status (e.g., \fIbeta1\fP). +.TP +.B BASH_VERSINFO[\fR5\fP] +The value of \fBMACHTYPE\fP. +.PD +.RE +.TP .B SHLVL Incremented by one each time an instance of .B bash is started. .TP .B RANDOM -Each time this parameter is referenced, a random integer is +Each time this parameter is referenced, a random integer between +0 and 32767 is generated. The sequence of random numbers may be initialized by assigning a value to .SM @@ -762,12 +1074,7 @@ Each time this parameter is referenced, the shell substitutes a decimal number representing the current sequential line number (starting with 1) within a script or function. When not in a script or function, the value substituted is not guaranteed to -be meaningful. When in a function, the value is not -the number of the source line that the command appears -on (that information has been lost by the time the function is -executed), but is an approximation of the number of -.I simple commands -executed in the current function. +be meaningful. If .SM .B LINENO @@ -776,12 +1083,40 @@ subsequently reset. .TP .B HISTCMD The history number, or index in the history list, of the current -command. If +command. +If .SM .B HISTCMD is unset, it loses its special properties, even if it is subsequently reset. .TP +.B DIRSTACK +An array variable (see +.B Arrays +below) containing the current contents of the directory stack. +Directories appear in the stack in the order they are displayed by the +.B dirs +builtin. +Assigning to members of this array variable may be used to modify +directories already in the stack, but the +.B pushd +and +.B popd +builtins must be used to add and remove directories. +Assignment to this variable will not change the current directory. +If +.SM +.B DIRSTACK +is unset, it loses its special properties, even if it is +subsequently reset. +.TP +.B PIPESTATUS +An array variable (see +.B Arrays +below) containing a list of exit status values from the processes +in the most-recently-executed foreground pipeline (which may +contain only a single command). +.TP .B OPTARG The value of the last option argument processed by the .B getopts @@ -798,17 +1133,50 @@ builtin command (see .B SHELL BUILTIN COMMANDS below). .TP +.B HOSTNAME +Automatically set to the name of the current host. +.TP .B HOSTTYPE Automatically set to a string that uniquely describes the type of machine on which .B bash -is executing. The default is system-dependent. +is executing. +The default is system-dependent. .TP .B OSTYPE Automatically set to a string that describes the operating system on which .B bash -is executing. The default is system-dependent. +is executing. +The default is system-dependent. +.TP +.B MACHTYPE +Automatically set to a string that fully describes the system +type on which +.B bash +is executing, in the standard GNU \fIcpu-company-system\fP format. +The default is system-dependent. +.TP +.B SHELLOPTS +A colon-separated list of enabled shell options. Each word in +the list is a valid argument for the +.B \-o +option to the +.B set +builtin command (see +.SM +.B "SHELL BUILTIN COMMANDS" +below). The options appearing in +.SM +.B SHELLOPTS +are those reported as +.I on +by \fBset \-o\fP. +If this variable is in the environment when +.B bash +starts up, each shell option in the list will be enabled before +reading any startup files. +This variable is read-only. .PD .PP The following variables are used by the shell. In some cases, @@ -834,7 +1202,7 @@ is a colon-separated list of directories in which the shell looks for commands (see .SM .B COMMAND EXECUTION -below). The default path is system\-dependent, +below). The default path is system-dependent, and is set by the administrator who installs .BR bash . A common value is ``/usr/gnu/bin:/usr/local/bin:/usr/ucb:/bin:/usr/bin:.''. @@ -862,13 +1230,13 @@ The value of .SM .B ENV is subjected to parameter expansion, command substitution, and arithmetic -expansion before being interpreted as a pathname. +expansion before being interpreted as a file name. .SM .B PATH -is not used to search for the resultant pathname. +is not used to search for the resultant file name. .TP .B MAIL -If this parameter is set to a filename and the +If this parameter is set to a file name and the .SM .B MAILPATH variable is not set, @@ -880,50 +1248,47 @@ Specifies how often (in seconds) .B bash checks for mail. The default is 60 seconds. When it is time to check -for mail, the shell does so before prompting. +for mail, the shell does so before displaying the primary prompt. If this variable is unset, the shell disables mail checking. .TP .B MAILPATH -A colon-separated list of pathnames to be checked for mail. -The message to be printed may be specified by separating the pathname from +A colon-separated list of file names to be checked for mail. +The message to be printed may be specified by separating the file name from the message with a `?'. $_ stands for the name of the current mailfile. Example: .RS .PP -\fBMAILPATH\fP='/usr/spool/mail/bfox?"You have mail":~/shell-mail?"$_ has mail!"' +\fBMAILPATH\fP='/usr/spool/mail/bfox?"You have mail":~/shell\-mail?"$_ has mail!"' .PP .B Bash supplies a default value for this variable, but the location of the user mail files that it uses is system dependent (e.g., /usr/spool/mail/\fB$USER\fP). .RE .TP -.B MAIL_WARNING -If set, and a file that \fBbash\fP is checking for mail has been -accessed since the last time it was checked, the message ``The mail in -\fImailfile\fP has been read'' is printed. -.TP .B PS1 The value of this parameter is expanded (see .SM .B PROMPTING below) and used as the primary prompt string. The default value is -``\fBbash\e$ \fP''. +``\fB\es\-\ev\e$ \fP''. .TP .B PS2 -The value of this parameter is expanded +The value of this parameter is expanded as with +.B PS1 and used as the secondary prompt string. The default is ``\fB> \fP''. .TP .B PS3 The value of this parameter is used as the prompt for the -.I select +.B select command (see .SM .B SHELL GRAMMAR above). .TP .B PS4 -The value of this parameter is expanded +The value of this parameter is expanded as with +.B PS1 and the value is printed before each command .B bash displays during an execution trace. The first character of @@ -932,6 +1297,53 @@ 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 TIMEFORMAT +The value of this parameter is used as a format string specifying +how the timing information for pipelines prefixed with the +.B time +reserved word should be displayed. +The \fB%\fP character introduces an escape sequence that is +expanded to a time value or other information. +The escape sequences and their meanings are as follows; the +braces denote optional portions. +.sp .5 +.RS +.PD 0 +.TP 10 +.B %% +A literal \fB%\fP. +.TP +.B %[\fIp\fP][l]R +The elapsed time in seconds. +.TP +.B %[\fIp\fP][l]U +The number of CPU seconds spent in user mode. +.TP +.B %[\fIp\fP][l]S +The number of CPU seconds spent in system mode. +.TP +.B %P +The CPU percentage, computed as (%U + %S) / %R. +.PD +.RE +.IP +The optional \fIp\fP is a digit specifying the \fIprecision\fP, +the number of fractional digits after a decimal point. +A value of 0 causes no decimal point or fraction to be output. +At most three places after the decimal point may be specified; +values of \fIp\fP greater than 3 are changed to 3. +If \fIp\fP is not specified, the value 3 is used. +.IP +The optional \fBl\fP specifies a longer format, including +minutes, of the form \fIMM\fPm\fISS\fP.\fIFF\fPs. +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. +If the value is null, no timing information is displayed. +A trailing newline is added when the format string is displayed. +.TP .B HISTSIZE The number of commands to remember in the command history (see .SM @@ -939,17 +1351,18 @@ The number of commands to remember in the command history (see below). The default value is 500. .TP .B HISTFILE -The name of the file in which command history is saved. (See +The name of the file in which command history is saved (see .SM .B HISTORY -below.) The default value is \fI~/.bash_history\fP. If unset, the +below). The default value is \fI~/.bash_history\fP. If unset, the command history is not saved when an interactive shell exits. .TP .B HISTFILESIZE The maximum number of lines contained in the history file. When this variable is assigned a value, the history file is truncated, if necessary, to contain no more than that number of lines. The default -value is 500. +value is 500. The history file is also truncated to this size after +writing it when an interactive shell exits. .TP .B OPTERR If set to the value 1, @@ -965,27 +1378,43 @@ below). is initialized to 1 each time the shell is invoked or a shell script is executed. .TP +.B LANG +Used to determine the locale category for any category not specifically +selected with a variable starting with \fBLC_\fP. +.TP +.B LC_ALL +This variable overrides the value of \fBLANG\fP and any other +\fBLC_\fP variable specifying a locale category. +.TP +.B LC_COLLATE +This variable determines the collation order used when sorting the +results of pathname expansion. +.TP +.B LC_MESSAGES +This variable determines the locale used to translate double-quoted +strings preceded by a \fB$\fP. +.TP .B PROMPT_COMMAND If set, the value is executed as a command prior to issuing each primary prompt. .TP .B IGNOREEOF Controls the -action of the shell on receipt of an +action of an interactive shell on receipt of an .SM .B EOF character as the sole input. If set, the value is the number of consecutive .SM .B EOF -characters typed as the first characters on an input line before +characters which must be +typed as the first characters on an input line before .B bash exits. If the variable exists but does not have a numeric value, or has no value, the default value is 10. If it does not exist, .SM .B EOF -signifies the end of input to the shell. This is only in effect for -interactive shells. +signifies the end of input to the shell. .TP .B TMOUT If set to a value greater than zero, the value is interpreted as the @@ -1004,36 +1433,33 @@ A colon-separated list of suffixes to ignore when performing filename completion (see .SM .B READLINE -below). A filename whose suffix matches one of the entries in +below). +A filename whose suffix matches one of the entries in .SM .B FIGNORE -is excluded from the list of matched filenames. A sample -value is ``.o:~''. +is excluded from the list of matched filenames. +A sample value is ``.o:~''. +.TP +.B GLOBIGNORE +A colon-separated list of patterns defining the set of filenames to +be ignored by pathname expansion. +If a filename matched by a pathname expansion pattern also matches one +of the patterns in +.SM +.BR GLOBIGNORE , +it is removed from the list of matches. .TP .B INPUTRC -The filename for the readline startup file, overriding the default -of +The filename for the +.B readline +startup file, overriding the default of .FN ~/.inputrc (see .SM .B READLINE below). .TP -.B notify -If set, -.B bash -reports terminated background jobs immediately, rather than waiting -until before printing the next primary prompt (see also the -.B \-b -option to the -.B set -builtin command). -.PD 0 -.TP -.B history_control -.TP .B HISTCONTROL -.PD If set to a value of .IR ignorespace , lines which begin with a @@ -1047,29 +1473,23 @@ A value of combines the two options. If unset, or if set to any other value than those above, all lines read -by the parser are saved on the history list. -.TP -.B command_oriented_history -If set, -.B bash -attempts to save all lines of a multiple\-line -command in the same history entry. This allows -easy re\-editing of multi\-line commands. -.TP -.B glob_dot_filenames -If set, -.B bash -includes filenames beginning with a `.' in the results of pathname -expansion. -.TP -.B allow_null_glob_expansion -If set, -.B bash -allows pathname patterns which match no -files (see -.B Pathname Expansion -below) -to expand to a null string, rather than themselves. +by the parser are saved on the history list, subject to the value +of +.BR HISTIGNORE . +This variable's function is superseded by +.BR HISTIGNORE . +.TP +.B HISTIGNORE +A colon-separated list of patterns used to decide which command lines +should be saved on the history list. Each pattern is anchored at the +beginning of the line and must fully specify the line (no implicit +`\fB*\fP' is appended). Each pattern is tested against the line +after the checks specified by +.B HISTCONTROL +are applied. +In addition to the normal shell pattern matching characters, `\fB&\fP' +matches the previous history line. `\fB&\fP' may be escaped using a +backslash. The backslash is removed before attempting a match. .TP .B histchars The two or three characters which control history expansion @@ -1086,31 +1506,13 @@ character, which is used as shorthand for re-running the previous command entered, substituting one string for another in the command. The default is `\fB^\fP'. The optional third character is the character -which signifies that the remainder of the line is a comment, when found +which signifies that the remainder of the line is a comment when found as the first character of a word, normally `\fB#\fP'. The history comment character causes history substitution to be skipped for the remaining words on the line. It does not necessarily cause the shell parser to treat the rest of the line as a comment. .TP -.B nolinks -If set, the shell does not follow symbolic links when executing -commands that change the current working directory. It uses the -physical directory structure instead. By default, -.B bash -follows the logical chain of directories when performing commands -which change the current directory, such as -.BR cd . -See also the description of the \fB\-P\fP option to the \fBset\fP -builtin ( -.SM -.B SHELL BUILTIN COMMANDS -below). -.PD 0 -.TP -.B hostname_completion_file -.TP .B HOSTFILE -.PD Contains the name of a file in the same format as .FN /etc/hosts that should be read when the shell needs to complete a @@ -1119,23 +1521,6 @@ time hostname completion is attempted .B bash adds the contents of the new file to the already existing database. .TP -.B noclobber -If set, -.B bash -does not overwrite an existing file with the -.BR > , -.BR >& , -and -.B <> -redirection operators. This variable may be overridden when -creating output files by using the redirection operator -.B >| -instead of -.B > -(see also the \fB\-C\fP option to the -.B set -builtin command). -.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 @@ -1156,30 +1541,103 @@ stopped job. The .I substring value provides functionality analogous to the .B %? -job id (see +job identifier (see .SM .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 .B % -job id. -.TP -.B no_exit_on_failed_exec -If this variable exists, a non-interactive shell will not exit if -it cannot execute the file specified in the -.B exec -builtin command. An interactive shell does not exit if -.B exec -fails. -.TP -.B cdable_vars -If this is set, an argument to the -.B cd -builtin command that -is not a directory is assumed to be the name of a variable whose -value is the directory to change to. +job identifier. .PD +.SS Arrays +.B Bash +provides one-dimensional array variables. Any variable may be used as +an array; the +.B declare +builtin will explicitly declare an array. There is no maximum +limit on the size of an array, nor any requirement that members +be indexed or assigned contiguously. Arrays are indexed using +integers and are zero-based. +.PP +An array is created automatically if any variable is assigned to using +the syntax \fIname\fP[\fIsubscript\fP]=\fIvalue\fP. The +.I subscript +is treated as an arithmetic expression that must evaluate to a number +greater than or equal to zero. To explicitly declare an array, use +.B declare \-a \fIname\fP +(see +.SM +.B SHELL BUILTIN COMMANDS +below). +.B declare \-a \fIname\fP[\fIsubscript\fP] +is also accepted; the \fIsubscript\fP is ignored. Attributes may be +specified for an array variable using the +.B declare +and +.B readonly +builtins. Each attribute applies to all members of an array. +.PP +Arrays are assigned to using compound assignments of the form +\fIname\fP=\fB(\fPvalue\fI1\fP ... value\fIn\fP\fB)\fP, where each +\fIvalue\fP is of the form [\fIsubscript\fP]=\fIstring\fP. Only +\fIstring\fP is required. If +the optional brackets and subscript are supplied, that index is assigned to; +otherwise the index of the element assigned is the last index assigned +to by the statement plus one. Indexing starts at zero. +This syntax is also accepted by the +.B declare +builtin. Individual array elements may be assigned to using the +\fIname\fP[\fIsubscript\fP]=\fIvalue\fP syntax introduced above. +.PP +Any element of an array may be referenced using +${\fIname\fP[\fIsubscript\fP]}. The braces are required to avoid +conflicts with pathname expansion. If +\fIsubscript\fP is \fB@\fP or \fB*\fP, the word expands to +all members of \fIname\fP. These subscripts differ only when the +word appears within double quotes. If the word is double-quoted, +${\fIname\fP[*]} expands to a single +word with the value of each array member separated by the first +character of the +.SM +.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. 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 +${\fIname\fP[\fIsubscript\fP]}. If \fIsubscript\fP is \fB*\fP or +\fB@\fP, the expansion is the number of elements in the array. +Referencing an array variable without a subscript is equivalent to +referencing element zero. +.PP +The +.B unset +builtin is used to destroy arrays. \fBunset\fP \fIname\fP[\fIsubscript\fP] +destroys the array element at index \fIsubscript\fP. +\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. +.PP +The +.BR declare , +.BR local , +and +.B readonly +builtins each accept a +.B \-a +option to specify an array. The +.B read +builtin accepts a +.B \-a +option to assign a list of words read from the standard input +to an array. The +.B set +and +.B declare +builtins display array values in a way that allows them to be +reused as assignments. .SH EXPANSION Expansion is performed on the command line after it has been split into words. There are seven kinds of expansion performed: @@ -1193,8 +1651,9 @@ and .IR "pathname expansion" . .PP The order of expansions is: brace expansion, tilde expansion, -parameter, variable, command, and arithmetic substitution (done -in a left\-to\-right fashion), word splitting, and pathname +parameter, variable and arithmetic expansion and +command substitution +(done in a left-to-right fashion), word splitting, and pathname expansion. .PP On systems that can support it, there is an additional expansion @@ -1203,8 +1662,9 @@ available: \fIprocess substitution\fP. Only brace expansion, word splitting, and pathname expansion can change the number of words of the expansion; other expansions expand a single word to a single word. -The single exception to this is the expansion of -``\fB$@\fP'' as explained above (see +The only exceptions to this are the expansions of +``\fB$@\fP'' and ``\fB${\fP\fIname\fP\fB[@]}\fP'' +as explained above (see .SM .BR PARAMETERS ). .SS Brace Expansion @@ -1219,7 +1679,7 @@ the form of an optional followed by a series of comma-separated strings between a pair of braces, followed by an optional .IR postamble . -The preamble is prepended to each string contained +The preamble is prefixed to each string contained within the braces, and the postamble is then appended to each resulting string, expanding left to right. .PP @@ -1237,6 +1697,8 @@ expansion or the text between the braces. A correctly-formed brace expansion must contain unquoted opening and closing braces, and at least one unquoted comma. Any incorrectly formed brace expansion is left unchanged. +A \fB{\fP or \fB,\fP may be quoted with a backslash to prevent its +being considered part of a brace expression. .PP This construct is typically used as shorthand when the common prefix of the strings to be generated is longer than in the @@ -1251,9 +1713,8 @@ chown root /usr/{ucb/{ex,edit},lib/{ex?.?*,how_ex}} .RE .PP Brace expansion introduces a slight incompatibility with -traditional versions of -.BR sh , -the Bourne shell. +historical versions of +.BR sh . .B sh does not treat opening or closing braces specially when they appear as part of a word, and preserves them in the output. @@ -1272,13 +1733,9 @@ If strict compatibility with is desired, start .B bash with the -.B \-nobraceexpansion -flag (see -.SM -.B OPTIONS -above) -or disable brace expansion with the -.B +o braceexpand +.B +B +option or disable brace expansion with the +.B +B option to the .B set command (see @@ -1314,12 +1771,12 @@ associated with that name. If the name is invalid, or the tilde expansion fails, the word is unchanged. .PP Each variable assignment is checked for unquoted -instances of tildes following a +tildes immediately following a .B : or .BR = . In these cases, tilde substitution is also performed. Consequently, one -may use pathnames with tildes in assignments to +may use file names with tildes in assignments to .SM .BR PATH , .SM @@ -1350,10 +1807,19 @@ is followed by a character which is not to be interpreted as part of its name. .PD .PP +If the first character of \fIparameter\fP is an exclamation point, +a level of variable indirection is introduced. +\fBBash\fP uses the value of the variable formed from the rest of +\fIparameter\fP as the name of the variable; this variable is then +expanded and that value used in the rest of the substitution, rather +than the value of \fIparameter\fP itself. +This is known as \fIindirect expansion\fP. +.PP In each of the cases below, \fIword\fP is subject to tilde expansion, parameter expansion, command substitution, and arithmetic expansion. -\fBBash\fP tests for a parameter that is unset or null; omitting the -colon results in a test only for a parameter that is unset. +When not performing substring expansion, \fBbash\fP tests for a parameter +that is unset or null; omitting the colon results in a test only for a +parameter that is unset. .PP .PD 0 .TP @@ -1398,15 +1864,48 @@ is null or unset, nothing is substituted, otherwise the expansion of .I word is substituted. .TP +.PD 0 +${\fIparameter\fP\fB:\fP\fIoffset\fP} +.TP +${\fIparameter\fP\fB:\fP\fIoffset\fP\fB:\fP\fIlength\fP} +.PD +\fBSubstring Expansion.\fP +Expands to up to \fIlength\fP characters of \fIparameter\fP, +starting at \fIoffset\fP. +If \fIlength\fP is omitted, expands to the substring of +\fIparameter\fP, starting at the character specified by \fIoffset\fP. +\fIlength\fP and \fIoffset\fP are arithmetic expressions (see +.SM +.B +ARITHMETIC EVALUATION +below). +\fIlength\fP must evaluate to a number greater than or equal to zero. +If \fIoffset\fP evaluates to a number less than zero, the value +is used as an offset from the end of the value of \fIparameter\fP. +If \fIparameter\fP is \fB@\fP, the result is \fIlength\fP positional +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]}. +Substring indexing is zero-based unless the positional parameters are +used, in which case the indexing starts at 1. +.TP ${\fB#\fP\fIparameter\fP} The length in characters of the value of \fIparameter\fP is substituted. -If \fIparameter\fP is +If +.I parameter +is .B * or .BR @ , -the length substituted is the length of +the length substituted is the number of positional parameters. +If +.I parameter +is an array name subscripted by .B * -expanded within double quotes. +or +.BR @ , +the length substituted is the number of elements in the array. .TP .PD 0 ${\fIparameter\fP\fB#\fP\fIword\fP} @@ -1421,9 +1920,24 @@ the value of .IR parameter , then the expansion is the value of .I parameter -with the shortest matching pattern deleted (the ``\fB#\fP'' -case) or the longest -matching pattern deleted (the ``\fB##\fP'' case). +with the shortest matching pattern (the ``\fB#\fP'' case) or the +longest matching pattern (the ``\fB##\fP'' case) deleted. +If +.I parameter +is +.B @ +or +.BR * , +the pattern removal operation is applied to each positional +parameter in turn, and the expansion is the resultant list. +If +.I parameter +is an array variable subscripted with +.B @ +or +.BR * , +the pattern removal operation is applied to each member of the +array in turn, and the expansion is the resultant list. .TP .PD 0 ${\fIparameter\fP\fB%\fP\fIword\fP} @@ -1431,14 +1945,64 @@ ${\fIparameter\fP\fB%\fP\fIword\fP} ${\fIparameter\fP\fB%%\fP\fIword\fP} .PD The \fIword\fP is expanded to produce a pattern just as in -pathname expansion. If the pattern matches a -trailing portion of the value of +pathname expansion. +If the pattern matches a trailing portion of the value of .IR parameter , then the expansion is the value of .I parameter -with the shortest matching pattern deleted -(the ``\fB%\fP'' case) or the longest -matching pattern deleted (the ``\fB%%\fP'' case). +with the shortest matching pattern (the ``\fB%\fP'' case) or the +longest matching pattern (the ``\fB%%\fP'' case) deleted. +If +.I parameter +is +.B @ +or +.BR * , +the pattern removal operation is applied to each positional +parameter in turn, and the expansion is the resultant list. +If +.I parameter +is an array variable subscripted with +.B @ +or +.BR * , +the pattern removal operation is applied to each member of the +array in turn, and the expansion is the resultant list. +.TP +.PD 0 +${\fIparameter\fP\fB/\fP\fIpattern\fP\fB/\fP\fIstring\fP} +.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 \fIpattern\fP begins with \fB#\fP, it must match at the beginning +of \fIstring\fP. +If \fIpattern\fP begins with \fB%\fP, it must match at the end +of \fIstring\fP. +If \fIstring\fP is null, matches of \fIpattern\fP are deleted +and the \fB/\fP following \fIpattern\fP may be omitted. +If +.I parameter +is +.B @ +or +.BR * , +the substitution operation is applied to each positional +parameter in turn, and the expansion is the resultant list. +If +.I parameter +is an array variable subscripted with +.B @ +or +.BR * , +the substitution operation is applied to each member of the +array in turn, and the expansion is the resultant list. .SS Command Substitution .PP \fICommand substitution\fP allows the output of a command to replace @@ -1453,12 +2017,12 @@ or \fB`\fP\fIcommand\fP\fB`\fP .RE .PP -. B Bash +.B Bash performs the expansion by executing \fIcommand\fP and replacing the command substitution with the standard output of the command, with any trailing newlines deleted. .PP -When the old\-style backquote form of substitution is used, +When the old-style backquote form of substitution is used, backslash retains its literal meaning except when followed by .BR $ , .BR ` , @@ -1475,22 +2039,19 @@ pathname expansion are not performed on the results. .SS Arithmetic Expansion .PP Arithmetic expansion allows the evaluation of an arithmetic expression -and the substitution of the result. There are two formats for -arithmetic expansion: +and the substitution of the result. The format for arithmetic expansion is: .RS .PP -\fB$[\fP\fIexpression\fP\fB]\fP -.PP \fB$((\fP\fIexpression\fP\fB))\fP .RE .PP The .I expression is treated as if it were within double quotes, but a double quote -inside the braces or parentheses -is not treated specially. All tokens in the -expression undergo parameter expansion, command substitution, -and quote removal. Arithmetic substitutions may be nested. +inside the parentheses is not treated specially. +All tokens in the expression undergo parameter expansion, string +expansion, command substitution, and quote removal. +Arithmetic substitutions may be nested. .PP The evaluation is performed according to the rules listed below under .SM @@ -1517,11 +2078,9 @@ the file will provide input for \fIlist\fP. If the argument should be read to obtain the output of \fIlist\fP. .PP On systems that support it, \fIprocess substitution\fP is performed -simultaneously with -.IR "parameter and variable expansion" , -.IR "command substitution" , -and -.IR "arithmetic expansion" . +simultaneously with parameter and variable expansion, +command substitution, +and arithmetic expansion. .SS Word Splitting .PP The shell scans the results of @@ -1536,11 +2095,11 @@ The shell treats each character of .SM .B IFS as a delimiter, and splits the results of the other -expansions into words on these characters. If the -value of +expansions into words on these characters. If .SM .B IFS -is exactly +is unset, or its +value is exactly .BR , the default, then any sequence of @@ -1581,15 +2140,13 @@ If the value of .SM .B IFS is null, no word splitting occurs. -.SM -.B IFS -cannot be unset. .PP -Explicit null arguments (\^\f3"\^"\fP or \^\f3'\^'\fP\^) -are retained. Implicit null arguments, resulting from the expansion -of +Explicit null arguments (\^\f3"\^"\fP or \^\f3'\^'\fP\^) are retained. +Unquoted implicit null arguments, resulting from the expansion of .I parameters that have no values, are removed. +If a parameter with no value is expanded within double quotes, a +null argument results and is retained. .PP Note that if no expansion occurs, no splitting is performed. @@ -1600,9 +2157,7 @@ unless the .B \-f option has been set, .B bash -scans each -.I word -for the characters +scans each word for the characters .BR * , .BR ? , and @@ -1611,23 +2166,75 @@ If one of these characters appears, then the word is regarded as a .IR pattern , and replaced with an alphabetically sorted list of -pathnames matching the pattern. -If no matching pathnames are found, -and the shell variable -.B allow_null_glob_expansion -is unset, the word is left unchanged. -If the variable is set, and no matches are found, +file names matching the pattern. +If no matching file names are found, +and the shell option +.B nullglob +is disabled, the word is left unchanged. +If the option is set, and no matches are found, the word is removed. -When a pattern is used for pathname generation, +When a pattern is used for pathname expansion, the character .B ``.'' at the start of a name or immediately following a slash -must be matched explicitly, unless the shell variable -.B glob_dot_filenames -is set. The slash character must always be matched -explicitly. In other cases, the +must be matched explicitly, unless the shell option +.B dotglob +is set. +The slash character must always be matched explicitly. +In other cases, the .B ``.'' character is not treated specially. +See the description of +.B shopt +below under +.SM +.B SHELL BUILTIN COMMANDS +for a description of the +.B nullglob +and +.B dotglob +shell options. +.PP +The +.SM +.B GLOBIGNORE +shell variable may be used to restrict the set of file names matching a +.IR pattern . +If +.SM +.B GLOBIGNORE +is set, each matching file name that also matches one of the patterns in +.SM +.B GLOBIGNORE +is removed from the list of matches. +The file names +.B ``.'' +and +.B ``..'' +are always ignored, even when +.SM +.B GLOBIGNORE +is set. However, setting +.SM +.B GLOBIGNORE +has the effect of enabling the +.B dotglob +shell option, so all other file names beginning with a +.B ``.'' +will match. +To get the old behavior of ignoring file names beginning with a +.BR ``.'' , +make +.B ``.*'' +one of the patterns in +.SM +.BR GLOBIGNORE . +The +.B dotglob +option is disabled when +.SM +.B GLOBIGNORE +is unset. .PP The special pattern characters have the following meanings: .PP @@ -1650,12 +2257,15 @@ is a .B ! or a .B ^ -then any character not enclosed is matched. A +then any character not enclosed is matched. +A .B \- -or -.B ] may be matched by including it as the first or last character in the set. +A +.B ] +may be matched by including it as the first character +in the set. .PD .SS Quote Removal .PP @@ -1663,7 +2273,8 @@ After the preceding expansions, all unquoted occurrences of the characters .BR \e , .BR ` , -and \^\f3"\fP\^ are removed. +and \^\f3"\fP\^ that did not result from one of the above +expansions are removed. .SH REDIRECTION Before a command is executed, its input and output may be @@ -1750,17 +2361,21 @@ The general format for redirecting output is: .RE .PP If the redirection operator is +.BR > , +and the +.B \-C +option to the +.B set +builtin has been enabled, the redirection will fail if the filename +whose name results from the expansion of \fIword\fP exists. +If the redirection operator is .BR >| , then the value of the -.B -C +.B \-C option to the .B set -builtin command is not tested, and file creation is attempted. -(See also the description of -.B noclobber -under -.B "Shell Variables" -above.) +builtin command is not tested, and the redirection is attempted even +if the file named by \fIword\fP exists. .SS Appending Redirected Output .PP Redirection of output in this fashion @@ -1822,7 +2437,7 @@ The format of here-documents is as follows: .PP .nf \fB<<\fP[\fB\-\fP]\fIword\fP - \fIhere-document\fP + \fIhere\-document\fP \fIdelimiter\fP .fi .RE @@ -1904,54 +2519,9 @@ causes the file whose name is the expansion of .I word to be opened for both reading and writing on file descriptor .IR n , -or as the standard input and standard output if +or on file descriptor 0 if .I n is not specified. If the file does not exist, it is created. -.SH FUNCTIONS -A shell function, defined as described above under -.SM -.BR "SHELL GRAMMAR" , -stores a series of commands for later execution. -Functions are executed in the context of the -current shell; no new process is created to interpret -them (contrast this with the execution of a shell script). -When a function is executed, the arguments to the -function become the positional parameters -during its execution. The special parameter -.B # -is updated to reflect the change. Positional parameter 0 -is unchanged. -.PP -Variables local to the function may be declared with the -.B local -builtin command. Ordinarily, variables and their values -are shared between the function and its caller. -.PP -If the builtin command -.B return -is executed in a function, the function completes and -execution resumes with the next command after the function -call. When a function completes, the values of the -positional parameters and the special parameter -.B # -are restored to the values they had prior to function -execution. -.PP -Function names and definitions may be listed with the -.B \-f -option to the -.B declare -or -.B typeset -builtin commands. Functions may be exported so that subshells -automatically have them defined with the -.B \-f -option to the -.B export -builtin. -.PP -Functions may be recursive. No limit is imposed on the number -of recursive calls. .SH ALIASES The shell maintains a list of .I aliases @@ -1990,12 +2560,20 @@ command, and removed with the .B unalias command. .PP -There is no mechanism for using arguments in the replacement text, -as in -.BR csh . +There is no mechanism for using arguments in the replacement text. If arguments are needed, a shell function should be used. .PP -Aliases are not expanded when the shell is not interactive. +Aliases are not expanded when the shell is not interactive, unless +the +.B expand_aliases +shell option is set using +.B shopt +(see the description of +.B shopt +under +.SM +\fBSHELL BUILTIN COMMANDS\fP +below). .PP The rules concerning the definition and use of aliases are somewhat confusing. @@ -2006,7 +2584,7 @@ of the commands on that line. Aliases are expanded when a command is read, not when it is executed. Therefore, an alias definition appearing on the same line as another command does not take effect until the next line of input is read. -This means that the commands following the alias definition +The commands following the alias definition on that line are not affected by the new alias. This behavior is also an issue when functions are executed. Aliases are expanded when the function definition is read, @@ -2020,209 +2598,68 @@ in compound commands. .PP Note that for almost every purpose, aliases are superseded by shell functions. -.SH "JOB CONTROL" -.I Job control -refers to the ability to selectively stop (\fIsuspend\fP) -the execution of processes and continue (\fIresume\fP) -their execution at a later point. A user typically employs -this facility via an interactive interface supplied jointly -by the system's terminal driver and -.BR bash . +.SH FUNCTIONS +A shell function, defined as described above under +.SM +.BR "SHELL GRAMMAR" , +stores a series of commands for later execution. +Functions are executed in the context of the +current shell; no new process is created to interpret +them (contrast this with the execution of a shell script). +When a function is executed, the arguments to the +function become the positional parameters +during its execution. The special parameter +.B # +is updated to reflect the change. Positional parameter 0 +is unchanged. All other aspects of the shell execution +environment are identical between a function and its caller +with the exception that the +.SM +.B DEBUG +trap (see the description of the +.B trap +builtin under +.SM +.B SHELL BUILTIN COMMANDS +below) is not inherited. .PP -The shell associates a -.I job -with each pipeline. It keeps a table of currently executing -jobs, which may be listed with the -.B jobs -command. When -.B bash -starts a job asynchronously (in the -.IR background ), -it prints a line that looks like: -.RS -.PP -[1] 25647 -.RE -.PP -indicating that this job is job number 1 and that the process ID -of the last process in the pipeline associated with this job is 25647. -All of the processes in a single pipeline are members of the same job. -.B Bash -uses the -.I job -abstraction as the basis for job control. -.PP -To facilitate the implementation of the user interface to job -control, the system maintains the notion of a \fIcurrent terminal -process group ID\fP. Members of this process group (processes whose -process group ID is equal to the current terminal process group ID) -receive keyboard-generated signals such as -.SM -.BR SIGINT . -These processes are said to be in the -.IR foreground . -.I Background -processes are those whose process group ID differs from the terminal's; -such processes are immune to keyboard-generated signals. -Only foreground processes are allowed to read from or write to the -terminal. Background processes which attempt to read from (write to) the -terminal are sent a -.SM -.B SIGTTIN (SIGTTOU) -signal by the terminal driver, -which, unless caught, suspends the process. -.PP -If the operating system on which -.B bash -is running supports -job control, -.B bash -allows you to use it. -Typing the -.I suspend -character (typically -.BR ^Z , -Control-Z) while a process is running -causes that process to be stopped and returns you to -.BR bash . -Typing the -.I "delayed suspend" -character (typically -.BR ^Y , -Control-Y) causes the process to be stopped when it -attempts to read input from the terminal, and control to -be returned to -.BR bash . -You may then manipulate the state of this job, using the -.B bg -command to continue it in the background, the -.B fg -command to continue it in the foreground, or -the -.B kill -command to kill it. A \fB^Z\fP takes effect immediately, -and has the additional side effect of causing pending output -and typeahead to be discarded. -.PP -There are a number of ways to refer to a job in the shell. -The character -.B % -introduces a job name. Job number -.I n -may be referred to as -.BR %n . -A job may also be referred to using a prefix of the name used to -start it, or using a substring that appears in its command line. -For example, -.B %ce -refers to a stopped -.B ce -job. If a prefix matches more than one job, -.B bash -reports an error. Using -.BR %?ce , -on the other hand, refers to any job containing the string -.B ce -in its command line. If the substring matches more than one job, -.B bash -reports an error. The symbols -.B %% -and -.B %+ -refer to the shell's notion of the -.IR "current job" , -which is the last job stopped while it was in -the foreground. -The -.I "previous job" -may be referenced using -.BR %\- . -In output pertaining to jobs (e.g., the output of the -.B jobs -command), the current job is always flagged with a -.BR + , -and the previous job with a -.BR \- . +Variables local to the function may be declared with the +.B local +builtin command. Ordinarily, variables and their values +are shared between the function and its caller. .PP -Simply naming a job can be used to bring it into the -foreground: -.B %1 -is a synonym for -\fB``fg %1''\fP, -bringing job 1 from the background into the foreground. -Similarly, -.B ``%1 &'' -resumes job 1 in the background, equivalent to -\fB``bg %1''\fP. +If the builtin command +.B return +is executed in a function, the function completes and +execution resumes with the next command after the function +call. When a function completes, the values of the +positional parameters and the special parameter +.B # +are restored to the values they had prior to function +execution. .PP -The shell learns immediately whenever a job changes state. -Normally, -.B bash -waits until it is about to print a prompt before reporting -changes in a job's status so as to not interrupt -any other output. If the -.B -b +Function names and definitions may be listed with the +.B \-f option to the -.B set -builtin command -is set, -.B bash -reports such changes immediately. (See also the description of -.B notify -variable under -.B "Shell Variables" -above.) -.PP -If you attempt to exit -.B bash -while jobs are stopped, the shell prints a message warning you. You -may then use the -.B jobs -command to inspect their status. If you do this, or try to exit -again immediately, you are not warned again, and the stopped -jobs are terminated. -.SH SIGNALS -When \fBbash\fP is interactive, it ignores -.SM -.B SIGTERM -(so that \fBkill 0\fP does not kill an interactive shell), -and -.SM -.B SIGINT -is caught and handled (so that the \fBwait\fP builtin is interruptible). -In all cases, \fBbash\fP ignores -.SM -.BR SIGQUIT . -If job control is in effect, -.B bash -ignores -.SM -.BR SIGTTIN , -.SM -.BR SIGTTOU , -and -.SM -.BR SIGTSTP . +.B declare +or +.B typeset +builtin commands. The +.B \-F +option to +.B declare +or +.B typeset +will list the function names only. +Functions may be exported so that subshells +automatically have them defined with the +.B \-f +option to the +.B export +builtin. .PP -Synchronous jobs started by \fBbash\fP have signals set to the -values inherited by the shell from its parent. When job control -is not in effect, background jobs (jobs started with -.BR & ) -ignore -.SM -.B SIGINT -and -.SM -.BR SIGQUIT . -Commands run as a result of command substitution ignore the -keyboard-generated job control signals -.SM -.BR SIGTTIN , -.SM -.BR SIGTTOU , -and -.SM -.BR SIGTSTP . +Functions may be recursive. No limit is imposed on the number +of recursive calls. .SH "COMMAND EXECUTION" After a command has been split into words, if it results in a simple command and an optional list of arguments, the following @@ -2244,8 +2681,20 @@ searches each element of the .SM .B PATH for a directory containing an executable file by that name. +.B Bash +uses a hash table to remember the full file names of executable +files (see +.B hash +under +.SM +.B "SHELL BUILTIN COMMANDS" +below). +A full search of the directories in +.SM +.B PATH +is performed only if the command is not found in the hash table. If the search is unsuccessful, the shell prints an error -message and returns a nonzero exit status. +message and returns a non-zero exit status. .PP If the search is successful, or if the command name contains one or more slashes, the shell executes the named program. @@ -2305,48 +2754,271 @@ less any pairs removed by the command, plus any additions via the .B export and -.B declare \-x -commands. +.B declare \-x +commands. +.PP +The environment for any +.I simple command +or function may be augmented temporarily by prefixing it with +parameter assignments, as described above in +.SM +.BR PARAMETERS . +These assignment statements affect only the environment seen +by that command. +.PP +If the +.B \-k +flag is set (see the +.B set +builtin command below), then +.I all +parameter assignments are placed in the environment for a command, +not just those that precede the command name. +.PP +When +.B bash +invokes an external command, the variable +.B _ +is set to the full file name of the command and passed to that +command in its environment. +.SH "EXIT STATUS" +For the purposes of the shell, a command which exits with a +zero exit status has succeeded. An exit status of zero +indicates success. A non-zero exit status indicates failure. +When a command terminates on a fatal signal, \fBbash\fP uses +the value of 128+\fBsignal\fP as the exit status. +.PP +If a command is not found, the child process created to +execute it returns a status of 127. If a command is found +but is not executable, the return status is 126. +.PP +Shell builtin commands return a status of 0 (\fItrue\fP) if +successful, and non-zero (\fIfalse\fP) if an error occurs +while they execute. +All builtins return an exit status of 2 to indicate incorrect usage. +.PP +\fBBash\fP itself returns the exit status of the last command +executed, unless a syntax error occurs, in which case it exits +with a non-zero value. See also the \fBexit\fP builtin +command below. +.SH SIGNALS +When \fBbash\fP is interactive, it ignores +.SM +.B SIGTERM +(so that \fBkill 0\fP does not kill an interactive shell), +and +.SM +.B SIGINT +is caught and handled (so that the \fBwait\fP builtin is interruptible). +In all cases, \fBbash\fP ignores +.SM +.BR SIGQUIT . +If job control is in effect, +.B bash +ignores +.SM +.BR SIGTTIN , +.SM +.BR SIGTTOU , +and +.SM +.BR SIGTSTP . +.PP +Synchronous jobs started by \fBbash\fP have signals set to the +values inherited by the shell from its parent. When job control +is not in effect, background jobs (jobs started with +.BR & ) +ignore +.SM +.B SIGINT +and +.SM +.BR SIGQUIT . +Commands run as a result of command substitution ignore the +keyboard-generated job control signals +.SM +.BR SIGTTIN , +.SM +.BR SIGTTOU , +and +.SM +.BR SIGTSTP . +.PP +The shell exits by default upon receipt of a +.SM +.BR SIGHUP . +Before exiting, it resends the +.SM +.B SIGHUP +to all jobs, running or stopped. To prevent the shell from +sending the signal to a particular job, remove it from the +jobs table with the +.B disown +builtin (see +.SM +.B "SHELL BUILTIN COMMANDS" +below) or use +.B "disown \-h" +to mark it to not receive +.SM +.BR SIGHUP . +.SH "JOB CONTROL" +.I Job control +refers to the ability to selectively stop (\fIsuspend\fP) +the execution of processes and continue (\fIresume\fP) +their execution at a later point. A user typically employs +this facility via an interactive interface supplied jointly +by the system's terminal driver and +.BR bash . +.PP +The shell associates a +.I job +with each pipeline. It keeps a table of currently executing +jobs, which may be listed with the +.B jobs +command. When +.B bash +starts a job asynchronously (in the +.IR background ), +it prints a line that looks like: +.RS +.PP +[1] 25647 +.RE +.PP +indicating that this job is job number 1 and that the process ID +of the last process in the pipeline associated with this job is 25647. +All of the processes in a single pipeline are members of the same job. +.B Bash +uses the +.I job +abstraction as the basis for job control. +.PP +To facilitate the implementation of the user interface to job +control, the system maintains the notion of a \fIcurrent terminal +process group ID\fP. Members of this process group (processes whose +process group ID is equal to the current terminal process group ID) +receive keyboard-generated signals such as +.SM +.BR SIGINT . +These processes are said to be in the +.IR foreground . +.I Background +processes are those whose process group ID differs from the terminal's; +such processes are immune to keyboard-generated signals. +Only foreground processes are allowed to read from or write to the +terminal. Background processes which attempt to read from (write to) the +terminal are sent a +.SM +.B SIGTTIN (SIGTTOU) +signal by the terminal driver, +which, unless caught, suspends the process. +.PP +If the operating system on which +.B bash +is running supports +job control, +.B bash +allows you to use it. +Typing the +.I suspend +character (typically +.BR ^Z , +Control-Z) while a process is running +causes that process to be stopped and returns you to +.BR bash . +Typing the +.I "delayed suspend" +character (typically +.BR ^Y , +Control-Y) causes the process to be stopped when it +attempts to read input from the terminal, and control to +be returned to +.BR bash . +You may then manipulate the state of this job, using the +.B bg +command to continue it in the background, the +.B fg +command to continue it in the foreground, or +the +.B kill +command to kill it. A \fB^Z\fP takes effect immediately, +and has the additional side effect of causing pending output +and typeahead to be discarded. +.PP +There are a number of ways to refer to a job in the shell. +The character +.B % +introduces a job name. Job number +.I n +may be referred to as +.BR %n . +A job may also be referred to using a prefix of the name used to +start it, or using a substring that appears in its command line. +For example, +.B %ce +refers to a stopped +.B ce +job. If a prefix matches more than one job, +.B bash +reports an error. Using +.BR %?ce , +on the other hand, refers to any job containing the string +.B ce +in its command line. If the substring matches more than one job, +.B bash +reports an error. The symbols +.B %% +and +.B %+ +refer to the shell's notion of the +.IR "current job" , +which is the last job stopped while it was in +the foreground. +The +.I "previous job" +may be referenced using +.BR %\- . +In output pertaining to jobs (e.g., the output of the +.B jobs +command), the current job is always flagged with a +.BR + , +and the previous job with a +.BR \- . .PP -The environment for any -.I simple command -or function may be augmented temporarily by prefixing it with -parameter assignments, as described above in -.SM -.BR PARAMETERS . -These assignment statements affect only the environment seen -by that command. +Simply naming a job can be used to bring it into the +foreground: +.B %1 +is a synonym for +\fB``fg %1''\fP, +bringing job 1 from the background into the foreground. +Similarly, +.B ``%1 &'' +resumes job 1 in the background, equivalent to +\fB``bg %1''\fP. .PP -If the -.B \-k -flag is set (see the +The shell learns immediately whenever a job changes state. +Normally, +.B bash +waits until it is about to print a prompt before reporting +changes in a job's status so as to not interrupt +any other output. If the +.B \-b +option to the .B set -builtin command below), then -.I all -parameter assignments are placed in the environment for a command, -not just those that precede the command name. -.PP -When +builtin command +is set, .B bash -invokes an external command, the variable -.B _ -is set to the full path name of the command and passed to that -command in its environment. -.SH "EXIT STATUS" -For the purposes of the shell, a command which exits with a -zero exit status has succeeded. An exit status of zero -indicates success. A non\-zero exit status indicates failure. -When a command terminates on a fatal signal, \fBbash\fP uses -the value of 128+\fBsignal\fP as the exit status. -.PP -If a command is not found, the child process created to -execute it returns a status of 127. If a command is found -but is not executable, the return status is 126. +reports such changes immediately. .PP -\fBBash\fP itself returns the exit status of the last command -executed, unless a syntax error occurs, in which case it exits -with a non\-zero value. See also the \fBexit\fP builtin -command below. +If an attempt to exit +.B bash +is made while jobs are stopped, the shell prints a warning message. The +.B jobs +command may then be used to inspect their status. +If a second attempt to exit is made without an intervening command, +the shell does not print another warning, and the stopped +jobs are terminated. .SH PROMPTING When executing interactively, .B bash @@ -2363,12 +3035,21 @@ backslash-escaped special characters that are decoded as follows: .RS .PD 0 .TP -.B \et -the current time in HH:MM:SS format +.B \ea +an ASCII bell character (07) .TP .B \ed the date in "Weekday Month Date" format (e.g., "Tue May 26") .TP +.B \ee +an ASCII escape character (033) +.TP +.B \eh +the hostname up to the first `.' +.TP +.B \eH +the hostname +.TP .B \en newline .TP @@ -2377,32 +3058,44 @@ the name of the shell, the basename of .B $0 (the portion following the final slash) .TP -.B \ew -the current working directory +.B \et +the current time in 24-hour HH:MM:SS format .TP -.B \eW -the basename of the current working directory +.B \eT +the current time in 12-hour HH:MM:SS format +.TP +.B \e@ +the current time in 12-hour am/pm format .TP .B \eu the username of the current user .TP -.B \eh -the hostname +.B \ev +the version of \fBbash\fP (e.g., 2.00) .TP -.B \e# -the command number of this command +.B \eV +the release of \fBbash\fP, version + patchlevel (e.g., 2.00.0) +.TP +.B \ew +the current working directory +.TP +.B \eW +the basename of the current working directory .TP .B \e! the history number of this command .TP +.B \e# +the command number of this command +.TP .B \e$ if the effective UID is 0, a .BR # , otherwise a .B $ .TP -.B \ennn -the character corresponding to the octal number \fBnnn\fP +.B \e\fInnn\fP +the character corresponding to the octal number \fInnn\fP .TP .B \e\e a backslash @@ -2425,15 +3118,33 @@ list, which may include commands restored from the history file below), while the command number is the position in the sequence of commands executed during the current shell session. After the string is decoded, it is expanded via -parameter expansion, -command substitution, arithmetic expansion, and word splitting. +parameter expansion, command substitution, arithmetic expansion, +string expansion, and quote removal, subject to the value of the +.B promptvars +shell option (see the description of the +.B shopt +command under +.SM +.B "SHELL BUILTIN COMMANDS" +below). .SH READLINE This is the library that handles reading input when using an interactive shell, unless the -.B \-nolineediting -option is given. By default, the line editing commands -are similar to those of emacs. +.B \-noediting +option is given at shell invocation. +By default, the line editing commands are similar to those of emacs. A vi-style line editing interface is also available. +To turn off line editing after the shell is running, use the +.B +o emacs +or +.B +o vi +options to the +.B set +builtin (see +.SM +.B SHELL BUILTIN COMMANDS +below). +.SS "Readline Notation" .PP In this section, the emacs-style notation is used to denote keystrokes. Control keys are denoted by C\-\fIkey\fR, e.g., C\-n @@ -2452,13 +3163,45 @@ then hold the Control key while pressing the .I x key.) .PP -The default key-bindings may be changed with an -.FN ~/.inputrc -file. The value of the shell variable +Readline commands may be given numeric +.IR arguments , +which normally act as a repeat count. +Sometimes, however, it is the sign of the argument that is significant. +Passing a negative argument to a command that acts in the forward +direction (e.g., \fBkill\-line\fP) causes that command to act in a +backward direction. +Commands whose behavior with arguments deviates from this are noted +below. +.PP +When a command is described as \fIkilling\fP text, the text +deleted is saved for possible future retrieval +(\fIyanking\fP). The killed text is saved in a +\fIkill ring\fP. Consecutive kills cause the text to be +accumulated into one unit, which can be yanked all at once. +Commands which do not kill text separate the chunks of text +on the kill ring. +.SS "Readline Initialization" +.PP +Readline is customized by putting commands in an initialization +file (the \fIinputrc\fP file). +The name of this file is taken from the value of the .SM -.BR INPUTRC , -if set, is used instead of +.B INPUTRC +variable. If that variable is unset, the default is .IR ~/.inputrc . +When a program which uses the readline library starts up, the +initialization file is read, and the key bindings and variables +are set. +There are only a few basic constructs allowed in the +readline initialization file. +Blank lines are ignored. +Lines beginning with a \fB#\fP are comments. +Lines beginning with a \fB$\fP indicate conditional constructs. +Other lines denote key bindings and variable settings. +.PP +The default key-bindings may be changed with an +.I inputrc +file. Other programs that use this library may add their own commands and bindings. .PP @@ -2472,7 +3215,7 @@ or C\-Meta\-u: universal\-argument .RE into the -.FN ~/.inputrc +.I inputrc would make M\-C\-u execute the readline command .IR universal\-argument . .PP @@ -2490,30 +3233,16 @@ and .IR TAB . In addition to command names, readline allows keys to be bound to a string that is inserted when the key is pressed (a \fImacro\fP). -.PP -Readline is customized by putting commands in an initialization -file. The name of this file is taken from the value of the -.SM -.B INPUTRC -variable. If that variable is unset, the default is -.IR ~/.inputrc . -When a program which uses the readline library starts up, the -init file is read, and the key bindings and variables are set. -There are only a few basic constructs allowed in the -readline init file. Blank lines are ignored. -Lines beginning with a \fB#\fP are comments. -Lines beginning with a \fB$\fP indicate conditional -constructs. Other lines -denote key bindings and variable settings. +.SS "Readline Key Bindings" .PP The syntax for controlling key bindings in the .I ~/.inputrc file is simple. All that is required is the name of the command or the text of a macro and a key sequence to which it should be bound. The name may be specified in one of two ways: -as a symbolic key name, possibly with \fIMeta-\fP or \fIControl-\fP +as a symbolic key name, possibly with \fIMeta\-\fP or \fIControl\-\fP prefixes, or as a key sequence. -When using the form \fBkeyname\fP:\fIfunction-name\fP or \fImacro\fP, +When using the form \fBkeyname\fP:\fIfunction\-name\fP or \fImacro\fP, .I keyname is the name of a key spelled out in English. For example: .sp @@ -2522,24 +3251,24 @@ Control-u: universal\-argument .br Meta-Rubout: backward-kill-word .br -Control-o: ">&output" +Control-o: "> output" .RE .LP In the above example, -.I C-u +.I C\-u is bound to the function .BR universal\-argument , -.I M-DEL +.I M\-DEL is bound to the function .BR backward\-kill\-word , and -.I C-o +.I C\-o is bound to run the macro expressed on the right hand side (that is, to insert the text -.I >&output +.I "> output" into the line). .PP -In the second form, \fB"keyseq"\fP:\fIfunction-name\fP or \fImacro\fP, +In the second form, \fB"keyseq"\fP:\fIfunction\-name\fP or \fImacro\fP, .B keyseq differs from .B keyname @@ -2549,18 +3278,18 @@ within double quotes. Some GNU Emacs style key escapes can be used, as in the following example. .sp .RS -"\eC-u": universal\-argument +"\eC\-u": universal\-argument .br -"\eC-x\eC-r": re\-read\-init\-file +"\eC\-x\eC\-r": re\-read\-init\-file .br "\ee[11~": "Function Key 1" .RE .PP In this example, -.I C-u +.I C\-u is again bound to the function .BR universal\-argument . -.I "C-x C-r" +.I "C\-x C\-r" is bound to the function .BR re\-read\-init\-file , and @@ -2573,7 +3302,7 @@ The full set of escape sequences is .B \eC\- control prefix .TP -.B \eM- +.B \eM\- meta prefix .TP .B \ee @@ -2607,6 +3336,7 @@ builtin command (see .SM .B SHELL BUILTIN COMMANDS below). +.SS "Readline Variables" .PP Readline has variables that can be used to further customize its behavior. A variable may be set in the @@ -2625,24 +3355,6 @@ The variables and their default values are: .PP .PD 0 .TP -.B horizontal\-scroll\-mode (Off) -When set to \fBOn\fP, makes readline use a single line for display, -scrolling the input horizontally on a single screen line when it -becomes longer than the screen width rather than wrapping to a new line. -.TP -.B editing\-mode (emacs) -Controls whether readline begins with a set of key bindings similar -to \fIemacs\fP or \fIvi\fP. -.B editing\-mode -can be set to either -.B emacs -or -.BR vi . -.TP -.B mark\-modified\-lines (Off) -If set to \fBOn\fP, history lines that have been modified are displayed -with a preceding asterisk (\fB*\fP). -.TP .B bell\-style (audible) Controls what happens when readline wants to ring the terminal bell. If set to \fBnone\fP, readline never rings the bell. If set to @@ -2650,25 +3362,15 @@ If set to \fBnone\fP, readline never rings the bell. If set to If set to \fBaudible\fP, readline attempts to ring the terminal's bell. .TP .B comment\-begin (``#'') -The string that is inserted in \fBvi\fP mode when the -.B vi\-comment +The string that is inserted when the +.B readline +.B insert\-comment command is executed. -.TP -.B meta\-flag (Off) -If set to \fBOn\fP, readline will enable eight-bit input (that is, -it will not strip the high bit from the characters it reads), -regardless of what the terminal claims it can support. -.TP -.B convert\-meta (On) -If set to \fBOn\fP, readline will convert characters with the -eighth bit set to an ASCII key sequence -by stripping the eighth bit and prepending an -escape character (in effect, using escape as the \fImeta prefix\fP). -.TP -.B output\-meta (Off) -If set to \fBOn\fP, readline will display characters with the -eighth bit set directly rather than as a meta-prefixed escape -sequence. +This command is bound to +.B M\-# +in emacs mode and to +.B # +in vi command mode. .TP .B completion\-query\-items (100) This determines when the user is queried about viewing @@ -2680,18 +3382,72 @@ or equal to the value of this variable, the user is asked whether or not he wishes to view them; otherwise they are simply listed on the terminal. .TP +.B convert\-meta (On) +If set to \fBOn\fP, readline will convert characters with the +eighth bit set to an ASCII key sequence +by stripping the eighth bit and prepending an +escape character (in effect, using escape as the \fImeta prefix\fP). +.TP +.B disable\-completion (Off) +If set to \fBOn\fP, readline will inhibit word completion. Completion +characters will be inserted into the line as if they had been +mapped to \fBself-insert\fP. +.TP +.B editing\-mode (emacs) +Controls whether readline begins with a set of key bindings similar +to \fIemacs\fP or \fIvi\fP. +.B editing\-mode +can be set to either +.B emacs +or +.BR vi . +.TP +.B enable\-keypad (Off) +When set to \fBOn\fP, readline will try to enable the application +keypad when it is called. Some systems need this to enable the +arrow keys. +.TP +.B expand\-tilde (Off) +If set to \fBon\fP, tilde expansion is performed when readline +attempts word completion. +.TP +.B horizontal\-scroll\-mode (Off) +When set to \fBOn\fP, makes readline use a single line for display, +scrolling the input horizontally on a single screen line when it +becomes longer than the screen width rather than wrapping to a new line. +.TP +.B input\-meta (Off) +If set to \fBOn\fP, readline will enable eight-bit input (that is, +it will not strip the high bit from the characters it reads), +regardless of what the terminal claims it can support. The name +.B meta\-flag +is a synonym for this variable. +.TP .B keymap (emacs) Set the current readline keymap. The set of legal keymap names is -\fIemacs, emacs-standard, emacs-meta, emacs-ctlx, vi, vi-move, -vi-command\fP, and -.IR vi-insert . -\fIvi\fP is equivalent to \fIvi-command\fP; \fIemacs\fP is -equivalent to \fIemacs-standard\fP. The default value is +\fIemacs, emacs\-standard, emacs\-meta, emacs\-ctlx, vi, +vi\-command\fP, and +.IR vi\-insert . +\fIvi\fP is equivalent to \fIvi\-command\fP; \fIemacs\fP is +equivalent to \fIemacs\-standard\fP. The default value is .IR emacs ; the value of .B editing\-mode also affects the default keymap. .TP +.B mark\-directories (On) +If set to \fBOn\fP, completed directory names have a slash +appended. +.TP +.B mark\-modified\-lines (Off) +If set to \fBOn\fP, history lines that have been modified are displayed +with a preceding asterisk (\fB*\fP). +.TP +.B output\-meta (Off) +If set to \fBOn\fP, readline will display characters with the +eighth bit set directly rather than as a meta-prefixed escape +sequence. +.TP .B show\-all\-if\-ambiguous (Off) This alters the default behavior of the completion functions. If set to @@ -2699,10 +3455,12 @@ set to words which have more than one possible completion cause the matches to be listed immediately instead of ringing the bell. .TP -.B expand\-tilde (Off) -If set to \fBon\fP, tilde expansion is performed when readline -attempts word completion. +.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 +completions. .PD +.SS "Readline Conditional Constructs" .PP Readline implements a facility similar in spirit to the conditional compilation features of the C preprocessor which allows key @@ -2721,7 +3479,7 @@ The \fBmode=\fP form of the \fB$if\fP directive is used to test whether readline is in emacs or vi mode. This may be used in conjunction with the \fBset keymap\fP command, for instance, to set bindings in -the \fIemacs-standard\fP and \fIemacs-ctlx\fP keymaps only if +the \fIemacs\-standard\fP and \fIemacs\-ctlx\fP keymaps only if readline is starting out in emacs mode. .IP \fBterm\fP The \fBterm=\fP form may be used to include terminal-specific @@ -2738,7 +3496,7 @@ and for instance. .IP \fBapplication\fP The \fBapplication\fP construct is used to include -application\-specific settings. Each program using the readline +application-specific settings. Each program using the readline library sets the \fIapplication name\fP, and an initialization file can test for a particular value. This could be used to bind key sequences to functions useful for @@ -2748,7 +3506,7 @@ key sequence that quotes the current or previous word in Bash: .nf \fB$if\fP Bash # Quote the current or previous word -"\eC-xq": "\eeb\e"\eef\e"" +"\eC\-xq": "\eeb\e"\eef\e"" \fB$endif\fP .fi .RE @@ -2759,25 +3517,47 @@ This command, as you saw in the previous example, terminates an .IP \fB$else\fP Commands in this branch of the \fB$if\fP directive are executed if the test fails. +.SS Searching .PP -Readline commands may be given numeric -.IR arguments , -which normally act as a repeat count. Sometimes, however, it is the -sign of the argument that is significant. Passing a negative argument -to a command that acts in the forward direction (e.g., \fBkill\-line\fP) -causes that command to act in a backward direction. Commands whose -behavior with arguments deviates from this are noted. -.PP -When a command is described as \fIkilling\fP text, the text -deleted is saved for possible future retrieval -(\fIyanking\fP). The killed text is saved in a -\fIkill\-ring\fP. Consecutive kills cause the text to be -accumulated into one unit, which can be yanked all at once. -Commands which do not kill text separate the chunks of text -on the kill\-ring. +Readline provides commands for searching through the command history +(see +.SM +.B HISTORY +below) for lines containing a specified string. +There are two search modes: +.I incremental +and +.IR non-incremental . +.PP +Incremental searches begin before the user has finished typing the +search string. +As each character of the search string is typed, readline displays +the next entry from the history matching the string typed so far. +An incremental search requires only as many characters as needed to +find the desired history entry. +The Escape character is used to terminate an incremental search. +Control-J will also terminate the search. +Control-G will abort an incremental search and restore the original +line. +When the search is terminated, the history entry containing the +search string becomes the current line. +To find other matching entries in the history list, type Control-S or +Control-R as appropriate. +This will search backward or forward in the history for the next +entry matching the search string typed so far. +Any other key sequence bound to a readline command will terminate +the search and execute that command. +For instance, a \fInewline\fP will terminate the search and accept +the line, thereby executing the command from the history list. +.PP +Non-incremental searches read the entire search string before starting +to search for matching history lines. The search string may be +typed by the user or part of the contents of the current line. +.SS "Readline Command Names" .PP The following is a list of the names of the commands and the default key sequences to which they are bound. +Command names without an accompanying key sequence are unbound by default. .SS Commands for Moving .PP .PD 0 @@ -2808,7 +3588,7 @@ With an argument, refresh the current line without clearing the screen. .TP .B redraw\-current\-line -Refresh the current line. By default, this is unbound. +Refresh the current line. .PD .SS Commands for Manipulating the History .PP @@ -2816,7 +3596,7 @@ Refresh the current line. By default, this is unbound. .TP .B accept\-line (Newline, Return) Accept the line regardless of where the cursor is. If this line is -non\-empty, add it to the history list according to the state of the +non-empty, add it to the history list according to the state of the .SM .B HISTCONTROL variable. If the line is a modified history @@ -2847,21 +3627,22 @@ the history as necessary. This is an incremental search. .TP .B non\-incremental\-reverse\-search\-history (M\-p) Search backward through the history starting at the current line -using a non\-incremental search for a string supplied by the user. +using a non-incremental search for a string supplied by the user. .TP .B non\-incremental\-forward\-search\-history (M\-n) -Search forward through the history using a non\-incremental search for +Search forward through the history using a non-incremental search for a string supplied by the user. .TP .B history\-search\-forward Search forward through the history for the string of characters -between the start of the current line and the current point. This -is a non-incremental search. By default, this command is unbound. +between the start of the current line and the current cursor +position (the \fIpoint\fP). +This is a non-incremental search. .TP .B history\-search\-backward Search backward through the history for the string of characters -between the start of the current line and the current point. This -is a non-incremental search. By default, this command is unbound. +between the start of the current line and the point. +This is a non-incremental search. .TP .B yank\-nth\-arg (M\-C\-y) Insert the first argument to the previous command (usually @@ -2874,9 +3655,9 @@ inserts the \fIn\fPth word from the end of the previous command. .TP .B yank\-last\-arg (M\-.\^, M\-_\^) -Insert the last argument to the previous command (the last word on -the previous line). With an argument, -behave exactly like \fByank-nth-arg\fP. +Insert the last argument to the previous command (the last word of +the previous history entry). With an argument, +behave exactly like \fByank\-nth\-arg\fP. .TP .B shell\-expand\-line (M\-C\-e) Expand the line the way the shell does when it reads it. This @@ -2895,7 +3676,7 @@ below for a description of history expansion. .B insert\-last\-argument (M\-.\^, M\-_\^) A synonym for \fByank\-last\-arg\fP. .TP -.B operate-and-get-next (C\-o) +.B operate\-and\-get\-next (C\-o) Accept the current line for execution and fetch the next line relative to the current line from the history for editing. Any argument is ignored. @@ -2915,13 +3696,13 @@ then return .TP .B backward\-delete\-char (Rubout) Delete the character behind the cursor. When given a numeric argument, -save the deleted text on the kill\-ring. +save the deleted text on the kill ring. .TP .B quoted\-insert (C\-q, C\-v) Add the next character that you type to the line verbatim. This is how to insert characters like \fBC\-q\fP, for example. .TP -.B tab\-insert (C-v TAB) +.B tab\-insert (C\-v TAB) Insert a tab character. .TP .B self\-insert (a,\ b,\ A,\ 1,\ !,\ ...) @@ -2955,7 +3736,7 @@ do the previous word, but do not move point. .B kill\-line (C\-k) Kill the text from the current cursor position to the end of the line. .TP -.B backward\-kill\-line (C\-x C\-Rubout) +.B backward\-kill\-line (C\-x Rubout) Kill backward to the beginning of the line. .TP .B unix\-line\-discard (C\-u) @@ -2964,7 +3745,7 @@ Kill backward from point to the beginning of the line. .TP .B kill\-whole\-line Kill all characters on the current line, no matter where the -cursor is. By default, this is unbound. +cursor is. .TP .B kill\-word (M\-d) Kill from the cursor to the end of the current word, or if between @@ -2977,16 +3758,29 @@ those used by \fBbackward\-word\fP. .TP .B unix\-word\-rubout (C\-w) Kill the word behind the cursor, using white space as a word boundary. -The word boundaries are different from backward\-kill\-word. +The word boundaries are different from \fBbackward\-kill\-word\fP. +.TP +.B delete\-horizontal\-space (M\-\e) +Delete all spaces and tabs around point. +.TP +.B kill\-region +Kill the text between the point and \fImark\fP (saved cursor position). +This text is referred to as the \fIregion\fP. +.TP +.B copy\-region\-as\-kill +Copy the text in the region to the kill buffer. .TP -.B delete\-horizontal\-space -Delete all spaces and tabs around point. By default, this is unbound. +.B copy\-backward\-word +Copy the word before point to the kill buffer. +.TP +.B copy\-forward\-word +Copy the word following point to the kill buffer. .TP .B yank (C\-y) Yank the top of the kill ring into the buffer at the cursor. .TP .B yank\-pop (M\-y) -Rotate the kill\-ring, and yank the new top. Only works following +Rotate the kill ring, and yank the new top. Only works following .B yank or .BR yank\-pop . @@ -3002,8 +3796,7 @@ argument. M\-\- starts a negative argument. .B universal\-argument Each time this is executed, the argument count is multiplied by four. The argument count is initially one, so executing this function the -first time makes the argument count four. By default, this is not -bound to a key. +first time makes the argument count four. .PD .SS Completing .PP @@ -3018,14 +3811,13 @@ text begins with \fB$\fP), username (if the text begins with command (including aliases and functions) in turn. If none of these produces a match, filename completion is attempted. .TP -.B possible\-completions (M-?) +.B possible\-completions (M\-?) List the possible completions of the text before point. .TP -.B insert\-completions +.B insert\-completions (M\-*) Insert all completions of the text before point that would have been generated by -\fBpossible\-completions\fP. By default, this -is not bound to a key. +\fBpossible\-completions\fP. .TP .B complete\-filename (M\-/) Attempt filename completion on the text before point. @@ -3069,7 +3861,7 @@ in that order. List the possible completions of the text before point, treating it as a command name. .TP -.B dynamic\-complete\-history (M-TAB) +.B dynamic\-complete\-history (M\-TAB) Attempt completion on the text before point, comparing the text against lines from the history list for possible completion matches. @@ -3084,14 +3876,14 @@ above). .PP .PD 0 .TP -.B start\-kbd\-macro (C-x (\^) +.B start\-kbd\-macro (C\-x (\^) Begin saving the characters typed into the current keyboard macro. .TP -.B end\-kbd\-macro (C-x )\^) +.B end\-kbd\-macro (C\-x )\^) Stop saving the characters typed into the current keyboard macro -and save the definition. +and store the definition. .TP -.B call\-last\-kbd\-macro (C-x e) +.B call\-last\-kbd\-macro (C\-x e) Re-execute the last keyboard macro defined, by making the characters in the macro appear as if typed at the keyboard. .PD @@ -3100,7 +3892,7 @@ in the macro appear as if typed at the keyboard. .PD 0 .TP .B re\-read\-init\-file (C\-x C\-r) -Read in the contents of your init file, and incorporate +Read in the contents of the \fIinputrc\fP file, and incorporate any bindings or variable assignments found there. .TP .B abort (C\-g) @@ -3108,9 +3900,9 @@ Abort the current editing command and ring the terminal's bell (subject to the setting of .BR bell\-style ). .TP -.B do\-uppercase\-version (M\-a, M\-b, ...) -Run the command that is bound to the corresponding uppercase -character. +.B do\-uppercase\-version (M\-a, M\-b, M\-\fIx\fP, ...) +If the metafied character \fIx\fP is lowercase, run the command +that is bound to the corresponding uppercase character. .TP .B prefix\-meta (ESC) Metafy the next character typed. @@ -3131,18 +3923,68 @@ command enough times to return the line to its initial state. .B tilde\-expand (M\-~) Perform tilde expansion on the current word. .TP +.B set\-mark (C\-@, M\-) +Set the mark to the current point. If a +numeric argument is supplied, the mark is set to that position. +.TP +.B exchange\-point\-and\-mark (C\-x C\-x) +Swap the point with the mark. The current cursor position is set to +the saved position, and the old cursor position is saved as the mark. +.TP +.B character\-search (C\-]) +A character is read and point is moved to the next occurrence of that +character. A negative count searches for previous occurrences. +.TP +.B character\-search\-backward (M\-C\-]) +A character is read and point is moved to the previous occurrence of that +character. A negative count searches for subsequent occurrences. +.TP +.B insert\-comment (M\-#) +The value of the +.B readline +.B comment\-begin +variable is inserted at the beginning of the current line, and the line +is accepted as if a newline had been typed. This makes the current line +a shell comment. +.TP +.B glob\-expand\-word (C\-x *) +The word before point is treated as a pattern for pathname expansion, +and the list of matching file names is inserted, replacing the word. +.TP +.B glob\-list\-expansions (C\-x g) +The list of expansions that would have been generated by +.B glob\-expand\-word +is displayed, and the line is redrawn. +.TP .B dump\-functions Print all of the functions and their key bindings to the readline output stream. 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 +.B dump\-variables +Print all of the settable readline variables and their values to the +readline output stream. 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 +.B dump\-macros +Print all of the readline key sequences bound to macros and the +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 .B display\-shell\-version (C\-x C\-v) Display version information about the current instance of .BR bash . .PD .SH HISTORY -When interactive, the shell provides access to the \fIcommand history\fP, +When the +.B -o history +option to the +.B set +builtin is enabled, the shell provides access to the +\fIcommand history\fP, the list of commands previously typed. The text of the last .SM .B HISTSIZE @@ -3153,7 +3995,8 @@ variable expansion (see .B EXPANSION above) but after history expansion is performed, subject to the values of the shell variables -.B command_oriented_history +.SM +.B HISTIGNORE and .SM .BR HISTCONTROL . @@ -3168,6 +4011,35 @@ is truncated, if necessary, to contain no more than .SM .B HISTFILESIZE lines. +When an interactive shell exits, the last +.SM +.B HISTSIZE +lines are copied from the history list to +.SM +.BR HISTFILE . +If the +.B histappend +shell option is enabled +(see the description of +.B shopt +under +.SM +.B "SHELL BUILTIN COMMANDS" +below), the lines are appended to the history file, +otherwise the history file is overwritten. +If +.SM +.B HISTFILE +is unset, or if the history file is unwritable, the history is +not saved. After saving the history, the history file is truncated +to contain no more than +.SM +.B HISTFILESIZE +lines. If +.SM +.B HISTFILESIZE +is not set, no truncation is performed. +.PP The builtin command .B fc (see @@ -3177,20 +4049,35 @@ below) may be used to list or edit and re-execute a portion of the history list. The .B history -builtin can be used to display the history list and manipulate the -history file. When using the command-line editing, search commands +builtin can be used to display or modify the history list and +manipulate the history file. +When using the command-line editing, search commands are available in each editing mode that provide access to the -history list. When an interactive shell exits, the last -.SM -.B HISTSIZE -lines are copied from the history list to +history list. +.PP +The shell allows control over which commands are saved on the history +list. The .SM -.BR HISTFILE . -If +.B HISTCONTROL +and .SM -.B HISTFILE -is unset, or if the history file is unwritable, the history is -not saved. +.B HISTIGNORE +variables may be set to cause the shell to save only a subset of the +commands entered. +The +.B cmdhist +shell option, if enabled, causes the shell to attempt to save each +line of a multi-line command in the same history entry, adding +semicolons where necessary to preserve syntactic correctness. +The +.B lithist +shell option causes the shell to save the command with embedded newlines +instead of semicolons. See the description of the +.B shopt +builtin below under +.SM +.B "SHELL BUILTIN COMMANDS" +for information on setting and unsetting shell options. .SH "HISTORY EXPANSION" .PP The shell supports a history expansion feature that @@ -3205,21 +4092,67 @@ option to the builtin command (see .SM .B SHELL BUILTIN COMMANDS -below). Non-interactive shells do not perform history expansion. +below). Non-interactive shells do not perform history expansion +by default. +.PP +History expansions introduce words from the history list into +the input stream, making it easy to repeat commands, insert the +arguments to a previous command into the current input line, or +fix errors in previous commands quickly. .PP History expansion is performed immediately after a complete line is read, before the shell breaks it into words. -It takes place in two parts. The first is to determine -which line from the previous history to use during -substitution. The second is to select portions of that line for -inclusion into the current one. The line selected from the -previous history is the \fIevent\fP, and the portions of that -line that are acted upon are \fIwords\fP. The line is broken -into words in the same fashion as when reading input, so that -several \fImetacharacter\fP\-separated words surrounded by quotes -are considered as one word. Only backslash (\^\fB\e\fP\^) -and single quotes can quote -the history escape character, which is \^\fB!\fP\^ by default. +It takes place in two parts. +The first is to determine which line from the previous history +to use during substitution. +The second is to select portions of that line for inclusion into +the current one. +The line selected from the previous history is the \fIevent\fP, +and the portions of that line that are acted upon are \fIwords\fP. +Various \fImodifiers\fP are available to manipulate the selected words. +The line is broken into words in the same fashion as when reading input, +so that several \fImetacharacter\fP-separated words surrounded by +quotes are considered as one word. +History expansions are introduced by the appearance of the +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 shell options settable with the +.B shopt +builtin may be used to tailor the behavior of history expansion. +If the +.B histverify +shell option is enabled (see the description of the +.B shopt +builtin), and +.B readline +is being used, history substitutions are not immediately passed to +the shell parser. +Instead, the expanded line is reloaded into the +.B readline +editing buffer for further modification. +If +.B readline +is being used, and the +.B histreedit +shell option is enabled, a failed history substitution will be reloaded +into the +.B readline +editing buffer for correction. +The +.B \-p +option to the +.B history +builtin command may be used to see what a history expansion will +do before using it. +The +.B \-s +option to the +.B history +builtin may be used to add commands to the end of the history list +without actually executing them, so that they are available for +subsequent recall. .PP The shell allows control of the various characters used by the history expansion mechanism (see the description of @@ -3238,9 +4171,6 @@ Start a history substitution, except when followed by a .BR blank , newline, = or (. .TP -.B !! -Refer to the previous command. This is a synonym for `!\-1'. -.TP .B !\fIn\fR Refer to command line .IR n . @@ -3249,6 +4179,9 @@ Refer to command line Refer to the current command line minus .IR n . .TP +.B !! +Refer to the previous command. This is a synonym for `!\-1'. +.TP .B !\fIstring\fR Refer to the most recent command starting with .IR string . @@ -3256,6 +4189,9 @@ Refer to the most recent command starting with .B !?\fIstring\fR\fB[?]\fR Refer to the most recent command containing .IR string . +The trailing \fB?\fP may be omitted if +.I string +is followed immediately by a newline. .TP .B \d\s+2^\s-2\u\fIstring1\fP\d\s+2^\s-2\u\fIstring2\fP\d\s+2^\s-2\u Quick substitution. Repeat the last command, replacing @@ -3271,17 +4207,20 @@ The entire command line typed so far. .PD .SS Word Designators .PP +Word designators are used to select desired words from the event. A .B : -separates the event specification from the word -designator. It can be omitted if the word designator begins with a +separates the event specification from the word designator. +It can be omitted if the word designator begins with a .BR ^ , .BR $ , .BR * , +.BR \- , or .BR % . Words are numbered from the beginning of the line, -with the first word being denoted by a 0 (zero). +with the first word being denoted by 0 (zero). +Words are inserted into the current line separated by single spaces. .PP .PD 0 .TP @@ -3317,16 +4256,22 @@ Abbreviates \fIx\-$\fP. .B x\- Abbreviates \fIx\-$\fP like \fBx*\fP, but omits the last word. .PD +.PP +If a word designator is supplied without an event specification, the +previous command is used as the event. .SS Modifiers .PP -After the optional word designator, you can add a sequence of one -or more of the following modifiers, each preceded by a `:'. +After the optional word designator, there may appear a sequence of +one or more of the following modifiers, each preceded by a `:'. .PP .PD 0 .PP .TP .B h -Remove a trailing pathname component, leaving only the head. +Remove a trailing file name component, leaving only the head. +.TP +.B t +Remove all leading file name components, leaving the tail. .TP .B r Remove a trailing suffix of the form \fI.xxx\fP, leaving the @@ -3335,9 +4280,6 @@ basename. .B e Remove all but the trailing suffix. .TP -.B t -Remove all leading pathname components, leaving the tail. -.TP .B p Print the new command but do not execute it. .TP @@ -3366,7 +4308,16 @@ with a single backslash. If & appears in .IR new , it is replaced by .IR old . -A single backslash will quote the &. +A single backslash will quote the &. If +.I old +is null, it is set to the last +.I old +substituted, or, if no previous history substitutions took place, +the last +.I string +in a +.B !?\fIstring\fR\fB[?]\fR +search. .TP .B & Repeat the previous substitution. @@ -3427,6 +4378,9 @@ logical AND .B || logical OR .TP +.B \fIexpr\fP?\fIexpr\fP:\fIexpr\fP +conditional evaluation +.TP .B = *= /= %= += \-= <<= >>= &= ^= |= assignment .PD @@ -3438,11 +4392,16 @@ an expression. A shell variable need not have its integer attribute turned on to be used in an expression. .PP Constants with a leading 0 are interpreted as octal numbers. -A leading \fI0x\fP or \fI0X\fP denotes hexadecimal. Otherwise, -numbers take the form [\fIbase#\fP]n, where \fIbase\fP is a -decimal number between 2 and 36 representing the arithmetic -base, and \fIn\fP is a number in that base. If \fIbase\fP is -omitted, then base 10 is used. +A leading 0x or 0X denotes hexadecimal. +Otherwise, numbers take the form [\fIbase#\fP]n, where \fIbase\fP +is a decimal number between 2 and 64 representing the arithmetic +base, and \fIn\fP is a number in that base. +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 interchangably to represent numbers between 10 +and 35. .PP Operators are evaluated in order of precedence. Sub-expressions in parentheses are evaluated first and may override the precedence @@ -3450,6 +4409,14 @@ rules above. .SH "SHELL BUILTIN COMMANDS" .\" start of bash_builtins .zZ +.PP +Unless otherwise noted, each builtin command documented in this +section as accepting options preceded by +.B \- +accepts +.B \-\- +to signify the end of the options. +.sp .5 .PD 0 .TP \fB:\fP [\fIarguments\fP] @@ -3472,7 +4439,7 @@ executed from .IR filename . If .I filename -does not contain a slash, pathnames in +does not contain a slash, file names in .SM .B PATH are used to find the directory containing @@ -3484,26 +4451,35 @@ need not be executable. The current directory is searched if no file is found in .SM .BR PATH . +If the +.B sourcepath +option to the +.B shopt +builtin command is turned off, the +.SM +.B PATH +is not searched. If any \fIarguments\fP are supplied, they become the positional -parameters when \fIfile\fP is executed. Otherwise the positional +parameters when \fIfilename\fP is executed. Otherwise the positional parameters are unchanged. The return status is the status of the last command exited within the script (0 if no commands are executed), and false if .I filename is not found. .TP -\fBalias\fP [\fIname\fP[=\fIvalue\fP] ...] -\fBAlias\fP with no arguments prints the list of aliases in the form -\fIname\fP=\fIvalue\fP on standard output. When arguments are -supplied, an alias is defined for -each \fIname\fP -whose \fIvalue\fP is given. A trailing space in -\fIvalue\fP causes the next -word to be checked for alias substitution when the alias is -expanded. For each \fIname\fP in the argument list for which -no \fIvalue\fP 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. +\fBalias\fP [\fB\-p\fP] [\fIname\fP[=\fIvalue\fP] ...] +\fBAlias\fP with no arguments or with the +.B \-p +option prints the list of aliases in the form +\fBalias\fP \fIname\fP=\fIvalue\fP on standard output. +When arguments are supplied, an alias is defined for +each \fIname\fP whose \fIvalue\fP is given. +A trailing space in \fIvalue\fP causes the next word to be +checked for alias substitution when the alias is expanded. +For each \fIname\fP in the argument list for which no \fIvalue\fP +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] Place \fIjobspec\fP in the background, as if it had been started with @@ -3517,11 +4493,11 @@ job control enabled, if \fIjobspec\fP was not found or started without job control. .TP .PD 0 -\fBbind\fP [\fB\-m\fP \fIkeymap\fP] [\fB\-lvd\fP] [\fB-q\fP \fIname\fP] +\fBbind\fP [\fB\-m\fP \fIkeymap\fP] [\fB\-lpsvPSV\fP] [\fB\-q\fP \fIname\fP] [\fB\-r\fP \fIkeyseq\fP] .TP -\fBbind\fP [\fB\-m\fP \fIkeymap\fP] \fB-f\fP \fIfilename\fP +\fBbind\fP [\fB\-m\fP \fIkeymap\fP] \fB\-f\fP \fIfilename\fP .TP -\fBbind\fP [\fB\-m\fP \fIkeymap\fP] \fIkeyseq\fP:\fIfunction-name\fP +\fBbind\fP [\fB\-m\fP \fIkeymap\fP] \fIkeyseq\fP:\fIfunction\-name\fP .PD Display current .B readline @@ -3530,7 +4506,7 @@ key and function bindings, or bind a key sequence to a function or macro. The binding syntax accepted is identical to that of .IR .inputrc , but each binding must be passed as a separate argument; -e.g., '"\eC-x\eC-r": re\-read\-init\-file'. Options, if supplied, have the +e.g., '"\eC\-x\eC\-r": re\-read\-init\-file'. Options, if supplied, have the following meanings: .RS .PD 0 @@ -3542,26 +4518,45 @@ as the keymap to be affected by the subsequent bindings. Acceptable .I keymap names are -\fIemacs, emacs-standard, emacs-meta, emacs-ctlx, vi, vi-move, -vi-command\fP, and -.IR vi-insert . -\fIvi\fP is equivalent to \fIvi-command\fP; \fIemacs\fP is -equivalent to \fIemacs-standard\fP. +\fIemacs, emacs\-standard, emacs\-meta, emacs\-ctlx, vi, +vi\-command\fP, and +.IR vi\-insert . +\fIvi\fP is equivalent to \fIvi\-command\fP; \fIemacs\fP is +equivalent to \fIemacs\-standard\fP. .TP .B \-l -List the names of all \fBreadline\fP functions +List the names of all \fBreadline\fP functions. +.TP +.B \-p +Display \fBreadline\fP function names and bindings in such a way +that they can be re-read. +.TP +.B \-P +List current \fBreadline\fP function names and bindings. .TP .B \-v -List current function names and bindings +Display \fBreadline\fP variable names and values in such a way that they +can be re-read. .TP -.B \-d -Dump function names and bindings in such a way that they can be re-read +.B \-V +List current \fBreadline\fP variable names and values. +.TP +.B \-s +Display \fBreadline\fP key sequences bound to macros and the strings +they output in such a way that they can be re-read. +.TP +.B \-S +Display \fBreadline\fP key sequences bound to macros and the strings +they output. .TP .B \-f \fIfilename\fP -Read key bindings from \fIfilename\fP +Read key bindings from \fIfilename\fP. .TP .B \-q \fIfunction\fP -Query about which keys invoke the named \fIfunction\fP +Query about which keys invoke the named \fIfunction\fP. +.TP +.B \-r \fIkeyseq\fP +Remove any current binding for \fIkeyseq\fP. .PD .PP The return value is 0 unless an unrecognized option is given or an @@ -3572,8 +4567,9 @@ error occurred. Exit from within a .BR for , .BR while , +.BR until , or -.B until +.B select loop. If \fIn\fP is specified, break \fIn\fP levels. .I n must be \(>= 1. If @@ -3596,7 +4592,7 @@ commonly redefined this way. The return status is false if .I shell\-builtin is not a shell builtin command. .TP -\fBcd\fP [\fIdir\fP] +\fBcd\fP [\fB\-LP\fP] [\fIdir\fP] Change the current directory to \fIdir\fP. The variable .SM .B HOME @@ -3606,21 +4602,30 @@ default The variable .SM .B CDPATH -defines the search path for -the directory containing +defines the search path for the directory containing .IR dir . -Alternative directory names are -separated by a colon (:). A null directory name in +Alternative directory names in +.SM +.B CDPATH +are separated by a colon (:). A null directory name in .SM .B CDPATH -is the same as -the current directory, i.e., ``\fB.\fP''. If +is the same as the current directory, i.e., ``\fB.\fP''. If .I dir begins with a slash (/), then .SM .B CDPATH -is not used. An argument of +is not used. The +.B \-P +option says to use the physical directory structure instead of +following symbolic links (see also the +.B \-P +option to the +.B set +builtin command); the +.B \-L +option forces symbolic links to be followed. An argument of .B \- is equivalent to .SM @@ -3628,7 +4633,7 @@ is equivalent to The return value is true if the directory was successfully changed; false otherwise. .TP -\fBcommand\fP [\fB-pVv\fP] \fIcommand\fP [\fIarg\fP ...] +\fBcommand\fP [\fB\-pVv\fP] \fIcommand\fP [\fIarg\fP ...] Run .I command with @@ -3652,15 +4657,12 @@ option is supplied, a description of .I command is printed. The .B \-v -option causes a single word indicating the command or pathname +option causes a single word indicating the command or file name used to invoke .I command to be printed; the .B \-V option produces a more verbose description. -An argument of -.B \-\- -disables option checking for the rest of the arguments. If the .B \-V or @@ -3679,8 +4681,9 @@ builtin is the exit status of Resume the next iteration of the enclosing .BR for , .BR while , +.BR until , or -.B until +.B select loop. If .I n @@ -3689,24 +4692,52 @@ is specified, resume at the \fIn\fPth enclosing loop. must be \(>= 1. If .I n is greater than the number of enclosing loops, the last enclosing loop -(the `top\-level' loop) is resumed. The return value is 0 unless the +(the ``top-level'' loop) is resumed. The return value is 0 unless the shell is not executing a loop when .B continue is executed. .TP .PD 0 -\fBdeclare\fP [\fB\-frxi\fP] [\fIname\fP[=\fIvalue\fP]] +\fBdeclare\fP [\fB\-afFirx\fP] [\fB\-p\fP] [\fIname\fP[=\fIvalue\fP]] .TP -\fBtypeset\fP [\fB\-frxi\fP] [\fIname\fP[=\fIvalue\fP]] +\fBtypeset\fP [\fB\-afFirx\fP] [\fB\-p\fP] [\fIname\fP[=\fIvalue\fP]] .PD -Declare variables and/or give them attributes. If no \fIname\fPs are -given, then display the values of variables instead. The options can -be used to restrict output to variables with the specified attribute. +Declare variables and/or give them attributes. +If no \fIname\fPs are given then display the values of variables. +The +.B \-p +option will display the attributes and values of each +.IR name . +When +.B \-p +is used, additional options are ignored. +The +.B \-F +option inhibits the display of function definitions; only the +function name and attributes are printed. +The +.B \-F +option implies +.BR \-f . +The following options can +be used to restrict output to variables with the specified attribute or +to give variables attributes: .RS .PD 0 .TP +.B \-a +Each \fIname\fP is an array variable (see +.B Arrays +above). +.TP .B \-f -Use function names only +Use function names only. +.TP +.B \-i +The variable is treated as an integer; arithmetic evaluation (see +.SM +.B "ARITHMETIC EVALUATION" ") " +is performed when the variable is assigned a value. .TP .B \-r Make \fIname\fPs readonly. These names cannot then be assigned values @@ -3714,50 +4745,63 @@ by subsequent assignment statements. .TP .B \-x Mark \fIname\fPs for export to subsequent commands via the environment. -.TP -.B \-i -The variable is treated as an integer; arithmetic evaluation (see -.SM -.B "ARITHMETIC EVALUATION" ") " -is performed when the variable is assigned a value. .PD .PP Using `+' instead of `\-' -turns off the attribute instead. When used in a function, makes -\fIname\fPs local, as with the +turns off the attribute instead, with the exception that \fB+a\fP +may not be used to destroy an array variable. When used in a function, +makes each +\fIname\fP local, as with the .B local command. The return value is 0 unless an illegal option is encountered, -an attempt is made to define a function using "-f foo=bar", -one of the \fInames\fP is not a legal shell variable name, +an attempt is made to define a function using "\-f foo=bar", +an attempt is made to assign a value to a readonly variable, +an attempt is made to assign a value to an array variable without +using the compound assignment syntax (see +.B Arrays +above), one of the \fInames\fP is not a legal shell variable name, an attempt is made to turn off readonly status for a readonly variable, -or an attempt is made to display a non-existant function with -f. +an attempt is made to turn off array status for an array variable, +or an attempt is made to display a non-existent function with \-f. .RE .TP -.B dirs [\fB-l\fP] [\fB+/\-n\fP] -Display the list of currently remembered directories. Directories -are added to the list with the +.B dirs [\fB\-clpv\fP] [+\fIn\fP] [\-\fIn\fP] +Without options, displays the list of currently remembered directories. +The default display is on a single line with directory names separated +by spaces. +Directories are added to the list with the .B pushd command; the .B popd -command moves back up through the list. +command removes entries from the list. .RS .PD 0 .TP -.B +n -displays the \fIn\fPth entry counting from the left of the list +\fB+\fP\fIn\fP +Displays the \fIn\fPth entry counting from the left of the list shown by .B dirs when invoked without options, starting with zero. .TP -.B \-n -displays the \fIn\fPth entry counting from the right of the list +\fB\-\fP\fIn\fP +Displays the \fIn\fPth entry counting from the right of the list shown by .B dirs when invoked without options, starting with zero. .TP +.B \-c +Clears the directory stack by deleting all of the entries. +.TP .B \-l -produces a longer listing; the default listing format uses a +Produces a longer listing; the default listing format uses a tilde to denote the home directory. +.TP +.B \-p +Print the directory stack with one entry per line. +.TP +.B \-v +Print the directory stack with one entry per line, +prefixing each entry with its index in the stack. .PD .PP The return value is 0 unless an @@ -3765,14 +4809,39 @@ illegal option is supplied or \fIn\fP indexes beyond the end of the directory stack. .RE .TP +\fBdisown\fP [\fB\-h\fP] [\fIjobspec\fP ...] +Without options, each +.I jobspec +is removed from the table of active jobs. +If the \fB\-h\fP option is given, the job is not removed from the table, +but is marked so that +.SM +.B SIGHUP +is not sent to the job if the shell receives a +.SM +.BR SIGHUP . +If no +.I jobspec +is present, the \fIcurrent job\fP is used. The return value is +0 unless a +.I jobspec +does not specify a valid job. +.TP \fBecho\fP [\fB\-neE\fP] [\fIarg\fP ...] -Output the \fIarg\fPs, separated by spaces. The return status is -always 0. If \fB\-n\fP is specified, the trailing newline is +Output the \fIarg\fPs, separated by spaces, followed by a newline. +The return status is always 0. +If \fB\-n\fP is specified, the trailing newline is suppressed. If the \fB\-e\fP option is given, interpretation of the following backslash-escaped characters is enabled. The .B \-E option disables the interpretation of these escape characters, even on systems where they are interpreted by default. +.B echo +does not interpret +.B \-\- +to mean the end of options. +.B echo +interprets the following escape sequences: .RS .PD 0 .TP @@ -3785,6 +4854,9 @@ backspace .B \ec suppress trailing newline .TP +.B \ee +an escape character +.TP .B \ef form feed .TP @@ -3808,10 +4880,10 @@ the character whose ASCII code is \fInnn\fP (octal) .PD .RE .TP -\fBenable\fP [\fB\-n\fP] [\fB\-all\fP] [\fIname\fP ...] +\fBenable\fP [\fB\-adnps\fP] [\fB\-f\fP \fIfilename\fP] [\fIname\fP ...] Enable and disable builtin shell commands. This allows the execution of a disk command which has the same name as a shell -builtin without specifying a full pathname. +builtin without specifying a full file name. If \fB\-n\fP is used, each \fIname\fP is disabled; otherwise, \fInames\fP are enabled. For example, to use the @@ -3819,49 +4891,73 @@ is disabled; otherwise, binary found via the .SM .B PATH -instead of the shell builtin version, type -``enable -n test''. If no arguments are given, -a list of all enabled shell builtins is printed. -If only \fB\-n\fP is supplied, a list of all disabled -builtins is printed. If only \fB\-all\fP is supplied, -the list printed includes all builtins, with an +instead of the shell builtin version, run +\f(CWenable -n test\fP. +The +.B \-f +option means to load the new builtin command +.I name +from shared object +.IR filename , +on systems that support dynamic loading. The +.B \-d +option will delete a builtin previously loaded with +.BR \-f . +If no \fIname\fP arguments are given, or if the +.B \-p +option is supplied, a list of shell builtins is printed. +With no other option arguments, the list consists of all enabled +shell builtins. +If \fB\-n\fP is supplied, only disabled builtins are printed. +If \fB\-a\fP is supplied, the list printed includes all builtins, with an indication of whether or not each is enabled. -.B enable -accepts -.B \-a -as a synonym for -.BR \-all . +If \fB\-s\fP is supplied, the output is restricted to the POSIX +\fIspecial\fP builtins. The return value is 0 unless a .I name -is not a shell builtin. +is not a shell builtin or there is a problem loading a new builtin +from a shared object. .TP \fBeval\fP [\fIarg\fP ...] The \fIarg\fPs are read and concatenated together into a single command. This command is then read and executed by the shell, and -its exit status is returned as the value of the -.B eval -command. If there are no +its exit status is returned as the value of +.BR eval . +If there are no .IR args , or only null arguments, .B eval -returns true. +returns 0. .TP -\fBexec\fP [[\fB\-\fP] \fIcommand\fP [\fIarguments\fP]] +\fBexec\fP [\fB\-cl\fP] [\fB\-a\fP \fIname\fP] [\fIcommand\fP] [\fIarguments\fP] If .I command is specified, it replaces the shell. No new process is created. The .I arguments become the arguments to \fIcommand\fP. -If the first argument is -.BR \- , +If the +.B \-l +option is supplied, the shell places a dash in the zeroth arg passed to .IR command . -This is what login does. If the file +This is what +.IR login (1) +does. The +.B \-c +option causes +.I command +to be executed with an empty environment. If +.B \-a +is supplied, the shell passes +.I name +as the zeroth argument to the executed command. If +.I command cannot be executed for some reason, a non-interactive shell exits, -unless the shell variable \fBno_exit_on_failed_exec\fP exists, in -which case it returns failure. An interactive shell returns failure -if the file cannot be executed. +unless the shell option +.B execfail +is enabled, in which case it returns failure. +An interactive shell returns failure if the file cannot be executed. If .I command is not specified, any redirections take effect in the current shell, @@ -3879,7 +4975,7 @@ A trap on is executed before the shell terminates. .TP .PD 0 -\fBexport\fP [\fB\-nf\fP\^] [\fIname\fP[=\fIword\fP]] ... +\fBexport\fP [\fB\-fn\fP\^] [\fIname\fP[=\fIword\fP]] ... .TP .B export \-p .PD @@ -3901,9 +4997,7 @@ of all names that are exported in this shell is printed. The .B \-n option causes the export property to be removed from the -named variables. An argument of -.B \-\- -disables option checking for the rest of the arguments. +named variables. .B export returns an exit status of 0 unless an illegal option is encountered, @@ -3975,9 +5069,18 @@ echoed and executed. .sp 1 In the second form, \fIcommand\fP is re-executed after each instance of \fIpat\fP is replaced by \fIrep\fP. -A useful alias to use with this is ``r=fc \-s'', -so that typing ``r cc'' -runs the last command beginning with ``cc'' and typing ``r'' +A useful alias to use with this is +.if n ``r=fc -s'', +.if t \f(CWr='fc \-s'\fP, +so that typing +.if n ``r cc'' +.if t \f(CWr cc\fP +runs the last command beginning with +.if n ``cc'' +.if t \f(CWcc\fP +and typing +.if n ``r'' +.if t \f(CWr\fP re-executes the last command. .sp 1 If the first form is used, the return value is 0 unless an illegal @@ -4105,19 +5208,24 @@ returns true if an option, specified or unspecified, is found. It returns false if the end of options is encountered or an error occurs. .TP -\fBhash\fP [\fB\-r\fP] [\fIname\fP] +\fBhash\fP [\fB\-r\fP] [\fB\-p\fP \fIfilename\fP] [\fIname\fP] For each .IR name , -the full pathname of the command is determined -and remembered. The +the full file name of the command is determined by searching +the directories in +.B $PATH +and remembered. +If the +.B \-p +option is supplied, no path search is performed, and +.I filename +is used as the full file name of the command. +The .B \-r option causes the shell to forget all remembered locations. If no arguments are given, information about remembered commands is printed. -An argument of -.B \-\- -disables option checking for the rest of the arguments. The return -status is true unless a +The return status is true unless a .I name is not found or an illegal option is supplied. .TP @@ -4128,16 +5236,18 @@ is specified, .B help gives detailed help on all commands matching .IR pattern ; -otherwise a list of the builtins is printed. The return status is 0 -unless no command matches +otherwise help for all the builtins and shell control structures +is printed. The return status is 0 unless no command matches .IR pattern . .TP .PD 0 -\fBhistory\fP [\fIn\fP] +\fBhistory\fP [\fB\-c\fP] [\fIn\fP] +.TP +\fBhistory\fP \fB\-anrw\fP [\fIfilename\fP] .TP -\fBhistory\fP \fB\-rwan\fP [\fIfilename\fP] -.\".TP -.\"\fBhistory\fP \fB\-s\fP \fIargs\fP +\fBhistory\fP \fB\-p\fP \fIarg\fP [\fIarg ...\fP] +.TP +\fBhistory\fP \fB\-s\fP \fIarg\fP [\fIarg ...\fP] .PD With no options, display the command history list with line numbers. Lines listed @@ -4147,7 +5257,7 @@ have been modified. An argument of .I n lists only the last .I n -lines. If a non-option argument 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 @@ -4157,7 +5267,7 @@ is used. Options, if supplied, have the following meanings: .TP .B \-a Append the ``new'' history lines (history lines entered since the -beginning of the current \fBbash\fP session) to the history file +beginning of the current \fBbash\fP session) to the history file. .TP .B \-n Read the history lines not already read from the history @@ -4167,16 +5277,28 @@ current \fBbash\fP session. .TP .B \-r Read the contents of the history file -and use them as the current history +and use them as the current history. .TP .B \-w Write the current history to the history file, overwriting the history file's contents. -.\".TP -.\".B \-s -.\"perform history -.\"substitution on the following \fIargs\fP and display -.\"the result on the standard output. +.TP +.B \-c +Clear the history list by deleting all the entries. +.TP +.B \-p +Perform history substitution on the following \fIargs\fP and display +the result on the standard output. +Does not store the results in the history list. +Each \fIarg\fP must be quoted to disable normal history expansion. +.TP +.B \-s +Store the +.I args +in the history list as a single entry. The last command in the +history list is removed before the +.I args +are added. .PD .PP The return value is 0 unless an illegal option is encountered or an @@ -4184,27 +5306,42 @@ error occurs while reading or writing the history file. .RE .TP .PD 0 -\fBjobs\fP [\fB\-lnp\fP] [ \fIjobspec\fP ... ] +\fBjobs\fP [\fB\-lnprs\fP] [ \fIjobspec\fP ... ] .TP \fBjobs\fP \fB\-x\fP \fIcommand\fP [ \fIargs\fP ... ] .PD -The first form lists the active jobs. The +The first form lists the active jobs. The options have the following +meanings: +.RS +.PD 0 +.TP .B \-l -option lists process IDs -in addition to the normal information; the +List process IDs +in addition to the normal information. +.TP .B \-p -option lists only the process ID of the job's process group -leader. The +List only the process ID of the job's process group +leader. +.TP .B \-n -option displays only jobs that have changed status since -last notified. If +Display information only about jobs that have changed status since +the user was last notified of their status. +.TP +.B \-r +Restrict output to running jobs. +.TP +.B \-s +Restrict output to stopped jobs. +.PD +.PP +If .I jobspec is given, output is restricted to information about that job. The return status is 0 unless an illegal option is encountered or an illegal .I jobspec is supplied. -.sp 1 +.PP If the .B \-x option is supplied, @@ -4220,14 +5357,17 @@ with the corresponding process group ID, and executes passing it .IR args , returning its exit status. +.RE .TP .PD 0 -\fBkill\fP [\fB-s sigspec\fP | \fB\-sigspec\fP] [\fIpid\fP | \fIjobspec\fP] ... +\fBkill\fP [\fB\-s\fP \fIsigspec\fP | \fB\-n\fP \fIsignum\fP | \fB\-\fP\fIsigspec\fP] [\fIpid\fP | \fIjobspec\fP] ... .TP -\fBkill\fP \fB\-l\fP [\fIsignum\fP] +\fBkill\fP \fB\-l\fP [\fIsignum\fP | \fIsigspec\fP] .PD Send the signal named by .I sigspec +or +.I signum to the processes named by .I pid or @@ -4236,9 +5376,11 @@ or is either a signal name such as .SM .B SIGKILL -or a signal number. If +or a signal number; +.I signum +is a signal number. If .I sigspec -is a signal name, the name is case insensitive and may be +is a signal name, the name may be given with or without the .SM .B SIG @@ -4253,10 +5395,10 @@ is assumed. An argument of lists the signal names. If any arguments are supplied when .B \-l is given, the names of the specified signals are listed, and -the return status is 0. -An argument of -.B \-\- -disables option checking for the rest of the arguments. +the return status is 0. The arguments to +.B \-l +may be either signal names or signal numbers; if signal names +are given, the corresponding signal number is displayed. .B kill returns true if at least one signal was successfully sent, or false if an error occurs or an illegal option is encountered. @@ -4297,27 +5439,32 @@ is supplied. .B logout Exit a login shell. .TP -\fBpopd\fP [\fB+/\-n\fP] +\fBpopd\fP [\-\fBn\fP] [+\fIn\fP] [\-\fIn\fP] Removes entries from the directory stack. With no arguments, removes the top directory from the stack, and performs a .B cd to the new top directory. +Arguments, if supplied, have the following meanings: .RS .PD 0 .TP -.B +n -removes the \fIn\fPth entry counting from the left of the list +\fB+\fP\fIn\fP +Removes the \fIn\fPth entry counting from the left of the list shown by .BR dirs , starting with zero. For example: ``popd +0'' removes the first directory, ``popd +1'' the second. .TP -.B \-n -removes the \fIn\fPth entry counting from the right of the list +\fB\-\fP\fIn\fP +Removes the \fIn\fPth entry counting from the right of the list shown by .BR dirs , starting with zero. For example: ``popd -0'' removes the last directory, ``popd -1'' the next to last. +.TP +.B \-n +Suppresses the normal change of directory when removing directories +from the stack, so that only the stack is manipulated. .PD .PP If the @@ -4332,29 +5479,34 @@ directory change fails. .RE .TP .PD 0 -\fBpushd\fP [\fIdir\fP] +\fBpushd\fP [\fB\-n\fP] [\fIdir\fP] .TP -\fBpushd\fP \fB+/\-n\fP +\fBpushd\fP [\fB\-n\fP] [+\fIn\fP] [\-\fIn\fP] .PD Adds a directory to the top of the directory stack, or rotates the stack, making the new top of the stack the current working directory. With no arguments, exchanges the top two directories and returns 0, unless the directory stack is empty. +Arguments, if supplied, have the following meanings: .RS .PD 0 .TP -.B +n +\fB+\fP\fIn\fP Rotates the stack so that the \fIn\fPth directory (counting from the left of the list shown by .BR dirs ) is at the top. .TP -.B \-n +\fB\-\fP\fIn\fP Rotates the stack so that the \fIn\fPth directory (counting from the right) is at the top. .TP +.B \-n +Suppresses the normal change of directory when adding directories +to the stack, so that only the stack is manipulated. +.TP .B dir -adds +Adds .I dir to the directory stack at the top, making it the new current working directory. @@ -4372,26 +5524,27 @@ returns 0 unless the cd to fails. With the second form, .B pushd returns 0 unless the directory stack is empty, -a non-existant directory stack element is specified, +a non-existent directory stack element is specified, or the directory change to the specified new current directory fails. .RE .TP -\fBpwd\fP -Print the absolute pathname of the current working directory. -The path printed contains no symbolic links if the +\fBpwd\fP [\fB\-LP\fP] +Print the absolute file name of the current working directory. +The file name printed contains no symbolic links if the .B \-P +option is supplied or the +.B \-o physical option to the .B set -builtin command is set. -See also the description of -.B nolinks -under -.B Shell Variables -above). The return status is 0 unless an error occurs while -reading the pathname of the current directory. +builtin command is enabled. +If the +.B \-L +option is used, symbolic links are followed. +The return status is 0 unless an error occurs while +reading the name of the current directory. .TP -\fBread\fP [\fB\-r\fP] [\fIname\fP ...] +\fBread\fP [\fB\-er\fP] [\fB\-a\fP \fIaname\fP] [\fB\-p\fP \fIprompt\fP] [\fIname\fP ...] One line is read from the standard input, and the first word is assigned to the first .IR name , @@ -4399,43 +5552,72 @@ the second word to the second .IR name , and so on, with leftover words assigned to the last .IR name . -Only the -characters in +Only the characters in .SM .B IFS -are recognized as word delimiters. If no +are recognized as word delimiters. Options, if supplied, have the +following meanings: +.RS +.PD 0 +.TP +.B \-r +A backslash-newline pair is not ignored, and +the backslash is considered to be part of the line. +.TP +.B \-p +Display \fIprompt\fP, without a +trailing newline, before attempting to read any input. The prompt +is displayed only if input is coming from a terminal. +.TP +.B \-a +The words are assigned to sequential indices +of the array variable +.IR aname , +starting at 0. +.I aname +is unset before any new values are assigned. +.TP +.B \-e +If the standard input +is coming from a terminal, +.B readline +(see +.SM +.B READLINE +above) is used to obtain the line. +.PD +.PP +If no .I names are supplied, the line read is assigned to the variable .SM .BR REPLY . -The return code is zero, unless end-of-file is encountered. If the -.B \-r -option -is given, a backslash-newline pair is not ignored, and -the backslash is considered to be part of the line. -.TP -.PD 0 -\fBreadonly\fP [\fB\-f\fP] [\fIname\fP ...] +The return code is zero, unless end-of-file is encountered. +.RE .TP -\fBreadonly -p\fP +\fBreadonly\fP [\fB\-apf\fP] [\fIname\fP ...] .PD The given -\fInames\fP are marked readonly and the values of these -\fInames\fP +\fInames\fP are marked readonly; the values of these +.I names may not be changed by subsequent assignment. If the .B \-f option is supplied, the functions corresponding to the \fInames\fP are so -marked. If no arguments are given, or if the +marked. +The +.B \-a +option restricts the variables to arrays. +If no +.I name +arguments are given, or if the .B \-p -option is supplied, a list of all readonly names -is printed. -An argument of -.B \-\- -disables option checking for the rest of the arguments. The -return status is 0 unless an illegal option is encountered, -one of the \fInames\fP is not a legal shell variable name, or +option is supplied, a list of all readonly names is printed. +The return status is 0 unless an illegal option is encountered, +one of the +.I names +is not a legal shell variable name, or .B \-f is supplied with a .I name @@ -4458,7 +5640,17 @@ script as the exit status of the script. If used outside a function and not during execution of a script by \fB.\fP\^, the return status is false. .TP -\fBset\fP [\fB\-\-abefhkmnptuvxldCHP\fP] [\fB-o\fP \fIoption\fP] [\fIarg\fP ...] +\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 re-used as input. +When options are specified, they set or unset shell attributes. +Any arguments remaining after the options are processed are treated +as values for the positional parameters and are assigned, in order, to +.BR $1 , +.BR $2 , +.B ... +.BR $\fIn\fP . +Options, if specified, have the following meanings: .RS .PD 0 .TP 8 @@ -4467,19 +5659,15 @@ Automatically mark variables which are modified or created for export to the environment of subsequent commands. .TP 8 .B \-b -Cause the status of terminated background jobs to be reported -immediately, rather than before the next primary prompt. -(Also see -.B notify -under -.B Shell Variables -above). +Report the status of terminated background jobs +immediately, rather than before the next primary prompt. This is +effective only when job control is enabled. .TP 8 .B \-e -Exit immediately if a \fIsimple-command\fP (see +Exit immediately if a \fIsimple command\fP (see .SM .B SHELL GRAMMAR -above) exits with a non\-zero status. The shell does not exit if the +above) exits with a non-zero status. The shell does not exit if the command that fails is part of an .I until or @@ -4490,7 +5678,7 @@ part of an statement, part of a .B && or -.B \(bv\|\(bv +.B \(bv\(bv list, or if the command's return value is being inverted via .BR ! . @@ -4499,13 +5687,13 @@ being inverted via Disable pathname expansion. .TP 8 .B \-h -Locate and remember function commands as functions are -defined. Function commands are normally looked up when -the function is executed. +Remember the location of commands as they are looked up for execution. +This is on by default. .TP 8 .B \-k -All keyword arguments are placed in the environment for a -command, not just those that precede the command name. +All arguments in the form of assignment statements +are placed in the environment for a command, not just +those that precede the command name. .TP 8 .B \-m Monitor mode. Job control is enabled. This flag is on @@ -4519,11 +5707,11 @@ upon their completion. .TP 8 .B \-n Read commands but do not execute them. This may be used to -check a shell script for syntax errors. This is ignored for +check a shell script for syntax errors. This is ignored by interactive shells. .TP 8 -.B \-o \fIoption-name\fP -The \fIoption-name\fP can be one of the following: +.B \-o \fIoption\-name\fP +The \fIoption\-name\fP can be one of the following: .RS .TP 8 .B allexport @@ -4531,39 +5719,43 @@ Same as .BR \-a . .TP 8 .B braceexpand -The shell performs brace expansion (see -.B Brace Expansion -above). This is on by default. +Same as +.BR \-B . .TP 8 .B emacs Use an emacs-style command line editing interface. This is enabled by default when the shell is interactive, unless the shell is started with the -.B \-nolineediting +.B \-\-noediting option. .TP 8 .B errexit Same as .BR \-e . .TP 8 +.B hashall +Same as +.BR \-h . +.TP 8 .B histexpand Same as .BR \-H . .TP 8 +.B history +Enable command history, as described above under +.SM +.BR HISTORY . +This option is on by default in interactive shells. +.TP 8 .B ignoreeof -The effect is as if the shell command `IGNOREEOF=10' had been executed +The effect is as if the shell command \f(CWIGNOREEOF=10\fP had been executed (see .B Shell Variables above). .TP 8 -.B interactive\-comments -Allow a word beginning with -.B # -to cause that word and all remaining characters on that -line to be ignored in an interactive shell (see -.SM -.B COMMENTS -above). +.B keyword +Same as +.BR \-k . .TP 8 .B monitor Same as @@ -4581,10 +5773,6 @@ Same as Same as .BR \-f . .TP 8 -.B nohash -Same as -.BR \-d . -.TP 8 .B notify Same as .BR \-b . @@ -4593,13 +5781,19 @@ Same as Same as .BR \-u . .TP 8 +.B onecmd +Same as +.BR \-t . +.TP 8 .B physical Same as .BR \-P . .TP 8 .B posix -Change the behavior of bash where the default operation differs -from the Posix 1003.2 standard to match the standard. +Change the behavior of +.B bash +where the default operation differs +from the POSIX 1003.2 standard to match the standard. .TP 8 .B privileged Same as @@ -4615,9 +5809,18 @@ Use a vi-style command line editing interface. .B xtrace Same as .BR \-x . +.sp .5 .PP -If no \fIoption-name\fP is supplied, the values of the current options are +If +.B \-o +is supplied with no \fIoption\-name\fP, the values of the current options are printed. +If +.B +o +is supplied with no \fIoption\-name\fP, a series of +.B set +commands to recreate the current option settings is displayed on +the standard output. .RE .TP 8 .B \-p @@ -4638,37 +5841,36 @@ Exit after reading and executing one command. Treat unset variables as an error when performing parameter expansion. If expansion is attempted on an unset variable, the shell prints an error message, and, -if not interactive, exits with a non\-zero status. +if not interactive, exits with a non-zero status. .TP 8 .B \-v Print shell input lines as they are read. .TP 8 .B \-x -After expanding each -.IR simple-command , -.B bash -displays the expanded value of +After expanding each \fIsimple command\fP, +display the expanded value of .SM .BR PS4 , followed by the command and its expanded arguments. .TP 8 -.B \-l -Save and restore the binding of \fIname\fP in a -\fBfor\fP \fIname\fP [in \fBword\fP] command (see -.SM -.B SHELL GRAMMAR -above). -.TP 8 -.B \-d -Disable the hashing of commands that are looked up for execution. -Normally, commands are remembered in a hash table, and once -found, do not have to be looked up again. +.B \-B +The shell performs brace expansion (see +.B Brace Expansion +above). This is on by default. .TP 8 .B \-C -The effect is as if the shell command `noclobber=' had been executed -(see -.B Shell Variables -above). +If set, +.B bash +does not overwrite an existing file with the +.BR > , +.BR >& , +and +.B <> +redirection operators. This may be overridden when +creating output files by using the redirection operator +.B >| +instead of +.BR > . .TP 8 .B \-H Enable @@ -4677,10 +5879,14 @@ style history substitution. This flag is on by default when the shell is interactive. .TP 8 .B \-P -If set, do not follow symbolic links when performing commands such as +If set, the shell does not follow symbolic links when executing +commands such as .B cd -which change the current directory. The physical directory is -used instead. +that change the current working directory. It uses the +physical directory structure instead. By default, +.B bash +follows the logical chain of directories when performing commands +which change the current directory. .TP 8 .B \-\- If no arguments follow this flag, then the positional parameters are @@ -4707,16 +5913,7 @@ flags can also be specified as options to an invocation of the shell. The current set of flags may be found in .BR $\- . -After the option arguments are processed, -the remaining \fIn\fP \fIarg\fPs are treated -as values for the positional -parameters and are assigned, in order, to -.BR $1 , -.BR $2 , -.B ... -.BR $\fIn\fP . -If no options or \fIarg\fPs are supplied, -all shell variables are printed. The return status is always true +The return status is always true unless an illegal option is encountered. .RE .TP @@ -4726,22 +5923,213 @@ The positional parameters from \fIn\fP+1 ... are renamed to .B .... Parameters represented by the numbers \fB$#\fP down to \fB$#\fP\-\fIn\fP+1 are unset. +.I n +must be a non-negative number less than or equal to \fB$#\fP. If .I n is 0, no parameters are changed. If .I n is not given, it is assumed to be 1. -.I n -must be a non-negative number less than or equal to \fB$#\fP. If .I n is greater than \fB$#\fP, the positional parameters are not changed. -The return status is greater than 0 if +The return status is greater than zero if .I n is greater than .B $# -or less than 0; otherwise 0. +or less than zero; otherwise 0. +.TP +\fBshopt\fP [\fB\-pqsu\fP] [\fB\-o\fP] [\fIoptname\fP ...] +Toggle the values of variables controlling optional shell behavior. +With no options, or with the +.B \-p +option, a list of all settable options is displayed, with +an indication of whether or not each is set. Other options have +the following meanings: +.RS +.PD 0 +.TP +.B \-s +Enable (set) each \fIoptname\fP. +.TP +.B \-u +Disable (unset) each \fIoptname\fP. +.TP +.B \-q +Suppresses normal output (quiet mode); the return status indicates +whether the \fIoptname\fP is set or unset. +If multiple \fIoptname\fP arguments are given with +.BR \-q , +the return status is zero if all \fIoptnames\fP are enabled; non-zero +otherwise. +.TP +.B \-o +Restricts the values of \fIoptname\fP to be those defined for the +.B \-o +option to the +.B set +builtin. +.PD +.PP +If either +.B \-s +or +.B \-u +is used with no \fIoptname\fP arguments, the display is limited to +those options which are set or unset, respectively. +Unless otherwise noted, the \fBshopt\fP options are disabled (unset) +by default. +.PP +The return status when listing options is zero if all \fIoptnames\fP +are enabled, non-zero otherwise. When setting or unsetting options, +the return status is zero unless an \fIoptname\fP is not a legal shell +option. +.PP +The list of \fBshopt\fP options is: +.if t .sp .5v +.if n .sp 1v +.PD 0 +.TP 8 +.B cdable_vars +If set, an argument to the +.B cd +builtin command that +is not a directory is assumed to be the name of a variable whose +value is the directory to change to. +.TP 8 +.B cdspell +If set, minor errors in the spelling of a directory component in a +.B cd +command will be corrected. +The errors checked for are transposed characters, +a missing character, and one character too many. +If a correction is found, the corrected file name is printed, +and the command proceeds. +This option is enabled by default, but is only used by interactive shells. +.TP 8 +.B checkhash +If set, \fBbash\fP checks that a command found in the hash +table exists before trying to execute it. If a hashed command no +longer exists, a normal path search is performed. +.TP 8 +.B checkwinsize +If set, \fBbash\fP checks the window size after each command +and, if necessary, updates the values of +.SM +.B LINES +and +.SM +.BR COLUMNS . +.TP 8 +.B cmdhist +If set, +.B bash +attempts to save all lines of a multiple-line +command in the same history entry. This allows +easy re-editing of multi-line commands. +.TP 8 +.B dotglob +If set, +.B bash +includes filenames beginning with a `.' in the results of pathname +expansion. +.TP 8 +.B execfail +If set, a non-interactive shell will not exit if +it cannot execute the file specified as an argument to the +.B exec +builtin command. An interactive shell does not exit if +.B exec +fails. +.TP 8 +.B expand_aliases +If set, aliases are expanded as described above under +.SM +.BR ALIASES . +This option is enabled by default for interactive shells. +.TP 8 +.B histappend +If set, the history list is appended to the file named by the value +of the +.B HISTFILE +variable when the shell exits, rather than overwriting the file. +.TP 8 +.B histreedit +If set, and +.B readline +is being used, a user is given the opportunity to re-edit a +failed history substitution. +.TP 8 +.B histverify +If set, and +.B readline +is being used, the results of history substitution are not immediately +passed to the shell parser. Instead, the resulting line is loaded into +the \fBreadline\fP editing buffer, allowing further modification. +.TP 8 +.B hostcomplete +If set, and +.B readline +is being used, bash will attempt to perform hostname completion when a +word beginning with \fB@\fP is being completed (see +.B Completing +under +.SM +.B READLINE +above). +This is enabled by default. +.TP 8 +.B interactive_comments +If set, allow a word beginning with +.B # +to cause that word and all remaining characters on that +line to be ignored in an interactive shell (see +.SM +.B COMMENTS +above). This option is enabled by default. +.TP 8 +.B lithist +If set, and the +.B cmdhist +option is enabled, multi-line commands are saved to the history with +embedded newlines rather than using semicolon separators where possible. +.TP 8 +.B mailwarn +If set, and a file that \fBbash\fP is checking for mail has been +accessed since the last time it was checked, the message ``The mail in +\fImailfile\fP has been read'' is displayed. +.TP 8 +.B nullglob +If set, +.B bash +allows patterns which match no +files (see +.B Pathname Expansion +above) +to expand to a null string, rather than themselves. +.TP 8 +.B promptvars +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. +.TP 8 +.B shift_verbose +If set, the +.B shift +builtin prints an error message when the shift count exceeds the +number of positional parameters. +.TP 8 +.B sourcepath +If set, the +\fBsource\fP (\fB.\fP) builtin uses the value of +.SM +.B PATH +to find the directory containing the file supplied as an argument. +This is enabled by default. +.RE .TP \fBsuspend\fP [\fB\-f\fP] Suspend the execution of this shell until it receives a @@ -4759,7 +6147,7 @@ is not supplied, or if job control is not enabled. \fBtest\fP \fIexpr\fP .TP \fB[\fP \fIexpr\fP \fB]\fP -Return a status of 0 (true) or 1 (false) depending on +Return a status of 0 or 1 depending on the evaluation of the conditional expression .IR expr . Expressions may be unary or binary. Unary @@ -4767,15 +6155,15 @@ expressions are often used to examine the status of a file. There are string operators and numeric comparison operators as well. Each operator and operand must be a separate argument. If \fIfile\fP is of the form /dev/fd/\fIn\fP, then file descriptor \fIn\fP is -checked. +checked. Expressions are composed of the following primaries: .RS .PD 0 .TP .B \-b \fIfile\fP -True if \fIfile\fP exists and is block special. +True if \fIfile\fP exists and is a block special file. .TP .B \-c \fIfile\fP -True if \fIfile\fP exists and is character special. +True if \fIfile\fP exists and is a character special file. .TP .B \-d \fIfile\fP True if \fIfile\fP exists and is a directory. @@ -4832,12 +6220,22 @@ True if \fIfile1\fP is newer (according to modification date) than \fIfile2\fP. .TP \fIfile1\fP \-\fBot\fP \fIfile2\fP -True if \fIfile1\fP is older than file2. +True if \fIfile1\fP is older than \fIfile2\fP. .TP -\fIfile1\fP \fB\-ef\fP \fIfile\fP +\fIfile1\fP \fB\-ef\fP \fIfile2\fP True if \fIfile1\fP and \fIfile2\fP have the same device and inode numbers. .TP +.B \-o \fIoptname\fP +True if shell option +.I optname +is enabled. +See the list of options under the description of the +.B \-o +option to the +.B set +builtin above. +.TP .B \-z \fIstring\fP True if the length of \fIstring\fP is zero. .TP @@ -4846,14 +6244,21 @@ True if the length of \fIstring\fP is zero. \fIstring\fP True if the length of .I string -is non\-zero. +is non-zero. .TP \fIstring1\fP \fB=\fP \fIstring2\fP -True if the strings are equal. +True if the strings are equal. \fB==\fP may be used in place of +\fB=\fP. .TP \fIstring1\fP \fB!=\fP \fIstring2\fP True if the strings are not equal. .TP +\fIstring1\fP \fB<\fP \fIstring2\fP +True if \fIstring1\fP sorts before \fIstring2\fP lexicographically. +.TP +\fIstring1\fP \fB>\fP \fIstring2\fP +True if \fIstring1\fP sorts after \fIstring2\fP lexicographically. +.TP .B ! \fIexpr\fP True if .I expr @@ -4873,7 +6278,7 @@ OR .I expr2 is true. .TP -.I arg1 \fBOP\fP arg2 +.I \fIarg1\fP \fBOP\fP \fIarg2\fP .SM .B OP is one of @@ -4885,16 +6290,12 @@ is one of or .BR \-ge . These arithmetic binary operators return true if \fIarg1\fP -is equal, not-equal, less-than, less-than-or-equal, -greater-than, or greater-than-or-equal than \fIarg2\fP, -respectively. +is equal to, not equal to, less than, less than or equal to, +greater than, or greater than or equal to \fIarg2\fP, respectively. .I Arg1 and .I arg2 -may be positive integers, negative integers, or the special -expression \fB\-l\fP \fIstring\fP, which evaluates to the -length of -.IR string . +may be positive or negative integers. .PD .RE .TP @@ -4902,7 +6303,7 @@ length of 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\-l\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 @@ -4919,31 +6320,48 @@ upon entrance to the shell). If is the null string this signal is ignored by the shell and by the commands it invokes. +If +.I arg +is +.B \-p +then the trap commands associated with +each +.I sigspec +are displayed. If no arguments are supplied or if +only +.B \-p +is given, +.B trap +prints the list of commands associated with each signal number. .I sigspec is either -a signal name defined in <\fIsignal.h\fP>, or a signal number. -If +a signal name defined in <\fIsignal.h\fP>, or a signal number. If .I sigspec is .SM .B EXIT (0) the command .I arg -is executed on exit from -the shell. With no arguments, -.B trap -prints the list of commands associated with each signal number. -The +is executed on exit from the shell. If +.I sigspec +is +.SM +.BR DEBUG , +the command +.I arg +is executed after every \fIsimple command\fP (see +.SM +.B SHELL GRAMMAR +above). +The .B \-l -option causes the shell to -print a list of signal names and their corresponding -numbers. An argument of -.B \-\- -disables option checking for the rest of the arguments. +option causes the shell to print a list of signal names and +their corresponding numbers. Signals ignored upon entry to the shell cannot be trapped or reset. Trapped signals are reset to their original values in a child -process when it is created. The return status is false if either -the trap name or number is invalid; otherwise +process when it is created. The return status is false if any +.I sigspec +is invalid; otherwise .B trap returns true. .TP @@ -4956,7 +6374,7 @@ If the .B \-type flag is used, .B type -prints a phrase which is one of +prints a string which is one of .IR alias , .IR keyword , .IR function , @@ -4966,8 +6384,11 @@ or if .I name is an alias, shell reserved word, function, builtin, or disk file, -respectively. If the name is not found, then nothing is printed, -and an exit status of false is returned. +respectively. +If the +.I name +is not found, then nothing is printed, and an exit status of false +is returned. If the .B \-path flag is used, @@ -5012,73 +6433,71 @@ in place of and .BR \-path , respectively. -An argument of -.B \-\- -disables option checking for the rest of the arguments. .B type returns true if any of the arguments are found, false if none are found. .TP -\fBulimit\fP [\fB\-SHacdfmstpnuv\fP [\fIlimit\fP]] -.B Ulimit -provides control over the resources available to the shell and to +\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 value of .I limit can be a number in the unit specified for the resource, or the value .BR unlimited . -The \fBH\fP and \fBS\fP options specify that the hard or soft limit is +The \fB\-H\fP and \fB\-S\fP options specify that the hard or soft limit is set for the given resource. A hard limit cannot be increased once it is set; a soft limit may be increased up to the value of the hard limit. -If neither \fBH\fP nor \fBS\fP is specified, the command applies to the -soft limit. If +If neither \fB\-H\fP nor \fB\-S\fP is specified, both the soft and hard +limits are set. +If .I limit is omitted, the current value of the soft limit of the resource is -printed, unless the \fBH\fP option is given. When more than one resource -is specified, the limit name and unit is printed before the value. +printed, unless the \fB\-H\fP option is given. When more than one +resource is specified, the limit name and unit are printed before the value. Other options are interpreted as follows: .RS .PD 0 .TP .B \-a -all current limits are reported +All current limits are reported .TP .B \-c -the maximum size of core files created +The maximum size of core files created .TP .B \-d -the maximum size of a process's data segment +The maximum size of a process's data segment .TP .B \-f -the maximum size of files created by the shell +The maximum size of files created by the shell .TP -.B \-m -the maximum resident set size +.B \-l +The maximum size that may be locked into memory .TP -.B \-s -the maximum stack size +.B \-m +The maximum resident set size .TP -.B \-t -the maximum amount of cpu time in seconds +.B \-n +The maximum number of open file descriptors (most systems do not +allow this value to be set) .TP .B \-p -the pipe size in 512-byte blocks (this may not be set) +The pipe size in 512-byte blocks (this may not be set) .TP -.B \-n -the maximum number of open file descriptors (most systems do not -allow this value to be set, only displayed) +.B \-s +The maximum stack size +.TP +.B \-t +The maximum amount of cpu time in seconds .TP .B \-u -the maximum number of processes available to a single user +The maximum number of processes available to a single user .TP .B \-v The maximum amount of virtual memory available to the shell .PD .PP -An argument of -.B \-\- -disables option checking for the rest of the arguments. If +If .I limit is given, it is the new value of the specified resource (the .B \-a @@ -5115,14 +6534,12 @@ If is omitted, or if the .B \-S option is supplied, the -current value of the mask is printed. The +current value of the mask is printed. +The .B \-S option causes the mask to be printed in symbolic form; the default output is an octal number. -An argument of -.B \-\- -disables option checking for the rest of the arguments. The -return status is 0 if the mode was successfully changed or if +The return status is 0 if the mode was successfully changed or if no \fImode\fP argument was supplied, and false otherwise. .TP \fBunalias\fP [\-\fBa\fP] [\fIname\fP ...] @@ -5136,42 +6553,38 @@ is not a defined alias. \fBunset\fP [\-\fBfv\fP] [\fIname\fP ...] For each .IR name , -remove the corresponding variable or, given the +remove the corresponding variable or function. +If no options are supplied, or the +.B \-v +option is given, each +.I name +refers to a shell variable. +Read-only variables may not be unset. +If .B \-f -option, function. -An argument of -.B \-\- -disables option checking for the rest of the arguments. -Note that -.SM -.BR PATH , -.SM -.BR IFS , -.SM -.BR PPID , -.SM -.BR PS1 , -.SM -.BR PS2 , -.SM -.BR UID , -and -.SM -.B EUID -cannot be unset. If any of +is specifed, +each +.I name +refers to a shell function, and the function definition +is removed. +Each unset variable or function is removed from the environment +passed to subsequent commands. +If any of .SM .BR RANDOM , .SM .BR SECONDS , .SM .BR LINENO , +.SM +.BR HISTCMD , or .SM -.B HISTCMD +.B DIRSTACK are unset, they lose their special properties, even if they are subsequently reset. The exit status is true unless a .I name -does not exist or is non-unsettable. +does not exist or is readonly. .TP \fBwait\fP [\fIn\fP] Wait for the specified process and return its termination @@ -5184,89 +6597,77 @@ in that job's pipeline are waited for. If is not given, all currently active child processes are waited for, and the return status is zero. If .I n -specifies a non-existant process or job, the return status is +specifies a non-existent process or job, the return status is 127. Otherwise, the return status is the exit status of the last process or job waited for. .\" bash_builtins .if \n(zZ=1 .ig zZ -.SH INVOCATION -A \fIlogin shell\fP is one whose first character of argument zero is a -.BR \- , -or one started with the -.B \-login -flag. +.SH "RESTRICTED SHELL" .PP -An \fIinteractive\fP shell is one whose standard input and output are -both connected to terminals (as determined by -.IR isatty (3)), -or one started with the -.B \-i -option. -.SM -.B PS1 -is set and -.B $\- -includes -.B i -if +If .B bash -is interactive, -allowing a shell script or a startup file to test this state. -.PP -.nf -Login shells: - On login (subject to the \fB\-noprofile\fP option): - if \fI/etc/profile\fP exists, source it. - - if \fI~/.bash_profile\fP exists, source it, - else if \fI~/.bash_login\fP exists, source it, - else if \fI~/.profile\fP exists, source it. - - On exit: - if \fI~/.bash_logout\fP exists, source it. - -Non-login interactive shells: - On startup (subject to the \fB\-norc\fP and \fB\-rcfile\fP options): - if \fI~/.bashrc\fP exists, source it. - -Non-interactive shells: - On startup: - if the environment variable \fBENV\fP is non-null, expand - it and source the file it names, as if the command - if [ "$ENV" ]; then . $ENV; fi - had been executed, but do not use \fBPATH\fP to search - for the pathname. When not started in Posix mode, bash - looks for \fBBASH_ENV\fP before \fBENV\fP. -.PP -.fi -.PP -If Bash is invoked as -.BR sh , -it tries to mimic the behavior of -.B sh -as closely as possible. For a login shell, it attempts to -source only -.I /etc/profile +is started with the name +.BR rbash , +or the +.B \-r +option is supplied at invocation, +the shell becomes restricted. +A restricted shell is used to +set up an environment more controlled than the standard shell. +It behaves identically to +.B bash +with the exception that the following are disallowed: +.IP \(bu +changing directories with \fBcd\fP +.IP \(bu +setting or unsetting the values of +.B SHELL +or +.B PATH +.IP \(bu +specifying command names containing +.B / +.IP \(bu +specifying a file name containing a +.B / +as an argument to the +.B . +builtin command +.IP \(bu +importing function definitions from the shell environment at startup +.IP \(bu +redirecting output using the >, >|, <>, >&, &>, and >> redirection operators +.IP \(bu +using the +.B exec +builtin command to replace the shell with another command +.IP \(bu +adding or deleting builtin commands with the +.B \-f and -.IR ~/.profile , -in that order. The -.B \-noprofile -option may still be used to disable this behavior. -A shell invoked as -.B sh -does not attempt to source any other startup files. +.B \-d +options to the +.B enable +builtin command +.IP \(bu +specifying the +.B \-p +option to the +.B command +builtin command +.IP \(bu +turning off restricted mode with +.BR "set +r" . .PP -When -.B bash -is started in -.I posix -mode, as with the -.B \-posix -command line option, it follows the Posix standard for -startup files. In this mode, the -.B ENV -variable is expanded and that file sourced; no other startup -files are read. +These restrictions are enforced after any startup files are read. +.PP +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. .SH "SEE ALSO" .PD 0 .TP @@ -5276,8 +6677,6 @@ files are read. .TP \fIThe Gnu History Library\fP, Brian Fox and Chet Ramey .TP -\fIA System V Compatible Implementation of 4.2\s-1BSD\s+1 Job Control\fP, David Lennert -.TP \fIPortable Operating System Interface (POSIX) Part 2: Shell and Utilities\fP, IEEE .TP \fIsh\fP(1), \fIksh\fP(1), \fIcsh\fP(1) @@ -5305,10 +6704,9 @@ The individual per-interactive-shell startup file Individual \fIreadline\fP initialization file .PD .SH AUTHORS -.RS -Brian Fox, Free Software Foundation (primary author) +Brian Fox, Free Software Foundation .br -bfox@ai.MIT.Edu +bfox@gnu.ai.MIT.Edu .PP Chet Ramey, Case Western Reserve University .br @@ -5368,4 +6766,20 @@ mostly because of the specification. .PP Aliases are confusing in some uses. +.PP +Shell builtin commands and functions are not stoppable/restartable. +.PP +Compound commands and command sequences of the form `a ; b ; c' +are not handled gracefully when process suspension is attempted. +When a process is stopped, the shell immediately executes the next +command in the sequence. +It suffices to place the sequence of commands between +parentheses to force it into a subshell, which may be stopped as +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. +.PP +Array variables may not (yet) be exported. .zZ diff --git a/doc/bashbug.1 b/doc/bashbug.1 new file mode 100644 index 0000000..39abaf2 --- /dev/null +++ b/doc/bashbug.1 @@ -0,0 +1,41 @@ +.TH BASHBUG 1 "1995 August 10" GNU +.SH NAME +bashbug \- report a bug in bash +.SH SYNOPSIS +\fBbashbug\fP [\fIaddress\fP] +.SH DESCRIPTION +.B bashbug +is a shell script to help the user compose and mail bug reports +concerning bash in a standard format. +.B bashbug +invokes the editor specified by the environment variable +.SM +.B EDITOR +on a temporary copy of the bug report format outline. The user must +fill in the appropriate fields and exit the editor. +.B bashbug +then mails the completed report to \fIbug-bash@prep.ai.mit.edu\fP, or +\fIaddress\fP. If the report cannot be mailed, it is saved in the +file \fIdead.bashbug\fP in the invoking user's home directory. +.PP +The bug report format outline consists of several sections. The first +section provides information about the machine, operating system, the +bash version, and the compilation environment. The second section +should be filled in with a description of the bug. The third section +should be a description of how to reproduce the bug. The optional +fourth section is for a proposed fix. Fixes are encouraged. +.SH ENVIRONMENT +.B bashbug +will utilize the following environment variables if they exist: +.TP +.B EDITOR +Specifies the preferred editor. If +.SM +.B EDITOR +is not set, +.B bashbug +defaults to +.BR emacs . +.TP +.B HOME +Directory in which the failed bug report is saved if the mail fails. diff --git a/doc/bashref.info b/doc/bashref.info new file mode 100644 index 0000000..6e4ecc1 --- /dev/null +++ b/doc/bashref.info @@ -0,0 +1,6513 @@ +This is Info file bashref.info, produced by Makeinfo-1.64 from the +input file ./bashref.texi. + +This text is a brief description of the features that are present in +the Bash shell. + +This is Edition 2.0, last updated 25 November 1996, +of `The GNU Bash Reference Manual', +for `Bash', Version 2.0. + +Copyright (C) 1991, 1993, 1996 Free Software Foundation, Inc. + +Permission is granted to make and distribute verbatim copies of +this manual provided the copyright notice and this permission notice +are preserved on all copies. + +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. + + +File: bashref.info, Node: Top, Next: Introduction, Prev: (dir), Up: (dir) + +Bash Features +************* + + This text is a brief description of the features that are present in +the Bash shell. + + This is Edition 2.0, last updated 25 November 1996, of `The GNU Bash +Reference Manual', for `Bash', Version 2.0. + + Copyright (C) 1991, 1993, 1996 Free Software Foundation, Inc. + + Bash contains features that appear in other popular shells, and some +features that only appear in Bash. Some of the shells that Bash has +borrowed concepts from are the Bourne Shell (`sh'), the Korn Shell +(`ksh'), and the C-shell (`csh' and its successor, `tcsh'). The +following menu breaks the features up into categories based upon which +one of these other shells inspired the feature. + + This manual is meant as a brief introduction to features found in +Bash. The Bash manual page should be used as the definitive reference +on shell behavior. + +* Menu: + +* Introduction:: An introduction to the shell. + +* Definitions:: Some definitions used in the rest of this + manual. + +* Basic Shell Features:: The shell "building blocks". + +* Bourne Shell Features:: Features similar to those found in the + Bourne shell. + +* Csh Features:: Features originally found in the + Berkeley C-Shell. + +* Korn Shell Features:: Features originally found in the Korn + Shell. + +* Bash Features:: Features found only in Bash. + +* Job Control:: A chapter describing what job control is + and how Bash allows you to use it. + +* Using History Interactively:: Chapter dealing with history expansion + rules. + +* Command Line Editing:: Chapter describing the command line + editing features. + +* Installing Bash:: How to build and install Bash on your system. + +* Reporting Bugs:: How to report bugs in Bash. + +* Builtin Index:: Index of Bash builtin commands. + +* Reserved Word Index:: Index of Bash reserved words. + +* Variable Index:: Quick reference helps you find the + variable you want. + +* Function Index:: Index of bindable Readline functions. + +* Concept Index:: General index for concepts described in + this manual. + + +File: bashref.info, Node: Introduction, Next: Definitions, Prev: Top, Up: Top + +Introduction +************ + +* Menu: + +* What is Bash?:: A short description of Bash. + +* What is a shell?:: A brief introduction to shells. + + +File: bashref.info, Node: What is Bash?, Next: What is a shell?, Up: Introduction + +What is Bash? +============= + + Bash is the shell, or command language interpreter, that will appear +in the GNU operating system. The name is an acronym for the +`Bourne-Again SHell', a pun on Steve Bourne, the author of the direct +ancestor of the current Unix shell `/bin/sh', which appeared in the +Seventh Edition Bell Labs Research version of Unix. + + Bash is an `sh'-compatible shell that incorporates useful features +from the Korn shell `ksh' and the C shell `csh'. It is ultimately +intended to be a conformant implementation of the IEEE POSIX Shell and +Tools specification (IEEE Working Group 1003.2). It offers functional +improvements over `sh' for both interactive and programming use. + + While the GNU operating system will include a version of `csh', Bash +will be the default shell. Like other GNU software, Bash is quite +portable. It currently runs on nearly every version of Unix and a few +other operating systems - independently-supported ports exist for OS/2 +and Windows NT. + + +File: bashref.info, Node: What is a shell?, Prev: What is Bash?, Up: Introduction + +What is a shell? +================ + + At its base, a shell is simply a macro processor that executes +commands. A Unix shell is both a command interpreter, which provides +the user interface to the rich set of Unix utilities, and a programming +language, allowing these utilitites to be combined. The shell reads +commands either from a terminal or a file. Files containing commands +can be created, and become commands themselves. These new commands +have the same status as system commands in directories like `/bin', +allowing users or groups to establish custom environments. + + A shell allows execution of Unix commands, both synchronously and +asynchronously. The "redirection" constructs permit fine-grained +control of the input and output of those commands, and the shell allows +control over the contents of their environment. Unix shells also +provide a small set of built-in commands ("builtins") implementing +functionality impossible (e.g., `cd', `break', `continue', and `exec'), +or inconvenient (`history', `getopts', `kill', or `pwd', for example) +to obtain via separate utilities. Shells may be used interactively or +non-interactively: they accept input typed from the keyboard or from a +file. All of the shell builtins are described in subsequent sections. + + While executing commands is essential, most of the power (and +complexity) of shells is due to their embedded programming languages. +Like any high-level language, the shell provides variables, flow +control constructs, quoting, and functions. + + Shells have begun offering features geared specifically for +interactive use rather than to augment the programming language. These +interactive features include job control, command line editing, history +and aliases. Each of these features is described in this manual. + + +File: bashref.info, Node: Definitions, Next: Basic Shell Features, Prev: Introduction, Up: Top + +Definitions +*********** + + These definitions are used throughout the remainder of this manual. + +`POSIX' + A family of open system standards based on Unix. Bash is + concerned with POSIX 1003.2, the Shell and Tools Standard. + +`blank' + A space or tab character. + +`builtin' + A command that is implemented internally by the shell itself, + rather than by an executable program somewhere in the file system. + +`control operator' + A `word' that performs a control function. It is a `newline' or + one of the following: `||', `&&', `&', `;', `;;', `|', `(', or `)'. + +`exit status' + The value returned by a command to its caller. + +`field' + A unit of text that is the result of one of the shell expansions. + After expansion, when executing a command, the resulting fields + are used as the command name and arguments. + +`filename' + A string of characters used to identify a file. + +`job' + A set of processes comprising a pipeline, and any processes + descended from it, that are all in the same process group. + +`job control' + A mechanism by which users can selectively start and stop execution + of processes. + +`metacharacter' + A character that, when unquoted, separates words. A metacharacter + is a `blank' or one of the following characters: `|', `&', `;', + `(', `)', `<', or `>'. + +`name' + A `word' consisting solely of letters, numbers, and underscores, + and beginning with a letter or underscore. `Name's are used as + shell variable and function names. Also referred to as an + `identifier'. + +`operator' + A `control operator' or a `redirection operator'. *Note + Redirections::, for a list of redirection operators. + +`process group' + A collection of related processes each having the same process + group ID. + +`process group ID' + A unique identifer that represents a `process group' during its + lifetime. + +`reserved word' + A `word' that has a special meaning to the shell. Most reserved + words introduce shell flow control constructs, such as `for' and + `while'. + +`return status' + A synonym for `exit status'. + +`signal' + A mechanism by which a process may be notified by the kernal of an + event occurring in the system. + +`special builtin' + A shell builtin command that has been classified as special by the + POSIX.2 standard. + +`token' + A sequence of characters considered a single unit by the shell. + It is either a `word' or an `operator'. + +`word' + A `token' that is not an `operator'. + + +File: bashref.info, Node: Basic Shell Features, Next: Bourne Shell Features, Prev: Definitions, Up: Top + +Basic Shell Features +******************** + + Bash is an acronym for `Bourne-Again SHell'. The Bourne shell is +the traditional Unix shell originally written by Stephen Bourne. All +of the Bourne shell builtin commands are available in Bash, and the +rules for evaluation and quoting are taken from the POSIX 1003.2 +specification for the `standard' Unix shell. + + This chapter briefly summarizes the shell's "building blocks": +commands, control structures, shell functions, shell parameters, shell +expansions, redirections, which are a way to direct input and output +from and to named files, and how the shell executes commands. + +* Menu: + +* Shell Syntax:: What your input means to the shell. +* Simple Commands:: The most common type of command. +* Pipelines:: Connecting the input and output of several + commands. +* Lists:: How to execute commands sequentially. +* Looping Constructs:: Shell commands for iterative action. +* Conditional Constructs:: Shell commands for conditional execution. +* Command Grouping:: Ways to group commands. +* Shell Functions:: Grouping commands by name. +* Shell Parameters:: Special shell variables. +* Shell Expansions:: How Bash expands variables and the various + expansions available. +* Redirections:: A way to control where input and output go. +* Executing Commands:: What happens when you run a command. +* Shell Scripts:: Executing files of shell commands. + + +File: bashref.info, Node: Shell Syntax, Next: Simple Commands, Up: Basic Shell Features + +Shell Syntax +============ + +* Menu: + +* Shell Operation:: The basic operation of the shell. + +* Quoting:: How to remove the special meaning from characters. + +* Comments:: How to specify comments. + + +File: bashref.info, Node: Shell Operation, Next: Quoting, Up: Shell Syntax + +Shell Operation +--------------- + + The following is a brief description of the shell's operation when it +reads and executes a command. Basically, the shell does the following: + + 1. Reads its input from a file (*note Shell Scripts::.), from a string + supplied as an argument to the `-c' invocation option (*note + Invoking Bash::.), or from the user's terminal. + + 2. Breaks the input into words and operators, obeying the quoting + rules described in *Note Quoting::. Tokens are separated by + `metacharacters'. Alias expansion is performed by this step + (*note Aliases::.). + + 3. Parses the tokens into simple and compound commands. + + 4. Performs the various shell expansions (*note Shell Expansions::.), + breaking the expanded tokens into lists of filenames (*note + Filename Expansion::.) and commands and arguments. + + 5. Performs any necessary redirections (*note Redirections::.) and + removes the redirection operators and their operands from the + argument list. + + 6. Executes the command (*note Executing Commands::.). + + 7. Optionally waits for the command to complete and collects its exit + status. + + + +File: bashref.info, Node: Quoting, Next: Comments, Prev: Shell Operation, Up: Shell Syntax + +Quoting +------- + +* Menu: + +* Escape Character:: How to remove the special meaning from a single + character. +* Single Quotes:: How to inhibit all interpretation of a sequence + of characters. +* Double Quotes:: How to suppress most of the interpretation of a + sequence of characters. +* ANSI-C Quoting:: How to expand ANSI-C sequences in quoted strings. + +* Locale Translation:: How to translate strings into different languages. + + Quoting is used to remove the special meaning of certain characters +or words to the shell. Quoting can be used to disable special +treatment for special characters, to prevent reserved words from being +recognized as such, and to prevent parameter expansion. + + Each of the shell `metacharacters' (*note Definitions::.) has +special meaning to the shell and must be quoted if they are to +represent themselves. There are three quoting mechanisms: the ESCAPE +CHARACTER, single quotes, and double quotes. + + +File: bashref.info, Node: Escape Character, Next: Single Quotes, Up: Quoting + +Escape Character +................ + + A non-quoted backslash `\' is the Bash escape character. It +preserves the literal value of the next character that follows, with +the exception of `newline'. If a `\newline' pair appears, and the +backslash is not quoted, the `\newline' is treated as a line +continuation (that is, it is effectively ignored). + + +File: bashref.info, Node: Single Quotes, Next: Double Quotes, Prev: Escape Character, Up: Quoting + +Single Quotes +............. + + Enclosing characters in single quotes preserves the literal value of +each character within the quotes. A single quote may not occur between +single quotes, even when preceded by a backslash. + + +File: bashref.info, Node: Double Quotes, Next: ANSI-C Quoting, Prev: Single Quotes, Up: Quoting + +Double Quotes +............. + + Enclosing characters in double quotes preserves the literal value of +all characters within the quotes, with the exception of `$', ``', and +`\'. The characters `$' and ``' retain their special meaning within +double quotes. The backslash retains its special meaning only when +followed by one of the following characters: `$', ``', `"', `\', or +`newline'. A double quote may be quoted within double quotes by +preceding it with a backslash. + + The special parameters `*' and `@' have special meaning when in +double quotes (*note Shell Parameter Expansion::.). + + +File: bashref.info, Node: ANSI-C Quoting, Next: Locale Translation, Prev: Double Quotes, Up: Quoting + +ANSI-C Quoting +.............. + + Words of the form `$'STRING'' are treated specially. The word +expands to STRING, with backslash-escaped characters replaced as +specifed by the ANSI C standard. Backslash escape sequences, if +present, are decoded as follows: + +`\a' + alert (bell) + +`\b' + backspace + +`\e' + an escape character (not ANSI C) + +`\f' + form feed + +`\n' + newline + +`\r' + carriage return + +`\t' + horizontal tab + +`\v' + vertical tab + +`\\' + backslash + +`\NNN' + the character whose `ASCII' code is NNN in octal + +The result is single-quoted, as if the dollar sign had not been present. + + +File: bashref.info, Node: Locale Translation, Prev: ANSI-C Quoting, Up: Quoting + +Locale-Specific Translation +........................... + + A double-quoted string preceded by a dollar sign (`$') will cause +the string to be translated according to the current locale. If the +current locale is `C' or `POSIX', the dollar sign is ignored. If the +string is translated and replaced, the replacement is double-quoted. + + +File: bashref.info, Node: Comments, Prev: Quoting, Up: Shell Syntax + +Comments +-------- + + In a non-interactive shell, or an interactive shell in which the +`interactive_comments' option to the `shopt' builtin is enabled (*note +Bash Builtins::.), a word beginning with `#' causes that word and all +remaining characters on that line to be ignored. An interactive shell +without the `interactive_comments' option enabled does not allow +comments. The `interactive_comments' option is on by default in +interactive shells. + + +File: bashref.info, Node: Simple Commands, Next: Pipelines, Prev: Shell Syntax, Up: Basic Shell Features + +Simple Commands +=============== + + A simple command is the kind of command you'll encounter most often. +It's just a sequence of words separated by `blank's, terminated by one +of the shell control operators (*note Definitions::.). The first word +generally specifies a command to be executed. + + The return status (*note Exit Status::.) of a simple command is its +exit status as provided by the POSIX.1 `waitpid' function, or 128+N if +the command was terminated by signal N. + + +File: bashref.info, Node: Pipelines, Next: Lists, Prev: Simple Commands, Up: Basic Shell Features + +Pipelines +========= + + A `pipeline' is a sequence of simple commands separated by `|'. + + The format for a pipeline is + [`time' [`-p']] [`!'] COMMAND1 [`|' COMMAND2 ...] + +The output of each command in the pipeline is connected to the input of +the next command. That is, each command reads the previous command's +output. + + The reserved word `time' causes timing statistics to be printed for +the pipeline once it finishes. The `-p' option changes the output +format to that specified by POSIX. The `TIMEFORMAT' variable may be +set to a format string that specifies how the timing information should +be displayed. *Note Bash Variables::, for a description of the +available formats. + + Each command in a pipeline is executed in its own subshell. The exit +status of a pipeline is the exit status of the last command in the +pipeline. If the reserved word `!' precedes the pipeline, the exit +status is the logical NOT of the exit status of the last command. + + +File: bashref.info, Node: Lists, Next: Looping Constructs, Prev: Pipelines, Up: Basic Shell Features + +Lists of Commands +================= + + A `list' is a sequence of one or more pipelines separated by one of +the operators `;', `&', `&&', or `||', and optionally terminated by one +of `;', `&', or a `newline'. + + Of these list operators, `&&' and `||' have equal precedence, +followed by `;' and `&', which have equal precedence. + + If a command is terminated by the control operator `&', the shell +executes the command in the BACKGROUND in a subshell. The shell does +not wait for the command to finish, and the return status is 0 (true). +Commands separated by a `;' are executed sequentially; the shell waits +for each command to terminate in turn. The return status is the exit +status of the last command executed. + + The control operators `&&' and `||' denote AND lists and OR lists, +respectively. An AND list has the form + COMMAND && COMMAND2 + +COMMAND2 is executed if, and only if, COMMAND returns an exit status of +zero. + + An OR list has the form + COMMAND || COMMAND2 + +COMMAND2 is executed if and only if COMMAND returns a non-zero exit +status. + + The return status of AND and OR lists is the exit status of the last +command executed in the list. + + +File: bashref.info, Node: Looping Constructs, Next: Conditional Constructs, Prev: Lists, Up: Basic Shell Features + +Looping Constructs +================== + + Note that wherever you see a `;' in the description of a command's +syntax, it may be replaced indiscriminately with one or more newlines. + + Bash supports the following looping constructs. + +`until' + The syntax of the `until' command is: + until TEST-COMMANDS; do CONSEQUENT-COMMANDS; done + Execute CONSEQUENT-COMMANDS as long as the final command in + TEST-COMMANDS has an exit status which is not zero. + +`while' + The syntax of the `while' command is: + while TEST-COMMANDS; do CONSEQUENT-COMMANDS; done + + Execute CONSEQUENT-COMMANDS as long as the final command in + TEST-COMMANDS has an exit status of zero. + +`for' + The syntax of the `for' command is: + + for NAME [in WORDS ...]; do COMMANDS; done + Execute COMMANDS for each member in WORDS, with NAME bound to the + current member. If `in WORDS' is not present, `in "$@"' is + assumed. + + The `break' and `continue' builtins (*note Bourne Shell Builtins::.) +may be used to control loop execution. + + +File: bashref.info, Node: Conditional Constructs, Next: Command Grouping, Prev: Looping Constructs, Up: Basic Shell Features + +Conditional Constructs +====================== + +`if' + The syntax of the `if' command is: + + if TEST-COMMANDS; then + CONSEQUENT-COMMANDS; + [elif MORE-TEST-COMMANDS; then + MORE-CONSEQUENTS;] + [else ALTERNATE-CONSEQUENTS;] + fi + + Execute CONSEQUENT-COMMANDS only if the final command in + TEST-COMMANDS has an exit status of zero. Otherwise, each `elif' + list is executed in turn, and if its exit status is zero, the + corresponding MORE-CONSEQUENTS is executed and the command + completes. If `else ALTERNATE-CONSEQUENTS' is present, and the + final command in the final `if' or `elif' clause has a non-zero + exit status, then execute ALTERNATE-CONSEQUENTS. + +`case' + The syntax of the `case' command is: + + `case WORD in [PATTERN [| PATTERN]...) COMMANDS ;;]... esac' + + Selectively execute COMMANDS based upon WORD matching PATTERN. + The `|' is used to separate multiple patterns. + + Here is an example using `case' in a script that could be used to + describe one interesting feature of an animal: + + echo -n "Enter the name of an animal: " + read ANIMAL + echo -n "The $ANIMAL has " + case $ANIMAL in + horse | dog | cat) echo -n "four";; + man | kangaroo ) echo -n "two";; + *) echo -n "an unknown number of";; + esac + echo " legs." + +`((...))' + (( EXPRESSION )) + + The EXPRESSION is evaluated according to the rules described below + ((*note Arithmetic Evaluation::.). If the value of the expression + is non-zero, the return status is 0; otherwise the return status + is 1. This is exactly equivalent to + let "EXPRESSION" + + The `select' construct, which allows users to choose from a list of +items presented as a menu, is also available. *Note Korn Shell +Constructs::, for a full description of `select'. + + +File: bashref.info, Node: Command Grouping, Next: Shell Functions, Prev: Conditional Constructs, Up: Basic Shell Features + +Grouping Commands +================= + + Bash provides two ways to group a list of commands to be executed as +a unit. When commands are grouped, redirections may be applied to the +entire command list. For example, the output of all the commands in +the list may be redirected to a single stream. + +`()' + ( LIST ) + + Placing a list of commands between parentheses causes a subshell + to be created, and each of the commands to be executed in that + subshell. Since the LIST is executed in a subshell, variable + assignments do not remain in effect after the subshell completes. + +`{}' + { LIST; } + + Placing a list of commands between curly braces causes the list to + be executed in the current shell context. No subshell is created. + The semicolon following LIST is required. + + In addition to the creation of a subshell, there is a subtle +difference between these two constructs due to historical reasons. The +braces are `reserved words', so they must be separated from the LIST by +`blank's. The parentheses are `operators', and are recognized as +separate tokens by the shell even if they are not separated from `list' +by whitespace. + + The exit status of both of these constructs is the exit status of +LIST. + + +File: bashref.info, Node: Shell Functions, Next: Shell Parameters, Prev: Command Grouping, Up: Basic Shell Features + +Shell Functions +=============== + + Shell functions are a way to group commands for later execution +using a single name for the group. They are executed just like a +"regular" command. Shell functions are executed in the current shell +context; no new process is created to interpret them. + + Functions are declared using this syntax: + [ `function' ] NAME () { COMMAND-LIST; } + + This defines a shell function named NAME. The reserved word +`function' is optional. The BODY of the function is the COMMAND-LIST +between { and }. This list is executed whenever NAME is specified as +the name of a command. The exit status of a function is the exit +status of the last command executed in the body. + + When a function is executed, the arguments to the function become +the positional parameters during its execution (*note Positional +Parameters::.). The special parameter `#' that gives the number of +positional parameters is updated to reflect the change. Positional +parameter `0' is unchanged. + + If the builtin command `return' is executed in a function, the +function completes and execution resumes with the next command after +the function call. When a function completes, the values of the +positional parameters and the special parameter `#' are restored to the +values they had prior to function execution. If a numeric argument is +given to `return', that is the function return status. + + Variables local to the function may be declared with the `local' +builtin. These variables are visible only to the function and the +commands it invokes. + + Functions may be recursive. No limit is placed on the number of +recursive calls. + + +File: bashref.info, Node: Shell Parameters, Next: Shell Expansions, Prev: Shell Functions, Up: Basic Shell Features + +Shell Parameters +================ + +* Menu: + +* Positional Parameters:: The shell's command-line arguments. +* Special Parameters:: Parameters with special meanings. + + A PARAMETER is an entity that stores values. It can be a `name', a +number, or one of the special characters listed below. For the shell's +purposes, a VARIABLE is a parameter denoted by a `name'. + + A parameter is set if it has been assigned a value. The null string +is a valid value. Once a variable is set, it may be unset only by using +the `unset' builtin command. + + A variable may be assigned to by a statement of the form + NAME=[VALUE] + +If VALUE is not given, the variable is assigned the null string. All +VALUEs undergo tilde expansion, parameter and variable expansion, +command substitution, arithmetic expansion, and quote removal (detailed +below). If the variable has its `-i' attribute set (see the +description of the `declare' builtin in *Note Bash Builtins::), then +VALUE is subject to arithmetic expansion even if the `$((...))' syntax +does not appear (*note Arithmetic Expansion::.). Word splitting is not +performed, with the exception of `"$@"' as explained below. Filename +expansion is not performed. + + +File: bashref.info, Node: Positional Parameters, Next: Special Parameters, Up: Shell Parameters + +Positional Parameters +--------------------- + + A POSITIONAL PARAMETER is a parameter denoted by one or more digits, +other than the single digit `0'. Positional parameters are assigned +from the shell's arguments when it is invoked, and may be reassigned +using the `set' builtin command. Positional parameters may not be +assigned to with assignment statements. The positional parameters are +temporarily replaced when a shell function is executed (*note Shell +Functions::.). + + When a positional parameter consisting of more than a single digit +is expanded, it must be enclosed in braces. + + +File: bashref.info, Node: Special Parameters, Prev: Positional Parameters, Up: Shell Parameters + +Special Parameters +------------------ + + The shell treats several parameters specially. These parameters may +only be referenced; assignment to them is not allowed. + +`*' + Expands to the positional parameters, starting from one. When the + expansion occurs within double quotes, it expands to a single word + with the value of each parameter separated by the first character + of the `IFS' special variable. That is, `"$*"' is equivalent to + `"$1C$2C..."', where C is the first character of the value of the + `IFS' variable. If `IFS' is null or unset, the parameters are + separated by spaces. + +`@' + Expands to the positional parameters, starting from one. When the + expansion occurs within double quotes, each parameter expands as a + separate word. That is, `"$@"' is equivalent to `"$1" "$2" ...'. + When there are no positional parameters, `"$@"' and `$@' expand to + nothing (i.e., they are removed). + +`#' + Expands to the number of positional parameters in decimal. + +`?' + Expands to the exit status of the most recently executed foreground + pipeline. + +`-' + Expands to the current option flags as specified upon invocation, + by the `set' builtin command, or those set by the shell itself + (such as the `-i' option). + +`$' + Expands to the process ID of the shell. In a `()' subshell, it + expands to the process ID of the current shell, not the subshell. + +`!' + Expands to the process ID of the most recently executed background + (asynchronous) command. + +`0' + Expands to the name of the shell or shell script. This is set at + shell initialization. If Bash is invoked with a file of commands, + `$0' is set to the name of that file. If Bash is started with the + `-c' option, then `$0' is set to the first argument after the + string to be executed, if one is present. Otherwise, it is set to + the filename used to invoke Bash, as given by argument zero. + +`_' + At shell startup, set to the absolute filename 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 filename 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. + + +File: bashref.info, Node: Shell Expansions, Next: Redirections, Prev: Shell Parameters, Up: Basic Shell Features + +Shell Expansions +================ + + Expansion is performed on the command line after it has been split +into `token's. There are seven kinds of expansion performed: + * brace expansion + + * tilde expansion + + * parameter and variable expansion + + * command substitution + + * arithmetic expansion + + * word splitting + + * filename expansion + +* Menu: + +* Shell Parameter Expansion:: How Bash expands variables to their values. +* Command Substitution:: Using the output of a command as an argument. +* Process Substitution:: A way to write and read to and from a + command. +* Word Splitting:: How the results of expansion are split into separate + arguments. +* Filename Expansion:: A shorthand for specifying filenames matching patterns. +* Quote Removal:: How and when quote characters are removed from + words. + + Brace expansion, tilde expansion, and arithmetic expansion are +described in other sections. For brace expansion, see *Note Brace +Expansion::; for tilde expansion, see *Note Tilde Expansion::; and for +arithmetic expansion, see *Note Arithmetic Expansion::. + + The order of expansions is: brace expansion, tilde expansion, +parameter, variable, and arithmetic expansion and command substitution +(done in a left-to-right fashion), word splitting, and filename +expansion. + + On systems that can support it, there is an additional expansion +available: PROCESS SUBSTITUTION. This is performed at the same time as +parameter, variable, and arithemtic expansion and command substitution. + + Only brace expansion, word splitting, and filename expansion can +change the number of words of the expansion; other expansions expand a +single word to a single word. The only exceptions to this are the +expansions of `"$@"' (*note Special Parameters::.) and `"${[@]}"' +(*note Arrays::.). + + After all expansions, `quote removal' (*note Quote Removal::.) is +performed. + + +File: bashref.info, Node: Shell Parameter Expansion, Next: Command Substitution, Up: Shell Expansions + +Shell Parameter Expansion +------------------------- + + The `$' character introduces parameter expansion, command +substitution, or arithmetic expansion. The parameter name or symbol to +be expanded may be enclosed in braces, which are optional but serve to +protect the variable to be expanded from characters immediately +following it which could be interpreted as part of the name. + + The basic form of parameter expansion is ${PARAMETER}. The value of +PARAMETER is substituted. The braces are required when PARAMETER is a +positional parameter with more than one digit, or when PARAMETER is +followed by a character that is not to be interpreted as part of its +name. + + If the first character of PARAMETER is an exclamation point, a level +of variable indirection is introduced. Bash uses the value of the +variable formed from the rest of PARAMETER as the name of the variable; +this variable is then expanded and that value used in the rest of the +substitution, rather than the value of PARAMETER itself. This is known +as `indirect expansion'. + + In each of the cases below, WORD is subject to tilde expansion, +parameter expansion, command substitution, and arithmetic expansion. +When not performing substring expansion, Bash tests for a parameter +that is unset or null; omitting the colon results in a test only for a +parameter that is unset. + +`${PARAMETER:-WORD}' + If PARAMETER is unset or null, the expansion of WORD is + substituted. Otherwise, the value of PARAMETER is substituted. + +`${PARAMETER:=WORD}' + If PARAMETER is unset or null, the expansion of WORD is assigned + to PARAMETER. The value of PARAMETER is then substituted. + Positional parameters and special parameters may not be assigned + to in this way. + +`${PARAMETER:?WORD}' + If PARAMETER is null or unset, the expansion of WORD (or a message + to that effect if WORD is not present) is written to the standard + error and the shell, if it is not interactive, exits. Otherwise, + the value of PARAMETER is substituted. + +`${PARAMETER:+WORD}' + If PARAMETER is null or unset, nothing is substituted, otherwise + the expansion of WORD is substituted. + +`${PARAMETER:OFFSET}' +`${PARAMETER:OFFSET:LENGTH}' + Expands to up to LENGTH characters of PARAMETER, starting at + OFFSET. If LENGTH is omitted, expands to the substring of + PARAMETER, starting at the character specified by OFFSET. LENGTH + and OFFSET are arithmetic expressions (*note Arithmetic + Evaluation::.). This is referred to as Substring Expansion. + + LENGTH must evaluate to a number greater than or equal to zero. + If OFFSET evaluates to a number less than zero, the value is used + as an offset from the end of the value of PARAMETER. If PARAMETER + is `@', the result is LENGTH positional parameters beginning at + OFFSET. If PARAMETER is an array name indexed by `@' or `*', the + result is the LENGTH members of the array beginning with + ${PARAMETER[OFFSET]}. Substring indexing is zero-based unless the + positional parameters are used, in which case the indexing starts + at 1. + +`${#PARAMETER}' + The length in characters of the value of PARAMETER is substituted. + If PARAMETER is `*' or `@', the length substituted is the number + of positional parameters. If PARAMETER is an array name + subscripted by `*' or `@', the length substituted is the number of + elements in the array. + +`${PARAMETER#WORD}' +`${PARAMETER##WORD}' + The WORD is expanded to produce a pattern just as in filename + expansion (*note Filename Expansion::.). If the pattern matches + the beginning of the value of PARAMETER, then the expansion is the + value of PARAMETER with the shortest matching pattern (the `#' + case) or the longest matching pattern (the `##' case) deleted. If + PARAMETER is `@' or `*', the pattern removal operation is applied + to each positional parameter in turn, and the expansion is the + resultant list. If PARAMETER is an array variable subscripted with + `@' or `*', the pattern removal operation is applied to each + member of the array in turn, and the expansion is the resultant + list. + +`${PARAMETER%WORD}' +`${PARAMETER%%WORD}' + The WORD is expanded to produce a pattern just as in filename + expansion. If the pattern matches a trailing portion of the value + of PARAMETER, then the expansion is the value of PARAMETER with + the shortest matching pattern (the `%' case) or the longest + matching pattern (the `%%' case) deleted. If PARAMETER is `@' or + `*', the pattern removal operation is applied to each positional + parameter in turn, and the expansion is the resultant list. If + PARAMETER is an array variable subscripted with `@' or `*', the + pattern removal operation is applied to each member of the array + in turn, and the expansion is the resultant list. + +`${PARAMETER/PATTERN/STRING}' +`${PARAMETER//PATTERN/STRING}' + The PATTERN is expanded to produce a pattern just as in filename + expansion. PARAMETER is expanded and the longest match of PATTERN + against its value is replaced with STRING. In the first form, + only the first match is replaced. The second form causes all + matches of PATTERN to be replaced with STRING. If PATTERN begins + with `#', it must match at the beginning of STRING. If PATTERN + begins with `%', it must match at the end of STRING. If STRING is + null, matches of PATTERN are deleted and the `/' following PATTERN + may be omitted. If PARAMETER is `@' or `*', the substitution + operation is applied to each positional parameter in turn, and the + expansion is the resultant list. If PARAMETER is an array + variable subscripted with `@' or `*', the substitution operation + is applied to each member of the array in turn, and the expansion + is the resultant list. + + +File: bashref.info, Node: Command Substitution, Next: Process Substitution, Prev: Shell Parameter Expansion, Up: Shell Expansions + +Command Substitution +-------------------- + + Command substitution allows the output of a command to replace the +command name. There are two forms: + $(COMMAND) + +or + `COMMAND` + +Bash performs the expansion by executing COMMAND and replacing the +command substitution with the standard output of the command, with any +trailing newlines deleted. + + When the old-style backquote form of substitution is used, backslash +retains its literal meaning except when followed by `$', ``', or `\'. +When using the `$(COMMAND)' form, all characters between the +parentheses make up the command; none are treated specially. + + Command substitutions may be nested. To nest when using the old +form, escape the inner backquotes with backslashes. + + If the substitution appears within double quotes, word splitting and +filename expansion are not performed on the results. + + +File: bashref.info, Node: Process Substitution, Next: Word Splitting, Prev: Command Substitution, Up: Shell Expansions + +Process Substitution +-------------------- + + Process substitution is supported on systems that support named +pipes (FIFOs) or the `/dev/fd' method of naming open files. It takes +the form of + <(LIST) + +or + >(LIST) + +The process LIST is run with its input or output connected to a FIFO or +some file in `/dev/fd'. The name of this file is passed as an argument +to the current command as the result of the expansion. If the +`>(LIST)' form is used, writing to the file will provide input for +LIST. If the `<(LIST)' form is used, the file passed as an argument +should be read to obtain the output of LIST. + + On systems that support it, process substitution is performed +simultaneously with parameter and variable expansion, command +substitution, and arithmetic expansion. + + +File: bashref.info, Node: Word Splitting, Next: Filename Expansion, Prev: Process Substitution, Up: Shell Expansions + +Word Splitting +-------------- + + The shell scans the results of parameter expansion, command +substitution, and arithmetic expansion that did not occur within double +quotes for word splitting. + + The shell treats each character of `$IFS' as a delimiter, and splits +the results of the other expansions into words on these characters. If +`IFS' is unset, or its value is exactly `', the +default, then any sequence of `IFS' characters serves to delimit words. +If `IFS' has a value other than the default, then sequences of the +whitespace characters `space' and `tab' are ignored at the beginning +and end of the word, as long as the whitespace character is in the +value of `IFS' (an `IFS' whitespace character). Any character in `IFS' +that is not `IFS' whitespace, along with any adjacent `IFS' whitespace +characters, delimits a field. A sequence of `IFS' whitespace +characters is also treated as a delimiter. If the value of `IFS' is +null, no word splitting occurs. + + Explicit null arguments (`""' or `''') 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 null argument results and is retained. + + Note that if no expansion occurs, no splitting is performed. + + +File: bashref.info, Node: Filename Expansion, Next: Quote Removal, Prev: Word Splitting, Up: Shell Expansions + +Filename Expansion +------------------ + + After word splitting, unless the `-f' option has been set (*note The +Set Builtin::.), Bash scans each word for the characters `*', `?', and +`['. If one of these characters appears, then the word is regarded as +a PATTERN, and replaced with an alphabetically sorted list of file +names matching the pattern. If no matching file names are found, and +the shell option `nullglob' is disabled, the word is left unchanged. If +the option is set, and no matches are found, the word is removed. When +a pattern is used for filename generation, the character `.' at the +start of a filename or immediately following a slash must be matched +explicitly, unless the shell option `dotglob' is set. The slash +character must always be matched explicitly. In other cases, the `.' +character is not treated specially. See the description of `shopt' in +*Note Bash Builtins::, for a description of the `nullglob' and +`dotglob' options. + + The `GLOBIGNORE' shell variable may be used to restrict the set of +filenames matching a PATTERN. If `GLOBIGNORE' is set, each matching +filename that also matches one of the patterns in `GLOBIGNORE' is +removed from the list of matches. The filenames `.' and `..' are +always ignored, even when `GLOBIGNORE'. is set. However, setting +`GLOBIGNORE' has the effect of enabling the `dotglob' shell option, so +all other filenames beginning with a `.' will match. To get the old +behavior of ignoring filenames beginning with a `.', make `.*' one of +the patterns in `GLOBIGNORE'. The `dotglob' option is disabled when +`GLOBIGNORE' is unset. + + The special pattern characters have the following meanings: +`*' + Matches any string, including the null string. + +`?' + Matches any single character. + +`[...]' + Matches any one of the enclosed characters. A pair of characters + separated by a minus sign denotes a RANGE; any character lexically + between those two characters, inclusive, is matched. If the first + character following the `[' is a `!' or a `^' then any character + not enclosed is matched. A `-' may be matched by including it as + the first or last character in the set. A `]' may be matched by + including it as the first character in the set. + + +File: bashref.info, Node: Quote Removal, Prev: Filename Expansion, Up: Shell Expansions + +Quote Removal +------------- + + After the preceding expansions, all unquoted occurrences of the +characters `\', `'', and `"' that did not result from one of the above +expansions are removed. + + +File: bashref.info, Node: Redirections, Next: Executing Commands, Prev: Shell Expansions, Up: Basic Shell Features + +Redirections +============ + + Before a command is executed, its input and output may be REDIRECTED +using a special notation interpreted by the shell. Redirection may +also be used to open and close files for the current shell execution +environment. The following redirection operators may precede or appear +anywhere within a simple command or may follow a command. Redirections +are processed in the order they appear, from left to right. + + In the following descriptions, if the file descriptor number is +omitted, and the first character of the redirection operator is `<', +the redirection refers to the standard input (file descriptor 0). If +the first character of the redirection operator is `>', the redirection +refers to the standard output (file descriptor 1). + + The word that follows the redirection operator in the following +descriptions is subjected to brace expansion, tilde expansion, +parameter expansion, command substitution, arithmetic expansion, quote +removal, and filename expansion. If it expands to more than one word, +Bash reports an error. + + Note that the order of redirections is significant. For example, +the command + ls > DIRLIST 2>&1 + +directs both standard output and standard error to the file DIRLIST, +while the command + ls 2>&1 > DIRLIST + +directs only the standard output to file DIRLIST, because the standard +error was duplicated as standard output before the standard output was +redirected to DIRLIST. + +Redirecting Input +----------------- + + Redirection of input causes the file whose name results from the +expansion of WORD to be opened for reading on file descriptor `n', or +the standard input (file descriptor 0) if `n' is not specified. + + The general format for redirecting input is: + [n][|]WORD + + If the redirection operator is `>', and the `-C' option to the `set' +builtin has been enabled, the redirection will fail if the filename +whose name results from the expansion of WORD exists. If the +redirection operator is `>|', then the value of the `-C' option to the +`set' builtin command is not tested, and the redirection is attempted +even if the file named by WORD exists. + +Appending Redirected Output +--------------------------- + + Redirection of output in this fashion causes the file whose name +results from the expansion of WORD to be opened for appending on file +descriptor `n', or the standard output (file descriptor 1) if `n' is +not specified. If the file does not exist it is created. + + The general format for appending output is: + [n]>>WORD + +Redirecting Standard Output and Standard Error +---------------------------------------------- + + Bash allows both the standard output (file descriptor 1) and the +standard error output (file descriptor 2) to be redirected to the file +whose name is the expansion of WORD with this construct. + + There are two formats for redirecting standard output and standard +error: + &>WORD + +and + >&WORD + +Of the two forms, the first is preferred. This is semantically +equivalent to + >WORD 2>&1 + +Here Documents +-------------- + + This type of redirection instructs the shell to read input from the +current source until a line containing only WORD (with no trailing +blanks) is seen. All of the lines read up to that point are then used +as the standard input for a command. + + The format of here-documents is as follows: + <<[-]WORD + HERE-DOCUMENT + DELIMITER + + No parameter expansion, command substitution, filename expansion, or +arithmetic expansion is performed on WORD. If any characters in WORD +are quoted, the DELIMITER is the result of quote removal on WORD, and +the lines in the here-document are not expanded. Otherwise, all lines +of the here-document are subjected to parameter expansion, command +substitution, and arithmetic expansion. In the latter case, the pair +`\newline' is ignored, and `\' must be used to quote the characters +`\', `$', and ``'. + + If the redirection operator is `<<-', then all leading tab +characters are stripped from input lines and the line containing +DELIMITER. This allows here-documents within shell scripts to be +indented in a natural fashion. + +Duplicating File Descriptors +---------------------------- + + The redirection operator + [n]<&WORD + +is used to duplicate input file descriptors. If WORD expands to one or +more digits, the file descriptor denoted by `n' is made to be a copy of +that file descriptor. If WORD evaluates to `-', file descriptor `n' is +closed. If `n' is not specified, the standard input (file descriptor +0) is used. + + The operator + [n]>&WORD + +is used similarly to duplicate output file descriptors. If `n' is not +specified, the standard output (file descriptor 1) is used. As a +special case, if `n' is omitted, and WORD does not expand to one or +more digits, the standard output and standard error are redirected as +described previously. + +Opening File Descriptors for Reading and Writing +------------------------------------------------ + + The redirection operator + [n]<>WORD + +causes the file whose name is the expansion of WORD to be opened for +both reading and writing on file descriptor `n', or on file descriptor +0 if `n' is not specified. If the file does not exist, it is created. + + +File: bashref.info, Node: Executing Commands, Next: Shell Scripts, Prev: Redirections, Up: Basic Shell Features + +Executing Commands +================== + +* Menu: + +* Command Search and Execution:: How Bash finds commands and runs them. + +* Environment:: The environment given to a command. + +* Exit Status:: The status returned by commands and how Bash + interprets it. + +* Signals:: What happens when Bash or a command it runs + receives a signal. + + +File: bashref.info, Node: Command Search and Execution, Next: Environment, Up: Executing Commands + +Command Search and Execution +---------------------------- + + After a command has been split into words, if it results in a simple +command and an optional list of arguments, the following actions are +taken. + + 1. If the command name contains no slashes, the shell attempts to + locate it. If there exists a shell function by that name, that + function is invoked as described above in *Note Shell Functions::. + + 2. If the name does not match a function, the shell searches for it + in the list of shell builtins. If a match is found, that builtin + is invoked. + + 3. If the name is neither a shell function nor a builtin, and + contains no slashes, Bash searches each element of `$PATH' for a + directory containing an executable file by that name. Bash uses a + hash table to remember the full filenames of executable files (see + the description of `hash' in *Note Bourne Shell Builtins::) to + avoid multiple `PATH' searches. A full search of the directories + in `$PATH' is performed only if the command is not found in the + hash table. If the search is unsuccessful, the shell prints an + error message and returns a nonzero exit status. + + 4. If the search is successful, or if the command name contains one + or more slashes, the shell executes the named program. Argument 0 + is set to the name given, and the remaining arguments to the + command are set to the arguments supplied, if any. + + 5. If this execution fails because the file is not in executable + format, and the file is not a directory, it is assumed to be SHELL + SCRIPT (*note Shell Scripts::.). + + +File: bashref.info, Node: Environment, Next: Exit Status, Prev: Command Search and Execution, Up: Executing Commands + +Environment +----------- + + When a program is invoked it is given an array of strings called the +ENVIRONMENT. This is a list of name-value pairs, of the form +`name=value'. + + Bash allows you to manipulate the environment in several ways. On +invocation, the shell scans its own environment and creates a parameter +for each name found, automatically marking it for EXPORT to child +processes. Executed commands inherit the environment. The `export' +and `declare -x' commands allow parameters and functions to be added to +and deleted from the environment. If the value of a parameter in the +environment is modified, the new value becomes part of the environment, +replacing the old. The environment inherited by any executed command +consists of the shell's initial environment, whose values may be +modified in the shell, less any pairs removed by the `unset' command, +plus any additions via the `export' and `declare -x' commands. + + The environment for any simple command or function may be augmented +temporarily by prefixing it with parameter assignments, as described in +*Note Shell Parameters::. These assignment statements affect only the +environment seen by that command. + + If the `-k' flag is set (*note The Set Builtin::., then all +parameter assignments are placed in the environment for a command, not +just those that precede the command name. + + When Bash invokes an external command, the variable `$_' is set to +the full path name of the command and passed to that command in its +environment. + + +File: bashref.info, Node: Exit Status, Next: Signals, Prev: Environment, Up: Executing Commands + +Exit Status +----------- + + For the purposes of the shell, a command which exits with a zero +exit status has succeeded. A non-zero exit status indicates failure. +This seemingly counter-intuitive scheme is used so there is one +well-defined way to indicate success and a variety of ways to indicate +various failure modes. When a command terminates on a fatal signal +whose number is N, Bash uses the value 128+N as the exit status. + + If a command is not found, the child process created to execute it +returns a status of 127. If a command is found but is not executable, +the return status is 126. + + The exit status is used by the Bash conditional commands (*note +Conditional Constructs::.) and some of the list constructs (*note +Lists::.). + + All of the Bash builtins return an exit status of zero if they +succeed and a non-zero status on failure, so they may be used by the +conditional and list constructs. + + +File: bashref.info, Node: Signals, Prev: Exit Status, Up: Executing Commands + +Signals +------- + + When Bash is interactive, it ignores `SIGTERM' (so that `kill 0' +does not kill an interactive shell), and `SIGINT' is caught and handled +(so that the `wait' builtin is interruptible). When Bash receives a +`SIGINT', it breaks out of any executing loops. In all cases, Bash +ignores `SIGQUIT'. If job control is in effect (*note Job Control::.), +Bash ignores `SIGTTIN', `SIGTTOU', and `SIGTSTP'. + + Synchronous jobs started by Bash have signals set to the values +inherited by the shell from its parent. When job control is not in +effect, background jobs (commands terminated with `&') ignore `SIGINT' +and `SIGQUIT'. Commands run as a result of command substitution ignore +the keyboard-generated job control signals `SIGTTIN', `SIGTTOU', and +`SIGTSTP'. + + The shell exits by default upon receipt of a `SIGHUP'. Before +exiting, it resends the `SIGHUP' to all jobs, running or stopped. To +prevent the shell from sending the `SIGHUP' signal to a particular job, +remove it from the jobs table with the `disown' builtin (*note Job +Control Builtins::.) or use `disown -h' to mark it to not receive +`SIGHUP'. + + +File: bashref.info, Node: Shell Scripts, Prev: Executing Commands, Up: Basic Shell Features + +Shell Scripts +============= + + A shell script is a text file containing shell commands. When such +a file is used as the first non-option argument when invoking Bash, and +neither the `-c' nor `-s' option is supplied (*note Invoking Bash::.), +Bash reads and executes commands from the file, then exits. This mode +of operation creates a non-interactive shell. When Bash runs a shell +script, it sets the special parameter `0' to the name of the file, +rather than the name of the shell, and the positional parameters are +set to the remaining arguments, if any are given. If no additional +arguments are supplied, the positional parameters are unset. + + A shell script may be made executable by using the `chmod' command +to turn on the execute bit. When Bash finds such a file while +searching the `$PATH' for a command, it spawns a subshell to execute +it. In other words, executing + filename ARGUMENTS + +is equivalent to executing + bash filename ARGUMENTS + +if `filename' is an executable shell script. This subshell +reinitializes itself, so that the effect is as if a new shell had been +invoked to interpret the script. + + Most versions of Unix make this a part of the kernel's command +execution mechanism. If the first line of a script begins with the two +characters `#!', the remainder of the line specifies an interpreter for +the program. The arguments to the interpreter consist of a single +optional argument following the interpreter name on the first line of +the script file, followed by the name of the script file, followed by +the rest of the arguments. Bash will perform this action on operating +systems that do not handle it themselves. Note that some older +versions of Unix limit the interpreter name and argument to a maximum +of 32 characters. + + +File: bashref.info, Node: Bourne Shell Features, Next: Csh Features, Prev: Basic Shell Features, Up: Top + +Bourne Shell Style Features +*************************** + +* Menu: + +* Bourne Shell Builtins:: Builtin commands inherited from the Bourne + Shell. +* Bourne Shell Variables:: Variables which Bash uses in the same way + as the Bourne Shell. +* Other Bourne Shell Features:: Addtional aspects of Bash which behave in + the same way as the Bourne Shell. + + This section briefly summarizes things which Bash inherits from the +Bourne Shell: builtins, variables, and other features. It also lists +the significant differences between Bash and the Bourne Shell. + + +File: bashref.info, Node: Bourne Shell Builtins, Next: Bourne Shell Variables, Up: Bourne Shell Features + +Bourne Shell Builtins +===================== + + The following shell builtin commands are inherited from the Bourne +Shell. These commands are implemented as specified by the POSIX 1003.2 +standard. + +`:' + : [ARGUMENTS] + Do nothing beyond expanding ARGUMENTS and performing redirections. + +`.' + . FILENAME + Read and execute commands from the FILENAME argument in the + current shell context. + +`break' + break [N] + Exit from a `for', `while', `until', or `select' loop. If N is + supplied, the Nth enclosing loop is exited. + +`cd' + cd [-LP] [DIRECTORY] + Change the current working directory to DIRECTORY. If DIRECTORY + is not given, the value of the `HOME' shell variable is used. If + the shell variable `CDPATH' exists, it is used as a search path. + If DIRECTORY begins with a slash, `CDPATH' is not used. The `-P' + option means to not follow symbolic links; symlinks are followed + by default or with the `-L' option. + +`continue' + continue [N] + Resume the next iteration of an enclosing `for', `while', `until', + or `select' loop. If N is supplied, the execution of the Nth + enclosing loop is resumed. + +`eval' + eval [ARGUMENTS] + The arguments are concatenated together into a single command, + which is then read and executed. + +`exec' + exec [-cl] [-a NAME] [COMMAND] [ARGUMENTS] + If COMMAND is supplied, it replaces the shell. If the `-l' option + is supplied, the shell places a dash in the zeroth arg passed to + COMMAND. This is what the `login' program does. The `-c' option + causes COMMAND to be executed with an empty environment. If `-a' + is supplied, the shell passes NAME as the zeroth argument to + COMMAND. If no COMMAND is specified, redirections may be used to + affect the current shell environment. + +`exit' + exit [N] + Exit the shell, returning a status of N to the shell's parent. + +`export' + export [-fn] [-p] [NAME[=VALUE]] + Mark each NAME to be passed to child processes in the environment. + If the `-f' option is supplied, the NAMEs refer to shell + functions. The `-n' option means to no longer mark each NAME for + export. If no NAMES are supplied, or if the `-p' option is given, + a list of exported names is displayed. + +`getopts' + getopts OPTSTRING NAME [ARGS] + `getopts' is used by shell scripts to parse positional parameters. + OPTSTRING contains the option letters to be recognized; if a letter + is followed by a colon, the option is expected to have an + argument, which should be separated from it by white space. Each + time it is invoked, `getopts' places the next option in the shell + variable NAME, initializing NAME if it does not exist, and the + index of the next argument to be processed into the variable + `OPTIND'. `OPTIND' is initialized to 1 each time the shell or a + shell script is invoked. When an option requires an argument, + `getopts' places that argument into the variable `OPTARG'. The + shell does not reset `OPTIND' automatically; it must be manually + reset between multiple calls to `getopts' within the same shell + invocation if a new set of parameters is to be used. + + `getopts' can report errors in two ways. If the first character of + OPTSTRING is a colon, SILENT error reporting is used. In normal + operation diagnostic messages are printed when illegal options or + missing option arguments are encountered. If the variable `OPTERR' + is set to 0, no error message will be displayed, even if the first + character of `optstring' is not a colon. + + If an illegal option is seen, `getopts' places `?' into NAME and, + if not silent, prints an error message and unsets `OPTARG'. If + `getopts' is silent, the option character found is placed in + `OPTARG' and no diagnostic message is printed. + + If a required argument is not found, and `getopts' is not silent, + a question mark (`?') is placed in NAME, `OPTARG' is unset, and a + diagnostic message is printed. If `getopts' is silent, then a + colon (`:') is placed in NAME and `OPTARG' is set to the option + character found. + + `getopts' normally parses the positional parameters, but if more + arguments are given in ARGS, `getopts' parses those instead. + +`hash' + hash [-r] [-p FILENAME] [NAME] + Remember the full filenames of commands specified as arguments, so + they need not be searched for on subsequent invocations. The + commands are found by searching through the directories listed in + `$PATH'. The `-p' option inhibits the path search, and FILENAME + is used as the location of NAME. The `-r' option causes the shell + to forget all remembered locations. If no arguments are given, + information about remembered commands is printed. + +`pwd' + pwd [-LP] + Print the current working directory. If the `-P' option is + supplied, the path printed will not contain symbolic links. If + the `-L' option is supplied, the path printed may contain symbolic + links. + +`readonly' + readonly [-apf] [NAME] ... + Mark each NAME as unchangable. The values of these names may not + be changed by subsequent assignment. If the `-f' option is + supplied, each NAME refers to a shell function. The `-a' option + means each NAME refers to an array variable. If no NAME arguments + are given, or if the `-p' option is supplied, a list of all + readonly names is printed. + +`return' + return [N] + Cause a shell function to exit with value N. This may also be used + to terminate execution of a script being executed with the `.' + builtin. + +`shift' + shift [N] + Shift positional parameters to the left by N. The positional + parameters from N+1 ... are renamed to `$1' ... . Parameters + represented by the numbers `$#' to N+1 are unset. N must be a + non-negative number less than or equal to `$#'. + +`test' +`[' + Evaluate a conditional expression (*note Bash Conditional + Expressions::.). + +`times' + times + Print out the user and system times used by the shell and its + children. + +`trap' + trap [-lp] [ARG] [SIGSPEC] + The commands in ARG are to be read and executed when the shell + receives signal SIGSPEC. If ARG is absent or equal to `-', all + specified signals are reset to the values they had when the shell + was started. If ARG is the null string, then SIGSPEC is ignored by + the shell and commands it invokes. If ARG is `-p', the shell + displays the trap commands associated with each SIGSPEC. If no + arguments are supplied, or only `-p' is given, `trap' prints the + list of commands associated with each signal number. SIGSPEC is + either a signal name such as `SIGINT' or a signal number. If + SIGSPEC is `0' or `EXIT', ARG is executed when the shell exits. + If SIGSPEC is `DEBUG', the command ARG is executed after every + simple command. The `-l' option causes the shell to print a list + of signal names and their corresponding numbers. + + Signals ignored upon entry to the shell cannot be trapped or reset. + Trapped signals are reset to their original values in a child + process when it is created. + +`umask' + umask [-S] [MODE] + Set the shell process's file creation mask to MODE. If MODE + begins with a digit, it is interpreted as an octal number; if not, + it is interpreted as a symbolic mode mask similar to that accepted + by the `chmod' command. If MODE is omitted, the current value of + the mask is printed. If the `-S' option is supplied without a + MODE argument, the mask is printed in a symbolic format. + +`unset' + unset [-fv] [NAME] + Each variable or function NAME is removed. If no options are + supplied, or the `-v' option is given, each NAME refers to a shell + variable. If the `-f' option is given, the NAMEs refer to shell + functions, and the function definition is removed. Read-only + variables and functions may not be unset. + + +File: bashref.info, Node: Bourne Shell Variables, Next: Other Bourne Shell Features, Prev: Bourne Shell Builtins, Up: Bourne Shell Features + +Bourne Shell Variables +====================== + + Bash uses certain shell variables in the same way as the Bourne +shell. In some cases, Bash assigns a default value to the variable. + +`IFS' + A list of characters that separate fields; used when the shell + splits words as part of expansion. + +`PATH' + A colon-separated list of directories in which the shell looks for + commands. + +`HOME' + The current user's home directory; the default for the `cd' builtin + command. + +`CDPATH' + A colon-separated list of directories used as a search path for + the `cd' command. + +`MAILPATH' + A colon-separated list of files which the shell periodically checks + for new mail. You can also specify what message is printed by + separating the file name from the message with a `?'. When used + in the text of the message, `$_' stands for the name of the + current mailfile. + +`MAIL' + If this parameter is set to a filename and the `MAILPATH' variable + is not set, Bash informs the user of the arrival of mail in the + specified file. + +`PS1' + The primary prompt string. The default value is `\s-\v\$ '. + +`PS2' + The secondary prompt string. The default value is `> '. + +`OPTIND' + The index of the last option processed by the `getopts' builtin. + +`OPTARG' + The value of the last option argument processed by the `getopts' + builtin. + + +File: bashref.info, Node: Other Bourne Shell Features, Prev: Bourne Shell Variables, Up: Bourne Shell Features + +Other Bourne Shell Features +=========================== + +* Menu: + +* Major Differences From The Bourne Shell:: Major differences between + Bash and the Bourne shell. + + Bash implements essentially the same grammar, parameter and variable +expansion, redirection, and quoting as the Bourne Shell. Bash uses the +POSIX 1003.2 standard as the specification of how these features are to +be implemented. There are some differences between the traditional +Bourne shell and the POSIX standard; this section quickly details the +differences of significance. A number of these differences are +explained in greater depth in subsequent sections. + + +File: bashref.info, Node: Major Differences From The Bourne Shell, Up: Other Bourne Shell Features + +Major Differences From The SVR4.2 Bourne Shell +---------------------------------------------- + + Bash is POSIX-conformant, even where the POSIX specification differs +from traditional `sh' behavior. + + Bash has multi-character invocation options (*note Invoking Bash::.). + + Bash has command-line editing (*note Command Line Editing::.) and +the `bind' builtin. + + Bash has command history (*note Bash History Facilities::.) and the +`history' and `fc' builtins to manipulate it. + + Bash implements `csh'-like history expansion (*note History +Interaction::.). + + Bash has one-dimensional array variables (*note Arrays::.), and the +appropriate variable expansions and assignment syntax to use them. +Some of the Bash builtins take options to act on arrays. Bash provides +some built-in array variables. + + Bash implements the `!' keyword to negate the return value of a +pipeline (*note Pipelines::.). Very useful when an `if' statement +needs to act only if a test fails. + + Bash includes the `select' compound command, which allows the +generation of simple menus (*note Korn Shell Constructs::.). + + Bash includes brace expansion (*note Brace Expansion::.) and tilde +expansion (*note Tilde Expansion::.). + + Bash implements command aliases and the `alias' and `unalias' +builtins (*note Aliases::.). + + Bash provides shell arithmetic and arithmetic expansion (*note Shell +Arithmetic::.). + + The POSIX and `ksh'-style `$()' form of command substitution is +implemented (*note Command Substitution::.), and preferred to the +Bourne shell's ```' (which is also implemented for backwards +compatibility). + + Variables present in the shell's initial environment are +automatically exported to child processes. The Bourne shell does not +normally do this unless the variables are explicitly marked using the +`export' command. + + Bash includes the POSIX and `ksh'-style pattern removal `%', `#', +`%%' and `##' constructs to remove leading or trailing substrings from +variable values (*note Shell Parameter Expansion::.). + + The expansion `${#xx}', which returns the length of `$xx', is +supported (*note Shell Parameter Expansion::.). + + The `$'...'' quoting syntax, which expands ANSI-C backslash-escaped +characters in the text between the single quotes, is supported (*note +ANSI-C Quoting::.). + + Bash supports the `$"..."' quoting syntax to do locale-specific +translation of the characters between the double quotes. The `-D' and +`--dump-strings' invocation options list the translatable strings found +in a script (*note Locale Translation::.). + + The expansion `${var:'LENGTH`[:'OFFSET`]}', which expands to the +substring of `var''s value of length LENGTH, optionally beginning at +OFFSET, is present (*note Shell Parameter Expansion::.). + + The expansion `${var/[/]'PATTERN`[/'REPLACEMENT`]}', which matches +PATTERN and replaces it with REPLACEMENT in the value of `var', is +available (*note Shell Parameter Expansion::.). + + Bash has INDIRECT variable expansion using `${!word}' (*note Shell +Parameter Expansion::.). + + Bash can expand positional parameters beyond `$9' using `${NUM}'. + + Bash has process substitution (*note Process Substitution::.). + + Bash automatically assigns variables that provide information about +the current user (`UID' and `EUID'), the current host (`HOSTTYPE', +`OSTYPE', `MACHTYPE', and `HOSTNAME'), and the instance of Bash that is +running (`BASH', `BASH_VERSION', and `BASH_VERSINFO'. *Note Bash +Variables::, for details. + + The `IFS' variable is used to split only the results of expansion, +not all words (*note Word Splitting::.). This closes a longstanding +shell security hole. + + It is possible to have a variable and a function with the same name; +`sh' does not separate the two name spaces. + + Bash functions are permitted to have local variables using the +`local' builtin, and thus useful recursive functions may be written. + + Variable assignments preceding commands affect only that command, +even builtins and functions. In `sh', all variable assignments +preceding commands are global unless the command is executed from the +file system. + + Bash performs filename expansion on filenames specified as operands +to output redirection operators. + + Bash contains the `<>' redirection operator, allowing a file to be +opened for both reading and writing, and the `&>' redirection operator, +for directing standard output and standard error to the same file +(*note Redirections::.). + + The `noclobber' option is available to avoid overwriting existing +files with output redirection (*note The Set Builtin::.). The `>|' +redirection operator may be used to override `noclobber'. + + Bash interprets special backslash-escaped characters in the prompt +strings when interactive (*note Printing a Prompt::.). + + Bash allows you to write a function to override a builtin, and +provides access to that builtin's functionality within the function via +the `builtin' and `command' builtins (*note Bash Builtins::.). + + The `command' builtin allows selective disabling of functions when +command lookup is performed (*note Bash Builtins::.). + + Individual builtins may be enabled or disabled using the `enable' +builtin (*note Bash Builtins::.). + + The Bash `hash' builtin allows a name to be associated with an +arbitrary filename, even when that filename cannot be found by +searching the `$PATH', using `hash -p'. + + Shell functions may be exported to children via the environment +(*note Shell Functions::.). + + Bash includes a `help' builtin for quick reference to shell +facilities (*note Bash Builtins::.). + + The Bash `read' builtin (*note Bash Builtins::.) will read a line +ending in `\' with the `-r' option, and will use the `REPLY' variable +as a default if no arguments are supplied. The Bash `read' builtin +also accepts a prompt string with the `-p' option and will use Readline +to obtain the line when given the `-e' option. + + Bash includes the `shopt' builtin, for finer control of shell +optional capabilities (*note Bash Builtins::.). + + Bash has much more optional behavior controllable with the `set' +builtin (*note The Set Builtin::.). + + The `disown' builtin can remove a job from the internal shell job +table (*note Job Control Builtins::.). + + The `return' builtin may be used to abort execution of scripts +executed with the `.' or `source' builtins (*note Bourne Shell +Builtins::.). + + The `test' builtin (*note Bourne Shell Builtins::.) is slightly +different, as it implements the POSIX 1003.2 algorithm, which specifies +the behavior based on the number of arguments. + + The `trap' builtin (*note Bourne Shell Builtins::.) allows a `DEBUG' +pseudo-signal specification, similar to `EXIT'. Commands specified +with a `DEBUG' trap are executed after every simple command. The +`DEBUG' trap is not inherited by shell functions. + + The Bash `export', `readonly', and `declare' builtins can take a +`-f' option to act on shell functions, a `-p' option to display +variables with various attributes set in a format that can be used as +shell input, a `-n' option to remove various variable attributes, and +`name=value' arguments to set variable attributes and values +simultaneously. + + The Bash `cd' and `pwd' builtins each take `-L' and `-P' builtins to +switch between logical and physical modes. + + The Bash `type' builtin is more extensive and gives more information +about the names it finds. + + Bash implements a `csh'-like directory stack, and provides the +`pushd', `popd', and `dirs' builtins to manipulate it. Bash also makes +the directory stack visible as the value of the `DIRSTACK' shell +variable. + + The Bash restricted mode is more useful (*note The Restricted +Shell::.); the SVR4.2 shell restricted mode is too limited. + + Bash has the `time' reserved word and command timing (*note +Pipelines::.). The display of the timing statistics may be controlled +with the `TIMEFORMAT' variable. + + The SVR4.2 shell has two privilege-related builtins (`mldmode' and +`priv') not present in Bash. + + Bash does not have the `stop' or `newgrp' builtins. + + Bash does not use the `SHACCT' variable or perform shell accounting. + + The SVR4.2 `sh' uses a `TIMEOUT' variable like Bash uses `TMOUT'. + + More features unique to Bash may be found in *Note Bash Features::. + +Implementation Differences From The SVR4.2 Shell +------------------------------------------------ + + Since Bash is a completely new implementation, it does not suffer +from many of the limitations of the SVR4.2 shell. For instance: + + * Bash does not fork a subshell when redirecting into or out of a + shell control structure such as an `if' or `while' statement. + + * Bash does not allow unbalanced quotes. The SVR4.2 shell will + silently insert a needed closing quote at `EOF' under certain + circumstances. This can be the cause of some hard-to-find errors. + + * The SVR4.2 shell uses a baroque memory management scheme based on + trapping `SIGSEGV'. If the shell is started from a process with + `SIGSEGV' blocked (e.g., by using the `system()' C library + function call), the shell misbehaves badly. + + * In a questionable attempt at security, the SVR4.2 shell will alter + its real and effective UID and GID if they are less than some + threshold value, commonly 100. This can lead to unexpected + results. + + * The SVR4.2 shell does not allow users to trap `SIGALRM' or + `SIGCHLD'. + + * For some reason, the SVR4.2 shell does not allow the `MAILCHECK' + variable to be unset. + + * The SVR4.2 shell treats `^' as the undocumented equivalent of `|'. + + * Bash allows multiple option arguments when it is invoked (`-x -v'); + the SVR4.2 shell allows only one option argument (`-xv'). In + fact, some versions of the shell dump core if the second argument + begins with a `-'. + + * The SVR4.2 shell exits a script if any builtin fails; Bash exits a + script only if one of the POSIX.2 special builtins fails, and only + for certain failures, as enumerated in the `POSIX.2' standard. + + * The SVR4.2 shell behaves differently when invoked as `jsh' (it + turns on job control). + + +File: bashref.info, Node: Csh Features, Next: Korn Shell Features, Prev: Bourne Shell Features, Up: Top + +C-Shell Style Features +********************** + + The C-Shell ("`csh'") was created by Bill Joy at The University of +California at Berkeley. It is generally considered to have better +features for interactive use than the original Bourne shell. Some of +the `csh' features present in Bash include job control, history +expansion, `protected' redirection, and several variables to control +the interactive behaviour of the shell (e.g., `IGNOREEOF'). + + *Note Using History Interactively::, for details on history +expansion. + +* Menu: + +* Brace Expansion:: Expansion of expressions within braces. +* Tilde Expansion:: Expansion of the ~ character. +* C Shell Builtins:: Builtin commands adopted from the C Shell. +* C Shell Variables:: Variables which Bash uses in essentially + the same way as the C Shell. + + +File: bashref.info, Node: Brace Expansion, Next: Tilde Expansion, Up: Csh Features + +Brace Expansion +=============== + + Brace expansion is a mechanism by which arbitrary strings may be +generated. This mechanism is similar to FILENAME EXPANSION (*note +Filename Expansion::.), but the file names generated need not exist. +Patterns to be brace expanded take the form of an optional PREAMBLE, +followed by a series of comma-separated strings between a pair of +braces, followed by an optional POSTAMBLE. The preamble is prepended +to each string contained within the braces, and the postamble is then +appended to each resulting string, expanding left to right. + + Brace expansions may be nested. The results of each expanded string +are not sorted; left to right order is preserved. For example, + bash$ echo a{d,c,b}e + ade ace abe + + Brace expansion is performed before any other expansions, and any +characters special to other expansions are preserved in the result. It +is strictly textual. Bash does not apply any syntactic interpretation +to the context of the expansion or the text between the braces. + + A correctly-formed brace expansion must contain unquoted opening and +closing braces, and at least one unquoted comma. Any incorrectly +formed brace expansion is left unchanged. + + This construct is typically used as shorthand when the common prefix +of the strings to be generated is longer than in the above example: + mkdir /usr/local/src/bash/{old,new,dist,bugs} + or + chown root /usr/{ucb/{ex,edit},lib/{ex?.?*,how_ex}} + + +File: bashref.info, Node: Tilde Expansion, Next: C Shell Builtins, Prev: Brace Expansion, Up: Csh Features + +Tilde Expansion +=============== + + Bash has tilde (~) expansion, similar, but not identical, to that of +`csh'. The following table shows what unquoted words beginning with a +tilde expand to. + +`~' + The current value of `$HOME'. + +`~/foo' + `$HOME/foo' + +`~fred/foo' + The subdirectory `foo' of the home directory of the user `fred'. + +`~+/foo' + `$PWD/foo' + +`~-/foo' + `$OLDPWD/foo' + + Bash will also tilde expand words following redirection operators +and words following `=' in assignment statements. + + +File: bashref.info, Node: C Shell Builtins, Next: C Shell Variables, Prev: Tilde Expansion, Up: Csh Features + +C Shell Builtins +================ + + Bash has several builtin commands whose definition is very similar +to `csh'. + +`pushd' + pushd [DIR | +N | -N] [-n] + + Save the current directory on a list and then `cd' to DIR. With no + arguments, exchanges the top two directories. + + `+N' + Brings the Nth directory (counting from the left of the list + printed by `dirs') to the top of the list by rotating the + stack. + + `-N' + Brings the Nth directory (counting from the right of the list + printed by `dirs') to the top of the list by rotating the + stack. + + `-n' + Suppresses the normal change of directory when adding + directories to the stack, so that only the stack is + manipulated. + + `DIR' + Makes the current working directory be the top of the stack, + and then `cd's to DIR. You can see the saved directory list + with the `dirs' command. + +`popd' + popd [+N | -N] [-n] + + Pop the directory stack, and `cd' to the new top directory. When + no arguments are given, `popd' removes the top directory from the + stack and performs a `cd' to the new top directory. The elements + are numbered from 0 starting at the first directory listed with + `dirs'; i.e., `popd' is equivalent to `popd +0'. + `+N' + Removes the Nth directory (counting from the left of the list + printed by `dirs'), starting with zero. + + `-N' + Removes the Nth directory (counting from the right of the + list printed by `dirs'), starting with zero. + + `-n' + Suppresses the normal change of directory when removing + directories from the stack, so that only the stack is + manipulated. + +`dirs' + dirs [+N | -N] [-clvp] + Display the list of currently remembered directories. Directories + find their way onto the list with the `pushd' command; you can get + back up through the list with the `popd' command. + `+N' + Displays the Nth directory (counting from the left of the + list printed by `dirs' when invoked without options), starting + with zero. + + `-N' + Displays the Nth directory (counting from the right of the + list printed by `dirs' when invoked without options), starting + with zero. + + `-c' + Clears the directory stack by deleting all of the elements. + + `-l' + Produces a longer listing; the default listing format uses a + tilde to denote the home directory. + + `-p' + Causes `dirs' to print the directory stack with one entry per + line. + + `-v' + Causes `dirs' to print the directory stack with one entry per + line, prepending each entry with its index in the stack. + +`history' + history [-c] [N] + history [-anrw] [FILENAME] + history -ps ARG + + Display the history list with line numbers. Lines prefixed with + with a `*' have been modified. An argument of N says to list only + the last N lines. Options, if supplied, have the following + meanings: + + `-w' + Write out the current history to the history file. + + `-r' + Read the current history file and append its contents to the + history list. + + `-a' + Append the new history lines (history lines entered since the + beginning of the current Bash session) to the history file. + + `-n' + Append the history lines not already read from the history + file to the current history list. These are lines appended + to the history file since the beginning of the current Bash + session. + + `-c' + Clear the history list. This may be combined with the other + options to replace the history list completely. + + `-s' + The ARGs are added to the end of the history list as a single + entry. + + `-p' + Perform history substitution on the ARGs and display the + result on the standard output, without storing the results in + the history list. + + When the `-w', `-r', `-a', or `-n' option is used, if FILENAME is + given, then it is used as the history file. If not, then the + value of the `HISTFILE' variable is used. + +`logout' + Exit a login shell. + +`source' + A synonym for `.' (*note Bourne Shell Builtins::.). + + +File: bashref.info, Node: C Shell Variables, Prev: C Shell Builtins, Up: Csh Features + +C Shell Variables +================= + +`IGNOREEOF' + If this variable is set, its value is used the number of + consecutive `EOF's Bash will read before exiting. By default, + Bash will exit upon reading a single `EOF'. If `IGNOREEOF' is not + set to a numeric value, Bash acts as if its value were 10. + + +File: bashref.info, Node: Korn Shell Features, Next: Bash Features, Prev: Csh Features, Up: Top + +Korn Shell Style Features +************************* + + This section describes features primarily inspired by the Korn Shell +(`ksh'). In some cases, the POSIX 1003.2 standard has adopted these +commands and variables from the Korn Shell; Bash implements those +features using the POSIX standard as a guide. + +* Menu: + +* Korn Shell Constructs:: Shell grammar constructs adopted from the + Korn Shell +* Korn Shell Builtins:: Builtin commands adopted from the Korn Shell. +* Korn Shell Variables:: Variables which Bash uses in essentially + the same way as the Korn Shell. +* Aliases:: Substituting one command for another. + + +File: bashref.info, Node: Korn Shell Constructs, Next: Korn Shell Builtins, Up: Korn Shell Features + +Korn Shell Constructs +===================== + + Bash includes the Korn Shell `select' construct. This construct +allows the easy generation of menus. It has almost the same syntax as +the `for' command. + + The syntax of the `select' command is: + select NAME [in WORDS ...]; do COMMANDS; done + + The list of words following `in' is expanded, generating a list of +items. The set of expanded words is printed on the standard error, +each preceded by a number. If the `in WORDS' is omitted, the +positional parameters are printed. The `PS3' prompt is then displayed +and a line is read from the standard input. If the line consists of a +number corresponding to one of the displayed words, then the value of +NAME is set to that word. If the line is empty, the words and prompt +are displayed again. If `EOF' is read, the `select' command completes. +Any other value read causes NAME to be set to null. The line read is +saved in the variable `REPLY'. + + The COMMANDS are executed after each selection until a `break' or +`return' command is executed, at which point the `select' command +completes. + + Bash also has adopted command timing from the Korn shell. If the +`time' reserved word precedes a pipeline or simple command, timing +statistics for the pipeline are displayed when it completes. The +statistics currently consist of elapsed (wall-clock) time and user and +system time consumed by the command's execution. + + The use of `time' as a reserved word permits the timing of shell +builtins, shell functions, and pipelines. An external `time' command +cannot time these easily. + + +File: bashref.info, Node: Korn Shell Builtins, Next: Korn Shell Variables, Prev: Korn Shell Constructs, Up: Korn Shell Features + +Korn Shell Builtins +=================== + + This section describes Bash builtin commands taken from `ksh'. + +`fc' + `fc [-e ENAME] [-nlr] [FIRST] [LAST]' + `fc -s [PAT=REP] [COMMAND]' + + Fix Command. In the first form, a range of commands from FIRST to + LAST is selected from the history list. Both FIRST and LAST may + be specified as a string (to locate the most recent command + beginning with that string) or as a number (an index into the + history list, where a negative number is used as an offset from the + current command number). If LAST is not specified it is set to + FIRST. If FIRST is not specified it is set to the previous + command for editing and -16 for listing. If the `-l' flag is + given, the commands are listed on standard output. The `-n' flag + suppresses the command numbers when listing. The `-r' flag + reverses the order of the listing. Otherwise, the editor given by + ENAME is invoked on a file containing those commands. If ENAME is + not given, the value of the following variable expansion is used: + `${FCEDIT:-${EDITOR:-vi}}'. This says to use the value of the + `FCEDIT' variable if set, or the value of the `EDITOR' variable if + that is set, or `vi' if neither is set. When editing is complete, + the edited commands are echoed and executed. + + In the second form, COMMAND is re-executed after each instance of + PAT in the selected command is replaced by REP. + + A useful alias to use with the `fc' command is `r='fc -s'', so + that typing `r cc' runs the last command beginning with `cc' and + typing `r' re-executes the last command (*note Aliases::.). + +`let' + The `let' builtin allows arithmetic to be performed on shell + variables. For details, refer to *Note Arithmetic Builtins::. + +`typeset' + The `typeset' command is supplied for compatibility with the Korn + shell; however, it has been deprecated in favor of the `declare' + command (*note Bash Builtins::.). + + +File: bashref.info, Node: Korn Shell Variables, Next: Aliases, Prev: Korn Shell Builtins, Up: Korn Shell Features + +Korn Shell Variables +==================== + +`REPLY' + The default variable for the `read' builtin. + +`RANDOM' + Each time this parameter is referenced, a random integer between 0 + and 32767 is generated. Assigning a value to this variable seeds + the random number generator. + +`SECONDS' + This variable expands to the number of seconds since the shell was + started. Assignment to this variable resets the count to the + value assigned, and the expanded value becomes the value assigned + plus the number of seconds since the assignment. + +`PS3' + The value of this variable is used as the prompt for the `select' + command. If this variable is not set, the `select' command + prompts with `#? ' + +`PS4' + This is the prompt printed before the command line is echoed when + the `-x' option is set (*note The Set Builtin::.). The default is + `+ '. + +`PWD' + The current working directory as set by the `cd' builtin. + +`OLDPWD' + The previous working directory as set by the `cd' builtin. + +`TMOUT' + If set to a value greater than zero, the value is interpreted as + the number of seconds to wait for input after issuing the primary + prompt. Bash terminates after that number of seconds if input does + not arrive. + +`LINENO' + The line number in the script or shell function currently + executing. + +`ENV' + If this variable is set when Bash is invoked to execute a shell + script, its value is expanded and used as the name of a startup + file to read before executing the script. *Note Bash Startup + Files::. + +`FCEDIT' + The editor used as a default by the `fc' builtin command. + + +File: bashref.info, Node: Aliases, Prev: Korn Shell Variables, Up: Korn Shell Features + +Aliases +======= + +* Menu: + +* Alias Builtins:: Builtins commands to maniuplate aliases. + + The shell maintains a list of ALIASES that may be set and unset with +the `alias' and `unalias' builtin commands. + + 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 alias name and the replacement text may contain any valid shell +input, including shell metacharacters, with the exception that the +alias name may not contain =. 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 +`ls' to `"ls -F"', for instance, and Bash does not try to recursively +expand the replacement text. If the last character of the alias value +is a space or tab character, then the next command word following the +alias is also checked for alias expansion. + + Aliases are created and listed with the `alias' command, and removed +with the `unalias' command. + + There is no mechanism for using arguments in the replacement text, +as in `csh'. If arguments are needed, a shell function should be used +(*note Shell Functions::.). + + Aliases are not expanded when the shell is not interactive, unless +the `expand_aliases' shell option is set using `shopt' (*note Bash +Builtins::.). + + The rules concerning the definition and use of aliases are somewhat +confusing. Bash always reads at least one complete line of input +before executing any of the commands on that line. Aliases are +expanded when a command is read, not when it is executed. Therefore, an +alias definition appearing on the same line as another command does not +take effect until the next line of input is read. The commands +following the alias definition on that line are not affected by the new +alias. This behavior is also an issue when functions are executed. +Aliases are expanded when the function definition is read, not when the +function is executed, because a function definition is itself a +compound command. As a consequence, aliases defined in a function are +not available until after that function is executed. To be safe, +always put alias definitions on a separate line, and do not use `alias' +in compound commands. + + Note that for almost every purpose, aliases are superseded by shell +functions. + + +File: bashref.info, Node: Alias Builtins, Up: Aliases + +Alias Builtins +-------------- + +`alias' + alias [`-p'] [NAME[=VALUE] ...] + + Without arguments or with the `-p' option, `alias' prints the list + of aliases on the standard output in a form that allows them to be + reused as input. If arguments are supplied, an alias is defined + for each NAME whose VALUE is given. If no VALUE is given, the name + and value of the alias is printed. + +`unalias' + unalias [-a] [NAME ... ] + + Remove each NAME from the list of aliases. If `-a' is supplied, + all aliases are removed. + + +File: bashref.info, Node: Bash Features, Next: Job Control, Prev: Korn Shell Features, Up: Top + +Bash Features +************* + + This section describes features unique to Bash. + +* Menu: + +* Invoking Bash:: Command line options that you can give + to Bash. +* Bash Startup Files:: When and how Bash executes scripts. +* Is This Shell Interactive?:: Determining the state of a running Bash. +* Bash Builtins:: Table of builtins specific to Bash. +* The Set Builtin:: This builtin is so overloaded it + deserves its own section. +* Bash Conditional Expressions:: Primitives used in composing expressions for + the `test' builtin. +* Bash Variables:: List of variables that exist in Bash. +* Shell Arithmetic:: Arithmetic on shell variables. +* Arrays:: Array Variables +* Printing a Prompt:: Controlling the PS1 string. +* The Restricted Shell:: A more controlled mode of shell execution. +* Bash POSIX Mode:: Making Bash behave more closely to what + the POSIX standard specifies. + + +File: bashref.info, Node: Invoking Bash, Next: Bash Startup Files, Up: Bash Features + +Invoking Bash +============= + + bash [long-opt] [-ir] [-abefhkmnptuvxdBCDHP] [-o OPTION] [ARGUMENT ...] + bash [long-opt] [-abefhkmnptuvxdBCDHP] [-o OPTION] -c STRING [ARGUMENT ...] + bash [long-opt] -s [-abefhkmnptuvxdBCDHP] [-o OPTION] [ARGUMENT ...] + + In addition to the single-character shell command-line options +(*note The Set Builtin::.), there are several multi-character options +that you can use. These options must appear on the command line before +the single-character options in order for them to be recognized. + +`--dump-strings' + Equivalent to `-D'. + +`--help' + Display a usage message on standard output and exit sucessfully. + +`--login' + Make this shell act as if it were directly invoked by login. This + is equivalent to `exec -l bash' but can be issued from another + shell, such as `csh'. If you wanted to replace your current login + shell with a Bash login shell, you would say `exec bash --login'. + +`--noediting' + Do not use the GNU Readline library (*note Command Line Editing::.) + to read interactive command lines. + +`--noprofile' + Don't load the system-wide startup file `/etc/profile' or any of + the personal initialization files `~/.bash_profile', + `~/.bash_login', or `~/.profile' when Bash is invoked as a login + shell. + +`--norc' + Don't read the `~/.bashrc' initialization file in an interactive + shell. This is on by default if the shell is invoked as `sh'. + +`--posix' + Change the behavior of Bash where the default operation differs + from the POSIX 1003.2 standard to match the standard. This is + intended to make Bash behave as a strict superset of that + standard. *Note Bash POSIX Mode::, for a description of the Bash + POSIX mode. + +`--rcfile FILENAME' + Execute commands from FILENAME (instead of `~/.bashrc') in an + interactive shell. + +`--restricted' + Make the shell a restricted shell (*note The Restricted Shell::.). + +`--verbose' + Equivalent to `-v'. + +`--version' + Show version information for this instance of Bash on the standard + output and exit successfully. + + There are several single-character options you can give which are +not available with the `set' builtin. + +`-c STRING' + Read and execute commands from STRING after processing the + options, then exit. Any remaining arguments are assigned to the + positional parameters, starting with `$0'. + +`-i' + Force the shell to run interactively. + +`-r' + Make the shell restricted. + +`-s' + If this flag is present, or if no arguments remain after option + processing, then commands are read from the standard input. This + option allows the positional parameters to be set when invoking an + interactive shell. + +`-D' + A list of all double-quoted strings preceded by `$' is printed on + the standard ouput. These are the strings that are subject to + language translation when the current locale is not `C' or `POSIX' + (*note Locale Translation::.). This implies the `-n' option; no + commands will be executed. + + An *interactive* shell is one whose input and output are both +connected to terminals (as determined by `isatty()'), or one started +with the `-i' option. + + If arguments remain after option processing, and neither the `-c' +nor the `-s' option has been supplied, the first argument is assumed to +be the name of a file containing shell commands (*note Shell +Scripts::.). When Bash is invoked in this fashion, `$0' is set to the +name of the file, and the positional parameters are set to the +remaining arguments. Bash reads and executes commands from this file, +then exits. Bash's exit status is the exit status of the last command +executed in the script. If no commands are executed, the exit status +is 0. + + +File: bashref.info, Node: Bash Startup Files, Next: Is This Shell Interactive?, Prev: Invoking Bash, Up: Bash Features + +Bash Startup Files +================== + + This section describs how bash executes its startup files. If any +of the files exist but cannot be read, bash reports an error. Tildes +are expanded in file names as described above under Tilde Expansion +(*note Tilde Expansion::.). + + When Bash is invoked as a login shell, it first reads and executes +commands from the file `/etc/profile', if that file exists. After +reading that file, it looks for `~/.bash_profile', `~/.bash_login', and +`~/.profile', in that order, and reads and executes commands from the +first one that exists and is readable. The `--noprofile' option may be +used when the shell is started to inhibit this behavior. + + When a login shell exits, Bash reads and executes commands from the +file `~/.bash_logout', if it exists. + + When an interactive shell that is not a login shell is started, Bash +reads and executes commands from `~/.bashrc', if that file exists. +This may be inhibited by using the `--norc' option. The `--rcfile +FILE' option will force Bash to read and execute commands from FILE +instead of `~/.bashrc'. + + So, typically, your `~/.bash_profile' contains the line + `if [ -f `~/.bashrc' ]; then . `~/.bashrc'; fi' + +after (or before) any login-specific initializations. + + When Bash is started non-interactively, to run a shell script, for +example, it looks for the variable `BASH_ENV' in the environment, +expands its value if it appears there, and uses the expanded value as +the name of a file to read and execute. Bash behaves as if the +following command were executed: + `if [ -n "$BASH_ENV" ]; then . "$BASH_ENV"; fi' + +but the value of the `PATH' variable is not used to search for the file +name. + + If Bash is invoked with the name `sh', it tries to mimic the startup +behavior of historical versions of `sh' as closely as possible, while +conforming to the POSIX standard as well. + + When invoked as a login shell, it first attempts to read and execute +commands from `/etc/profile' and `~/.profile', in that order. The +`--noprofile' option may be used to inhibit this behavior. When +invoked as an interactive shell with the name `sh', `bash' looks for +the variable `ENV', expands its value if it is defined, and uses the +expanded value as the name of a file to read and execute. Since a +shell invoked as `sh' does not attempt to read and execute commands +from any other startup files, the `--rcfile' option has no effect. A +non-interactive shell invoked with the name `sh' does not attempt to +read any startup files. + + When invoked as `sh', Bash enters POSIX mode after the startup files +are read. + + When Bash is started in POSIX mode, as with the `--posix' command +line option, it follows the POSIX standard for startup files. In this +mode, the `ENV' variable is expanded and commands are read and executed +from the file whose name is the expanded value. No other startup files +are read. This is done by both interactive and non-interactive shells. + + Bash attempts to determine when it is being run by the remote shell +daemon, usually `rshd'. If Bash determines it is being run by rshd, it +reads and executes commands from `~/.bashrc', if that file exists and +is readable. It will not do this if invoked as `sh'. The `--norc' +option may be used to inhibit this behavior, and the `--rcfile' option +may be used to force another file to be read, but rshd does not +generally invoke the shell with those options or allow them to be +specified. + + +File: bashref.info, Node: Is This Shell Interactive?, Next: Bash Builtins, Prev: Bash Startup Files, Up: Bash Features + +Is This Shell Interactive? +========================== + + As defined in *Note Invoking Bash::, an interactive shell is one +whose input and output are both connected to terminals (as determined +by `isatty(3)'), or one started with the `-i' option. + + You may wish to determine within a startup script whether Bash is +running interactively or not. To do this, examine the variable `$PS1'; +it is unset in non-interactive shells, and set in interactive shells. +Thus: + + if [ -z "$PS1" ]; then + echo This shell is not interactive + else + echo This shell is interactive + fi + + +File: bashref.info, Node: Bash Builtins, Next: The Set Builtin, Prev: Is This Shell Interactive?, Up: Bash Features + +Bash Builtin Commands +===================== + + This section describes builtin commands which are unique to or have +been extended in Bash. + +`bind' + bind [-m KEYMAP] [-lpsvPSV] [-q NAME] [-r KEYSEQ] + bind [-m KEYMAP] -f FILENAME + bind [-m KEYMAP] KEYSEQ:FUNCTION-NAME + + Display current Readline (*note Command Line Editing::.) key and + function bindings, or bind a key sequence to a Readline function + or macro. The binding syntax accepted is identical to that of + `.inputrc' (*note Readline Init File::.), but each binding must be + passed as a separate argument: e.g., + `"\C-x\C-r":re-read-init-file'. Options, if supplied, have the + following meanings: + + `-m KEYMAP' + Use KEYMAP as the keymap to be affected by the subsequent + bindings. Acceptable KEYMAP names are `emacs', + `emacs-standard', `emacs-meta', `emacs-ctlx', `vi', + `vi-command', and `vi-insert'. `vi' is equivalent to + `vi-command'; `emacs' is equivalent to `emacs-standard'. + + `-l' + List the names of all Readline functions + + `-p' + Display Readline function names and bindings in such a way + that they can be re-read + + `-P' + List current Readline function names and bindings + + `-v' + Display Readline variable names and values in such a way that + they can be re-read + + `-V' + List current Readline variable names and values + + `-s' + Display Readline key sequences bound to macros and the + strings they output in such a way that they can be re-read + + `-S' + Display Readline key sequences bound to macros and the + strings they output + + `-f FILENAME' + Read key bindings from FILENAME + + `-q' + Query about which keys invoke the named FUNCTION + + `-r KEYSEQ' + Remove any current binding for KEYSEQ + +`builtin' + builtin [SHELL-BUILTIN [ARGS]] + Run a shell builtin. This is useful when you wish to rename a + shell builtin to be a function, but need the functionality of the + builtin within the function itself. + +`command' + command [-pVv] COMMAND [ARGS ...] + Runs COMMAND with ARG ignoring shell functions. If you have a + shell function called `ls', and you wish to call the command `ls', + you can say `command ls'. The `-p' option means to use a default + value for `$PATH' that is guaranteed to find all of the standard + utilities. + + If either the `-V' or `-v' option is supplied, a description of + COMMAND is printed. The `-v' option causes a single word + indicating the command or file name used to invoke COMMAND to be + printed; the `-V' option produces a more verbose description. + +`declare' + declare [-afFrxi] [-p] [NAME[=VALUE]] + + Declare variables and give them attributes. If no NAMEs are + given, then display the values of variables instead. + + The `-p' option will display the attributes and values of each + NAME. When `-p' is used, additional options are ignored. The + `-F' option inhibits the display of function definitions; only the + function name and attributes are printed. `-F' implies `-f'. The + following options can be used to restrict output to variables with + the specified attributes or to give variables attributes: + + `-a' + Each NAME is an array variable (*note Arrays::.). + + `-f' + Use function names only. + + `-i' + The variable is to be treated as an integer; arithmetic + evaluation (*note Shell Arithmetic::.) is performed when the + variable is assigned a value. + + `-r' + Make NAMEs readonly. These names cannot then be assigned + values by subsequent assignment statements. + + `-x' + Mark each NAME for export to subsequent commands via the + environment. + + Using `+' instead of `-' turns off the attribute instead. When + used in a function, `declare' makes each NAME local, as with the + `local' command. + +`echo' + echo [-neE] [arg ...] + Output the `arg's, separated by spaces, terminated with a newline. + The return status is always 0. If `-n' is specified, the + trailing newline is suppressed. If the `-e' option is given, + interpretation of the following backslash-escaped characters is + enabled. The `-E' option disables the interpretation of these + escape characters, even on systems where they are interpreted by + default. `echo' interprets the following escape sequences: + `\a' + alert (bell) + + `\b' + backspace + + `\c' + suppress trailing newline + + `\e' + escape + + `\f' + form feed + + `\n' + new line + + `\r' + carriage return + + `\t' + horizontal tab + + `\v' + vertical tab + + `\\' + backslash + + `\nnn' + the character whose ASCII code is `nnn' (octal) + +`enable' + enable [-n] [-p] [-f FILENAME] [-ads] [NAME ...] + Enable and disable builtin shell commands. This allows you to use + a disk command which has the same name as a shell builtin. If + `-n' is used, the NAMEs become disabled. Otherwise NAMEs are + enabled. For example, to use the `test' binary found via `$PATH' + instead of the shell builtin version, type `enable -n test'. + + If the `-p' option is supplied, or no NAME arguments appear, a + list of shell builtins is printed. With no other arguments, the + list consists of all enabled shell builtins. The `-a' option + means to list each builtin with an indication of whether or not it + is enabled. + + The `-f' option means to load the new builtin command NAME from + shared object FILENAME, on systems that support dynamic loading. + The `-d' option will delete a builtin loaded with `-f'. If there + are no options, a list of the shell builtins is displayed. The + `-s' option restricts `enable' to the POSIX.2 special builtins. + If `-s' is used with `-f', the new builtin becomes a special + builtin. + +`help' + help [PATTERN] + Display helpful information about builtin commands. If PATTERN is + specified, `help' gives detailed help on all commands matching + PATTERN, otherwise a list of the builtins is printed. + +`local' + local NAME[=VALUE] + For each argument, create a local variable called NAME, and give + it VALUE. `local' can only be used within a function; it makes + the variable NAME have a visible scope restricted to that function + and its children. + +`logout' + logout [N] + Exit a login shell, returning a status of N to the shell's parent. + +`read' + read [-a ANAME] [-p PROMPT] [-er] [NAME ...] + One line is read from the standard input, and the first word is + assigned to the first NAME, the second word to the second NAME, + and so on, with leftover words assigned to the last NAME. Only + the characters in the value of the `IFS' variable are recognized + as word delimiters. If no names are supplied, the line read is + assigned to the variable `REPLY'. The return code is zero, unless + end-of-file is encountered. Options, if supplied, have the + following meanings: + + `-r' + If this option is given, a backslash-newline pair is not + ignored, and the backslash is considered to be part of the + line. + + `-p PROMPT' + Display `prompt', without a trailing newline, before + attempting to read any input. The prompt is displayed only + if input is coming from a terminal. + + `-a ANAME' + The words are assigned to sequential indices of the array + variable ANAME, starting at 0. + + `-e' + Readline (*note Command Line Editing::.) is used to obtain + the line. + +`shopt' + shopt [-pqsu] [-o] [OPTNAME ...] + Toggle the values of variables controlling optional shell behavior. + With no options, or with the `-p' option, a list of all settable + options is displayed, with an indication of whether or not each is + set. Other options have the following meanings: + + `-s' + Enable (set) each OPTNAME + + `-u' + Disable (unset) each OPTNAME. + + `-q' + Suppresses normal output; the return status indicates whether + the OPTNAME is set or unset. If multiple OPTNAME arguments + are given with `-q', the return status is zero if all + OPTNAMES are enabled; non-zero otherwise. + + `-o' + Restricts the values of OPTNAME to be those defined for the + `-o' option to the `set' builtin (*note The Set Builtin::.). + + If either of `-s' or `-u' is used with no OPTNAME arguments, the + display is limited to those options which are set or unset, + respectively. + + Unless otherwise noted, the `shopt' options are disabled (off) by + default. + + The return status when listing options is zero if all OPTNAMES are + enabled, non-zero otherwise. When setting or unsetting options, + the return status is zero unless an OPTNAME is not a legal shell + option. + + The list of `shopt' options is: + `cdable_vars' + If this is set, an argument to the `cd' builtin command that + is not a directory is assumed to be the name of a variable + whose value is the directory to change to. + + `cdspell' + If set, minor errors in the spelling of a directory component + in a `cd' command will be corrected. The errors checked for + are transposed characters, a missing character, and a + character too many. If a correction is found, the corrected + path is printed, and the command proceeds. This option is + enabled by default, but is only used by interactive shells. + + `checkhash' + If this is set, Bash checks that a command found in the hash + table exists before trying to execute it. If a hashed + command no longer exists, a normal path search is performed. + + `checkwinsize' + If set, Bash checks the window size after each command and, + if necessary, updates the values of `LINES' and `COLUMNS'. + + `cmdhist' + If set, Bash attempts to save all lines of a multiple-line + command in the same history entry. This allows easy + re-editing of multi-line commands. + + `dotglob' + If set, Bash includes filenames beginning with a `.' in the + results of filename expansion. + + `execfail' + If this is set, a non-interactive shell will not exit if it + cannot execute the file specified as an argument to the `exec' + builtin command. An interactive shell does not exit if `exec' + fails. + + `histappend' + If set, the history list is appended to the file named by the + value of the `HISTFILE' variable when the shell exits, rather + than overwriting the file. + + `histreedit' + If set, and Readline is being used, a user is given the + opportunity to re-edit a failed history substitution. + + `histverify' + If set, and Readline is being used, the results of history + substitution are not immediately passed to the shell parser. + Instead, the resulting line is loaded into the Readline + editing buffer, allowing further modification. + + `hostcomplete' + If set, and Readline is being used, Bash will attempt to + perform hostname completion when a word beginning with `@' is + being completed (*note Commands For Completion::.). + + `interactive_comments' + Allow a word beginning with `#' to cause that word and all + remaining characters on that line to be ignored in an + interactive shell. This option is enabled by default. + + `lithist' + If enabled, and the `cmdhist' option is enabled, multi-line + commands are saved to the history with embedded newlines + rather than using semicolon separators where possible. + + `mailwarn' + If set, and a file that Bash is checking for mail has been + accessed since the last time it was checked, the message + `"The mail in MAILFILE has been read"' is displayed. + + `nullglob' + If set, Bash allows filename patterns which match no files to + expand to a null string, rather than themselves. + + `promptvars' + If set, prompt strings undergo variable and parameter + expansion after being expanded (*note Printing a Prompt::.). + This option is enabled by default. + + `shift_verbose' + If this is set, the `shift' builtin prints an error message + when the shift count exceeds the number of positional + parameters. + + `sourcepath' + If set, the `source' builtin uses the value of `PATH' to find + the directory containing the file supplied as an argument. + This is enabled by default. + +`type' + type [-all] [-type | -path] [NAME ...] + For each NAME, indicate how it would be interpreted if used as a + command name. + + If the `-type' flag is used, `type' returns a single word which is + one of `alias', `function', `builtin', `file' or `keyword', if + NAME is an alias, shell function, shell builtin, disk file, or + shell reserved word, respectively. If the NAME is not found, then + nothing is printed, and `type' returns a failure status. + + If the `-path' flag is used, `type' either returns the name of the + disk file that would be executed, or nothing if `-type' would not + return `file'. + + If the `-all' flag is used, returns all of the places that contain + an executable named FILE. This includes aliases and functions, if + and only if the `-path' flag is not also used. + + `type' accepts `-a', `-t', and `-p' as equivalent to `-all', + `-type', and `-path', respectively. + +`ulimit' + ulimit [-acdflmnpstuvSH] [LIMIT] + `ulimit' provides control over the resources available to processes + started by the shell, on systems that allow such control. If an + option is given, it is interpreted as follows: + `-S' + change and report the soft limit associated with a resource. + + `-H' + change and report the hard limit associated with a resource. + + `-a' + all current limits are reported. + + `-c' + the maximum size of core files created. + + `-d' + the maximum size of a process's data segment. + + `-f' + the maximum size of files created by the shell. + + `-l' + The maximum size that may be locked into memory. + + `-m' + the maximum resident set size. + + `-n' + the maximum number of open file descriptors. + + `-p' + the pipe buffer size. + + `-s' + the maximum stack size. + + `-t' + the maximum amount of cpu time in seconds. + + `-u' + the maximum number of processes available to a single user. + + `-v' + the maximum amount of virtual memory available to the process. + + If LIMIT is given, it is the new value of the specified resource. + Otherwise, the current value of the soft limit for the specified + resource is printed, unless the `-H' option is supplied. When + setting new limits, if neither `-H' nor `-S' is supplied, both the + hard and soft limits are set. If no option is given, then `-f' is + assumed. Values are in 1024-byte increments, except for `-t', + which is in seconds, `-p', which is in units of 512-byte blocks, + and `-n' and `-u', which are unscaled values. + + +File: bashref.info, Node: The Set Builtin, Next: Bash Conditional Expressions, Prev: Bash Builtins, Up: Bash Features + +The Set Builtin +=============== + + This builtin is so overloaded that it deserves its own section. + +`set' + set [-abefhkmnptuvxdBCHP] [-o OPTION] [ARGUMENT ...] + + `-a' + Mark variables which are modified or created for export. + + `-b' + Cause the status of terminated background jobs to be reported + immediately, rather than before printing the next primary + prompt. + + `-e' + Exit immediately if a simple command exits with a non-zero + status. + + `-f' + Disable file name generation (globbing). + + `-h' + Locate and remember (hash) commands as they are looked up for + execution. + + `-k' + All arguments in the form of assignment statements are placed + in the environment for a command, not just those that precede + the command name. + + `-m' + Job control is enabled (*note Job Control::.). + + `-n' + Read commands but do not execute them. + + `-o OPTION-NAME' + Set the flag corresponding to OPTION-NAME: + + `allexport' + same as `-a'. + + `braceexpand' + same as `-B'. + + `emacs' + use an `emacs'-style line editing interface (*note + Command Line Editing::.). + + `errexit' + same as `-e'. + + `hashall' + same as `-h'. + + `histexpand' + same as `-H'. + + `history' + Enable command history, as described in *Note Bash + History Facilities::. This option is on by default in + interactive shells. + + `ignoreeof' + the shell will not exit upon reading EOF. + + `keyword' + same as `-k'. + + `monitor' + same as `-m'. + + `noclobber' + same as `-C'. + + `noexec' + same as `-n'. + + `noglob' + same as `-f'. + + `notify' + same as `-b'. + + `nounset' + same as `-u'. + + `onecmd' + same as `-t'. + + `physical' + same as `-P'. + + `posix' + change the behavior of Bash where the default operation + differs from the POSIX 1003.2 standard to match the + standard. This is intended to make Bash behave as a + strict superset of that standard. + + `privileged' + same as `-p'. + + `verbose' + same as `-v'. + + `vi' + use a `vi'-style line editing interface. + + `xtrace' + same as `-x'. + + `-p' + Turn on privileged mode. In this mode, the `$ENV' file is + not processed, and shell functions are not inherited from the + environment. This is enabled automatically on startup if the + effective user (group) id is not equal to the real user + (group) id. Turning this option off causes the effective user + and group ids to be set to the real user and group ids. + + `-t' + Exit after reading and executing one command. + + `-u' + Treat unset variables as an error when substituting. + + `-v' + Print shell input lines as they are read. + + `-x' + Print commands and their arguments as they are executed. + + `-B' + The shell will perform brace expansion (*note Brace + Expansion::.). This option is on by default. + + `-C' + Disallow output redirection to existing files. + + `-H' + Enable `!' style history substitution (*note History + Interaction::.). This flag is on by default for interactive + shells. + + `-P' + If set, do not follow symbolic links when performing commands + such as `cd' which change the current directory. The + physical directory is used instead. By default, Bash follows + the logical chain of directories when performing commands + which change the current directory. + + For example, if `/usr/sys' is a link to `/usr/local/sys' then: + $ cd /usr/sys; echo $PWD + /usr/sys + $ cd ..; pwd + /usr + + If `set -P' is on, then: + $ cd /usr/sys; echo $PWD + /usr/local/sys + $ cd ..; pwd + /usr/local + + `--' + If no arguments follow this flag, then the positional + parameters are unset. Otherwise, the positional parameters + are set to the ARGUMENTS, even if some of them begin with a + `-'. + + `-' + Signal the end of options, cause all remaining ARGUMENTS to + be assigned to the positional parameters. The `-x' and `-v' + options are turned off. If there are no arguments, the + positional parameters remain unchanged. + + Using `+' rather than `-' causes these flags to be turned off. + The flags can also be used upon invocation of the shell. The + current set of flags may be found in `$-'. + + The remaining N ARGUMENTS are positional parameters and are + assigned, in order, to `$1', `$2', ... `$N'. If no arguments are + given, all shell variables are printed. + + +File: bashref.info, Node: Bash Conditional Expressions, Next: Bash Variables, Prev: The Set Builtin, Up: Bash Features + +Bash Conditional Expressions +============================ + + Conditional expressions are used by the `test' and `[' builtins. + + Expressions may be unary or binary. Unary expressions are often +used to examine the status of a file. There are string operators and +numeric comparison operators as well. Each operator and operand must +be a separate argument. If FILE is of the form `/dev/fd/N', then file +descriptor N is checked. Expressions are composed of the following +primaries: + +`-b FILE' + True if FILE exists and is a block special file. + +`-c FILE' + True if FILE exists and is a character special file. + +`-d FILE' + True if FILE exists and is a directory. + +`-e FILE' + True if FILE exists. + +`-f FILE' + True if FILE exists and is a regular file. + +`-g FILE' + True if FILE exists and is set-group-id. + +`-k FILE' + True if FILE has its "sticky" bit set. + +`-L FILE' + True if FILE exists and is a symbolic link. + +`-p FILE' + True if FILE exists and is a named pipe. + +`-r FILE' + True if FILE exists and is readable. + +`-s FILE' + True if FILE exists and has a size greater than zero. + +`-S FILE' + True if FILE exists and is a socket. + +`-t FD' + True if FD is opened on a terminal. + +`-u FILE' + True if FILE exists and its set-user-id bit is set. + +`-w FILE' + True if FILE exists and is writable. + +`-x FILE' + True if FILE exists and is executable. + +`-O FILE' + True if FILE exists and is owned by the effective user id. + +`-G FILE' + True if FILE exists and is owned by the effective group id. + +`FILE1 -nt FILE2' + True if FILE1 is newer (according to modification date) than FILE2. + +`FILE1 -ot FILE2' + True if FILE1 is older than FILE2. + +`FILE1 -ef FILE2' + True if FILE1 and FILE2 have the same device and inode numbers. + +`-o OPTNAME' + True if shell option OPTNAME is enabled. The list of options + appears in the description of the `-o' option to the `set' builtin + (*note The Set Builtin::.). + +`-z STRING' + True if the length of STRING is zero. + +`-n STRING' +`STRING' + True if the length of STRING is non-zero. + +`STRING1 = STRING2' + True if the strings are equal. `==' may be used in place of `='. + +`STRING1 != STRING2' + True if the strings are not equal. + +`STRING1 < STRING2' + True if STRING1 sorts before STRING2 lexicographically. + +`STRING1 > STRING2' + True if STRING1 sorts after STRING2 lexicographically. + +`! EXPR' + True if EXPR is false. + +`EXPR1 -a EXPR2' + True if both EXPR1 and EXPR2 are true. + +`EXPR1 -o EXPR2' + True if either EXPR1 and EXPR2 is true. + +`ARG1 OP ARG2' + `OP' is one of `-eq', `-ne', `-lt', `-le', `-gt', or `-ge'. These + arithmetic binary operators return true if ARG1 is equal to, not + equal to, less than, less than or equal to, greater than, or + greater than or equal to ARG2, respectively. ARG1 and ARG2 may be + positive or negative integers. + + The Bash `test' and `[' builtins evaluate conditional expressions +using a set of rules based on the number of arguments. These are the +rules: + +0 arguments + The expression is false. + +1 argument + The expression is true if and only if the argument is not null. + +2 arguments + If the first argument is `!', the expression is true if and only + if the second argument is null. If the first argument is one of + the listed unary operators, the expression is true if the unary + test is true. If the first argument is not a legal unary + operator, the expression is false. + +3 arguments + If the first argument is `!', the value is the negation of the + two-argument test using the second and third arguments. If the + second argument is one of the binary operators, the result of the + expression is the result of the binary test using the first and + third arguments as operands. If the first argument is exactly `(' + and the third argument is exactly `)', the result is the + one-argument test of the second argument. Otherwise, the + expression is false. The `-a' and `-o' operators are considered + binary operators in this case. + +4 arguments + If the first argument is `!', the result is the negation of the + three-argument expression composed of the remaining arguments. + Otherwise, the expression is parsed and evaluated according to + precedence. `-a' has a higher precedence than `-o'. + +5 or more arguments + The expression is parsed and evaluated according to precedence, + with `-a' having a higher precedence than `-o'. + + +File: bashref.info, Node: Bash Variables, Next: Shell Arithmetic, Prev: Bash Conditional Expressions, Up: Bash Features + +Bash Variables +============== + + These variables are set or used by Bash, but other shells do not +normally treat them specially. + +`TIMEFORMAT' + The value of this parameter is used as a format string specifying + how the timing information for pipelines prefixed with the `time' + reserved word should be displayed. The `%' character introduces an + escape sequence that is expanded to a time value or other + information. The escape sequences and their meanings are as + follows; the braces denote optional portions. + + `%%' + A literal `%'. + + `%[P][l]R' + The elapsed time in seconds. + + `%[P][l]U' + The number of CPU seconds spent in user mode. + + `%[P][l]S' + The number of CPU seconds spent in system mode. + + `%P' + The CPU percentage, computed as (%U + %S) / %R. + + The optional P is a digit specifying the precision, the number of + fractional digits after a decimal point. A value of 0 causes no + decimal point or fraction to be output. At most three places + after the decimal point may be specified; values of P greater than + 3 are changed to 3. If P is not specified, the value 3 is used. + + The optional `l' specifies a longer format, including minutes, of + the form MMmSS.FFs. The value of P determines whether or not the + fraction is included. + + If this variable is not set, bash acts as if it had the value + `$'\nreal\t%3lR\nuser\t%3lU\nsys\t%3lS''. If the value is null, + no timing information is displayed. A trailing newline is added + when the format string is displayed. + +`HISTCONTROL' + Set to a value of `ignorespace', it means don't enter lines which + begin with a space or tab into the history list. Set to a value + of `ignoredups', it means don't enter lines which match the last + entered line. A value of `ignoreboth' combines the two options. + Unset, or set to any other value than those above, means to save + all lines on the history list. + +`HISTIGNORE' + A colon-separated list of patterns used to decide which command + lines should be saved on the history list. Each pattern is + anchored at the beginning of the line and must fully specify the + line (no implicit `*' is appended). Each pattern is tested + against the line after the checks specified by `HISTCONTROL' are + applied. In addition to the normal shell pattern matching + characters, `&' matches the previous history line. `&' may be + escaped using a backslash. The backslash is removed before + attempting a match. + + `HISTIGNORE' subsumes the function of `HISTCONTROL'. A pattern of + `&' is identical to `ignoredups', and a pattern of `[ ]*' is + identical to `ignorespace'. Combining these two patterns, + separating them with a colon, provides the functionality of + `ignoreboth'. + +`HISTFILE' + The name of the file to which the command history is saved. The + default is `~/.bash_history'. + +`HISTSIZE' + If set, this is the maximum number of commands to remember in the + history. + +`HISTFILESIZE' + The maximum number of lines contained in the history file. When + this variable is assigned a value, the history file is truncated, + if necessary, to contain no more than that number of lines. The + default value is 500. The history file is also truncated to this + size after writing it when an interactive shell exits. + +`histchars' + Up to three characters which control history expansion, quick + substitution, and tokenization (*note History Interaction::.). + The first character is the "history-expansion-char", that is, the + character which signifies the start of a history expansion, + normally `!'. The second character is the character which + signifies `quick substitution' when seen as the first character on + a line, normally `^'. The optional third character is the + character which signifies the remainder of the line is a comment, + when found as the first character of a word, usually `#'. The + history comment character causes history substitution to be + skipped for the remaining words on the line. It does not + necessarily cause the shell parser to treat the rest of the line + as a comment. + +`HISTCMD' + The history number, or index in the history list, of the current + command. If `HISTCMD' is unset, it loses its special properties, + even if it is subsequently reset. + +`HOSTFILE' + Contains the name of a file in the same format as `/etc/hosts' that + should be read when the shell needs to complete a hostname. You + can change the file interactively; the next time you attempt to + complete a hostname, Bash will add the contents of the new file to + the already existing database. + +`MAILCHECK' + How often (in seconds) that the shell should check for mail in the + files specified in `MAILPATH'. + +`PROMPT_COMMAND' + If present, this contains a string which is a command to execute + before the printing of each primary prompt (`$PS1'). + +`UID' + The numeric real user id of the current user. + +`EUID' + The numeric effective user id of the current user. + +`PPID' + The process id of the shell's parent process. + +`HOSTNAME' + The name of the current host. + +`HOSTTYPE' + A string describing the machine Bash is running on. + +`OSTYPE' + A string describing the operating system Bash is running on. + +`MACHTYPE' + A string that fully describes the system type on which Bash is + executing, in the standard GNU CPU-COMPANY-SYSTEM format. + +`SHELLOPTS' + A colon-separated list of enabled shell options. Each word in the + list is a valid argument for the `-o' option to the `set' builtin + command (*note The Set Builtin::.). The options appearing in + `SHELLOPTS' are those reported as `on' by `set -o'. If this + variable is in the environment when Bash starts up, each shell + option in the list will be enabled before reading any startup + files. This variable is readonly. + +`FIGNORE' + A colon-separated list of suffixes to ignore when performing + filename completion. A file name whose suffix matches one of the + entries in `FIGNORE' is excluded from the list of matched file + names. A sample value is `.o:~' + +`GLOBIGNORE' + A colon-separated list of patterns defining the set of filenames to + be ignored by filename expansion. If a filename matched by a + filename expansion pattern also matches one of the patterns in + `GLOBIGNORE', it is removed from the list of matches. + +`DIRSTACK' + An array variable (*note Arrays::.) containing the current + contents of the directory stack. Directories appear in the stack + in the order they are displayed by the `dirs' builtin. Assigning + to members of this array variable may be used to modify + directories already in the stack, but the `pushd' and `popd' + builtins must be used to add and remove directories. Assignment + to this variable will not change the current directory. If + `DIRSTACK' is unset, it loses its special properties, even if it + is subsequently reset. + +`PIPESTATUS' + An array variable (*note Arrays::.) containing a list of exit + status values from the processes in the most-recently-executed + foreground pipeline (which may contain only a single command). + +`INPUTRC' + The name of the Readline startup file, overriding the default of + `~/.inputrc'. + +`BASH' + The full filename used to execute the current instance of Bash. + +`BASH_VERSION' + The version number of the current instance of Bash. + +`BASH_VERSINFO' + An array variable whose members hold version information for this + instance of Bash. The values assigned to the array members are as + follows: + + `BASH_VERSINFO[0]' + The major version number (the RELEASE). + + `BASH_VERSINFO[1]' + The minor version number (the VERSION). + + `BASH_VERSINFO[2]' + The patch level. + + `BASH_VERSINFO[3]' + The build version. + + `BASH_VERSINFO[4]' + The release status (e.g., BETA1). + + `BASH_VERSINFO[5]' + The value of `MACHTYPE'. + +`SHLVL' + Incremented by one each time a new instance of Bash is started. + This is intended to be an account of how deeply your Bash shells + are nested. + +`OPTERR' + If set to the value 1, Bash displays error messages generated by + the `getopts' builtin command. + +`LANG' + Used to determine the locale category for any category not + specifically selected with a variable starting with `LC_'. + +`LC_ALL' + This variable overrides the value of `LANG' and any other `LC_' + variable specifying a locale category. + +`LC_MESSAGES' + This variable determines the locale used to translate double-quoted + strings preceded by a `$'. + +`IGNOREEOF' + Controls the action of the shell on receipt of an `EOF' character + as the sole input. If set, then the value of it is the number of + consecutive `EOF' characters that can be read as the first + character on an input line before the shell will exit. If the + variable exists but does not have a numeric value (or has no + value) then the default is 10. If the variable does not exist, + then `EOF' signifies the end of input to the shell. This is only + in effect for interactive shells. + + +File: bashref.info, Node: Shell Arithmetic, Next: Arrays, Prev: Bash Variables, Up: Bash Features + +Shell Arithmetic +================ + +* Menu: + +* Arithmetic Evaluation:: How shell arithmetic works. +* Arithmetic Expansion:: How to use arithmetic in shell expansions. +* Arithmetic Builtins:: Builtin commands that use shell arithmetic. + + Bash includes several mechanisms to evaluate arithmetic expressions +and display the result or use it as part of a command. + + +File: bashref.info, Node: Arithmetic Evaluation, Next: Arithmetic Expansion, Up: Shell Arithmetic + +Arithmetic Evaluation +--------------------- + + The shell allows arithmetic expressions to be evaluated, as one of +the shell expansions or by the `let' builtin. + + Evaluation is done in long integers with no check for overflow, +though division by 0 is trapped and flagged as an error. The following +list of operators is grouped into levels of equal-precedence operators. +The levels are listed in order of decreasing precedence. + +`- +' + unary minus and plus + +`! ~' + logical and bitwise negation + +`* / %' + multiplication, division, remainder + +`+ -' + addition, subtraction + +`<< >>' + left and right bitwise shifts + +`<= >= < >' + comparison + +`== !=' + equality and inequality + +`&' + bitwise AND + +`^' + bitwise exclusive OR + +`|' + bitwise OR + +`&&' + logical AND + +`||' + logical OR + +`expr ? expr : expr' + conditional evaluation + +`= *= /= %= += -= <<= >>= &= ^= |=' + assignment + + Shell variables are allowed as operands; parameter expansion is +performed before the expression is evaluated. The value of a parameter +is coerced to a long integer within an expression. A shell variable +need not have its integer attribute turned on to be used in an +expression. + + Constants with a leading 0 are interpreted as octal numbers. A +leading `0x' or `0X' denotes hexadecimal. Otherwise, numbers take the +form [BASE`#']N, where BASE is a decimal number between 2 and 64 +representing the arithmetic base, and N is a number in that base. If +BASE 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 BASE is less than or equal to 36, lowercase and +uppercase letters may be used interchangably to represent numbers +between 10 and 35. + + Operators are evaluated in order of precedence. Sub-expressions in +parentheses are evaluated first and may override the precedence rules +above. + + +File: bashref.info, Node: Arithmetic Expansion, Next: Arithmetic Builtins, Prev: Arithmetic Evaluation, Up: Shell Arithmetic + +Arithmetic Expansion +-------------------- + + Arithmetic expansion allows the evaluation of an arithmetic +expression and the substitution of the result. The format for +arithmetic expansion is: + + $(( EXPRESSION )) + + The expression is treated as if it were within double quotes, but a +double quote inside the braces or parentheses is not treated specially. +All tokens in the expression undergo parameter expansion, command +substitution, and quote removal. Arithmetic substitutions may be +nested. + + The evaluation is performed according to the rules listed above. If +the expression is invalid, Bash prints a message indicating failure and +no substitution occurs. + + +File: bashref.info, Node: Arithmetic Builtins, Prev: Arithmetic Expansion, Up: Shell Arithmetic + +Arithmetic Builtins +------------------- + +`let' + let EXPRESSION [EXPRESSION] + The `let' builtin allows arithmetic to be performed on shell + variables. Each EXPRESSION is evaluated according to the rules + given previously (*note Arithmetic Evaluation::.). If the last + EXPRESSION evaluates to 0, `let' returns 1; otherwise 0 is + returned. + + +File: bashref.info, Node: Arrays, Next: Printing a Prompt, Prev: Shell Arithmetic, Up: Bash Features + +Arrays +====== + + Bash provides one-dimensional array variables. Any variable may be +used as an array; the `declare' builtin will explicitly declare an +array. There is no maximum limit on the size of an array, nor any +requirement that members be indexed or assigned contiguously. Arrays +are zero-based. + + An array is created automatically if any variable is assigned to +using the syntax + name[SUBSCRIPT]=VALUE + +The SUBSCRIPT is treated as an arithmetic expression that must evaluate +to a number greater than or equal to zero. To explicitly declare an +array, use + declare -a NAME + +The syntax + declare -a NAME[SUBSCRIPT] + +is also accepted; the SUBSCRIPT is ignored. Attributes may be +specified for an array variable using the `declare' and `readonly' +builtins. Each attribute applies to all members of an array. + + Arrays are assigned to using compound assignments of the form + name=(value1 ... valueN) + +where each VALUE is of the form `[[SUBSCRIPT]=]'STRING. If the +optional subscript is supplied, that index is assigned to; otherwise +the index of the element assigned is the last index assigned to by the +statement plus one. Indexing starts at zero. This syntax is also +accepted by the `declare' builtin. Individual array elements may be +assigned to using the `name['SUBSCRIPT`]='VALUE syntax introduced above. + + Any element of an array may be referenced using +`${name['SUBSCRIPT`]}'. The braces are required to avoid conflicts +with the shell's filename expansion operators. If the SUBSCRIPT is `@' +or `*', the word expands to all members of the array NAME. These +subscripts differ only when the word appears within double quotes. If +the word is double-quoted, `${name[*]}' expands to a single word with +the value of each array member separated by the first character of the +`IFS' variable, and `${name[@]}' expands each element of NAME to a +separate word. When there are no array members, `${name[@]}' expands +to nothing. This is analogous to the expansion of the special +parameters `@' and `*'. `${#name['SUBSCRIPT`]}' expands to the length +of `${name['SUBSCRIPT`]}'. If SUBSCRIPT is `@' or `*', the expansion +is the number of elements in the array. Referencing an array variable +without a subscript is equivalent to referencing element zero. + + The `unset' builtin is used to destroy arrays. `unset' +NAME[SUBSCRIPT] destroys the array element at index SUBSCRIPT. `unset' +NAME, where NAME is an array, removes the entire array. A subscript of +`*' or `@' also removes the entire array. + + The `declare', `local', and `readonly' builtins each accept a `-a' +option to specify an array. The `read' builtin accepts a `-a' option +to assign a list of words read from the standard input to an array, and +can read values from the standard input into individual array elements. +The `set' and `declare' builtins display array values in a way that +allows them to be reused as input. + + +File: bashref.info, Node: Printing a Prompt, Next: The Restricted Shell, Prev: Arrays, Up: Bash Features + +Controlling the Prompt +====================== + + The value of the variable `PROMPT_COMMAND' is examined just before +Bash prints each primary prompt. If it is set and non-null, then the +value is executed just as if you had typed it on the command line. + + In addition, the following table describes the special characters +which can appear in the prompt variables: + +`\a' + a bell character. + +`\d' + the date, in "Weekday Month Date" format (e.g., "Tue May 26"). + +`\e' + an escape character. + +`\h' + the hostname, up to the first `.'. + +`\H' + the hostname. + +`\n' + newline. + +`\s' + the name of the shell, the basename of `$0' (the portion following + the final slash). + +`\t' + the time, in 24-hour HH:MM:SS format. + +`\T' + the time, in 12-hour HH:MM:SS format. + +`\@' + the time, in 12-hour am/pm format. + +`\v' + the version of Bash (e.g., 2.00) + +`\V' + the release of Bash, version + patchlevel (e.g., 2.00.0) + +`\w' + the current working directory. + +`\W' + the basename of `$PWD'. + +`\u' + your username. + +`\!' + the history number of this command. + +`\#' + the command number of this command. + +`\$' + if the effective uid is 0, `#', otherwise `$'. + +`\nnn' + the character corresponding to the octal number `nnn'. + +`\\' + a backslash. + +`\[' + begin a sequence of non-printing characters. This could be used to + embed a terminal control sequence into the prompt. + +`\]' + end a sequence of non-printing characters. + + +File: bashref.info, Node: The Restricted Shell, Next: Bash POSIX Mode, Prev: Printing a Prompt, Up: Bash Features + +The Restricted Shell +==================== + + If Bash is started with the name `rbash', or the `--restricted' +option is supplied at invocation, the shell becomes restricted. A +restricted shell is used to set up an environment more controlled than +the standard shell. A restricted shell behaves identically to `bash' +with the exception that the following are disallowed: + * Changing directories with the `cd' builtin. + + * Setting or unsetting the values of the `SHELL' or `PATH' variables. + + * Specifying command names containing slashes. + + * Specifying a filename containing a slash as an argument to the `.' + builtin command. + + * Importing function definitions from the shell environment at + startup. + + * Redirecting output using the `>', `>|', `<>', `>&', `&>', and `>>' + redirection operators. + + * Using the `exec' builtin to replace the shell with another command. + + * Adding or deleting builtin commands with the `-f' and `-d' options + to the `enable' builtin. + + * Specifying the `-p' option to the `command' builtin. + + * Turning off restricted mode with `set +r'. + + +File: bashref.info, Node: Bash POSIX Mode, Prev: The Restricted Shell, Up: Bash Features + +Bash POSIX Mode +=============== + + Starting Bash with the `--posix' command-line option or executing +`set -o posix' while Bash is running will cause Bash to conform more +closely to the POSIX.2 standard by changing the behavior to match that +specified by POSIX.2 in areas where the Bash default differs. + + The following list is what's changed when `POSIX mode' is in effect: + + 1. When a command in the hash table no longer exists, Bash will + re-search `$PATH' to find the new location. This is also + available with `shopt -s checkhash'. + + 2. The `>&' redirection does not redirect stdout and stderr. + + 3. The message printed by the job control code and builtins when a job + exits with a non-zero status is `Done(status)'. + + 4. Reserved words may not be aliased. + + 5. The POSIX.2 `PS1' and `PS2' expansions of `!' to the history + number and `!!' to `!' are enabled, and parameter expansion is + performed on the value regardless of the setting of the + `promptvars' option. + + 6. Interactive comments are enabled by default. (Note that Bash has + them on by default anyway.) + + 7. The POSIX.2 startup files are executed (`$ENV') rather than the + normal Bash files. + + 8. Tilde expansion is only performed on assignments preceding a + command name, rather than on all assignment statements on the line. + + 9. The default history file is `~/.sh_history' (this is the default + value of `$HISTFILE'). + + 10. The output of `kill -l' prints all the signal names on a single + line, separated by spaces. + + 11. Non-interactive shells exit if FILENAME in `.' FILENAME is not + found. + + 12. Redirection operators do not perform filename expansion on the word + in the redirection unless the shell is interactive. + + 13. Function names must be valid shell `name's. That is, they may not + contain characters other than letters, digits, and underscores, and + may not start with a digit. Declaring a function with an illegal + name causes a fatal syntax error in non-interactive shells. + + 14. POSIX.2 `special' builtins are found before shell functions during + command lookup. + + 15. If a POSIX.2 special builtin returns an error status, a + non-interactive shell exits. The fatal errors are those listed in + the POSIX.2 standard, and include things like passing incorrect + options, redirection errors, variable assignment errors for + assignments preceding the command name, and so on. + + 16. If the `cd' builtin finds a directory to change to using + `$CDPATH', the value it assigns to the `PWD' variable does not + contain any symbolic links, as if `cd -P' had been executed. + + 17. A non-interactive shell exits with an error status if a variable + assignment error occurs when no command name follows the assignment + statements. A variable assignment error occurs, for example, when + trying to assign a value to a read-only variable. + + 18. A non-interactive shell exits with an error status if the iteration + variable in a `for' statement or the selection variable in a + `select' statement is a read-only variable. + + 19. Process substitution is not available. + + 20. Assignment statements preceding POSIX.2 `special' builtins persist + in the shell environment after the builtin completes. + + + There is other POSIX.2 behavior that Bash does not implement. +Specifically: + + 1. Assignment statements affect the execution environment of all + builtins, not just special ones. + + +File: bashref.info, Node: Job Control, Next: Using History Interactively, Prev: Bash Features, Up: Top + +Job Control +*********** + + This chapter disusses what job control is, how it works, and how +Bash allows you to access its facilities. + +* Menu: + +* Job Control Basics:: How job control works. +* Job Control Builtins:: Bash builtin commands used to interact + with job control. +* Job Control Variables:: Variables Bash uses to customize job + control. + + +File: bashref.info, Node: Job Control Basics, Next: Job Control Builtins, Up: Job Control + +Job Control Basics +================== + + Job control refers to the ability to selectively stop (suspend) the +execution of processes and continue (resume) their execution at a later +point. A user typically employs this facility via an interactive +interface supplied jointly by the system's terminal driver and Bash. + + The shell associates a JOB with each pipeline. It keeps a table of +currently executing jobs, which may be listed with the `jobs' command. +When Bash starts a job asynchronously (in the background), it prints a +line that looks like: + [1] 25647 + +indicating that this job is job number 1 and that the process ID of the +last process in the pipeline associated with this job is 25647. All of +the processes in a single pipeline are members of the same job. Bash +uses the JOB abstraction as the basis for job control. + + To facilitate the implementation of the user interface to job +control, the system maintains the notion of a current terminal process +group ID. Members of this process group (processes whose process group +ID is equal to the current terminal process group ID) receive +keyboard-generated signals such as `SIGINT'. These processes are said +to be in the foreground. Background processes are those whose process +group ID differs from the terminal's; such processes are immune to +keyboard-generated signals. Only foreground processes are allowed to +read from or write to the terminal. Background processes which attempt +to read from (write to) the terminal are sent a `SIGTTIN' (`SIGTTOU') +signal by the terminal driver, which, unless caught, suspends the +process. + + If the operating system on which Bash is running supports job +control, Bash allows you to use it. Typing the SUSPEND character +(typically `^Z', Control-Z) while a process is running causes that +process to be stopped and returns you to Bash. Typing the DELAYED +SUSPEND character (typically `^Y', Control-Y) causes the process to be +stopped when it attempts to read input from the terminal, and control to +be returned to Bash. You may then manipulate the state of this job, +using the `bg' command to continue it in the background, the `fg' +command to continue it in the foreground, or the `kill' command to kill +it. A `^Z' takes effect immediately, and has the additional side +effect of causing pending output and typeahead to be discarded. + + There are a number of ways to refer to a job in the shell. The +character `%' introduces a job name. Job number `n' may be referred to +as `%n'. A job may also be referred to using a prefix of the name used +to start it, or using a substring that appears in its command line. +For example, `%ce' refers to a stopped `ce' job. Using `%?ce', on the +other hand, refers to any job containing the string `ce' in its command +line. If the prefix or substring matches more than one job, Bash +reports an error. The symbols `%%' and `%+' refer to the shell's +notion of the current job, which is the last job stopped while it was +in the foreground. The previous job may be referenced using `%-'. In +output pertaining to jobs (e.g., the output of the `jobs' command), the +current job is always flagged with a `+', and the previous job with a +`-'. + + Simply naming a job can be used to bring it into the foreground: +`%1' is a synonym for `fg %1', bringing job 1 from the background into +the foreground. Similarly, `%1 &' resumes job 1 in the background, +equivalent to `bg %1' + + The shell learns immediately whenever a job changes state. +Normally, Bash waits until it is about to print a prompt before +reporting changes in a job's status so as to not interrupt any other +output. If the the `-b' option to the `set' builtin is set, Bash +reports such changes immediately (*note The Set Builtin::.). + + If you attempt to exit Bash while jobs are stopped, the shell prints +a message warning you that you have stopped jobs. You may then use the +`jobs' command to inspect their status. If you do this, or try to exit +again immediately, you are not warned again, and the stopped jobs are +terminated. + + +File: bashref.info, Node: Job Control Builtins, Next: Job Control Variables, Prev: Job Control Basics, Up: Job Control + +Job Control Builtins +==================== + +`bg' + bg [JOBSPEC] + Place JOBSPEC into the background, as if it had been started with + `&'. If JOBSPEC is not supplied, the current job is used. + +`fg' + fg [JOBSPEC] + Bring JOBSPEC into the foreground and make it the current job. If + JOBSPEC is not supplied, the current job is used. + +`jobs' + jobs [-lpnrs] [JOBSPEC] + jobs -x COMMAND [JOBSPEC] + + The first form lists the active jobs. The options have the + following meanings: + + `-l' + List process IDs in addition to the normal information + + `-n' + Display information only about jobs that have changed status + since you were last notified of their status. + + `-p' + List only the process ID of the job's process group leader. + + `-r' + Restrict output to running jobs. + + `-s' + Restrict output to stopped jobs. + + If JOBSPEC is given, output is restricted to information about + that job. If JOBSPEC is not supplied, the status of all jobs is + listed. + + If the `-x' option is supplied, `jobs' replaces any JOBSPEC found + in COMMAND or ARGUMENTS with the corresponding process group ID, + and executes COMMAND, passing it ARGUMENTs, returning its exit + status. + +`kill' + kill [-s SIGSPEC] [-n SIGNUM] [-SIGSPEC] JOBSPEC + kill -l [SIGSPEC] + Send a signal specified by SIGSPEC or SIGNUM to the process named + by JOBSPEC. SIGSPEC is either a signal name such as `SIGINT' or a + signal number; SIGNUM is a signal number. If SIGSPEC and SIGNUM + are not present, `SIGTERM' is used. The `-l' option lists the + signal names, or the signal name corresponding to SIGSPEC. + +`wait' + wait [JOBSPEC|PID] + Wait until the child process specified by process ID PID or job + specification JOBSPEC exits and report its exit status. If a job + spec is given, all processes in the job are waited for. If no + arguments are given, all currently active child processes are + waited for. + +`disown' + disown [-h] [JOBSPEC ...] + Without options, each JOBSPEC is removed from the table of active + jobs. If the `-h' option is given, the job is not removed from + the table, but is marked so that `SIGHUP' is not sent to the job + if the shell receives a `SIGHUP'. If JOBSPEC is not present, the + current job is used. + +`suspend' + suspend [-f] + Suspend the execution of this shell until it receives a `SIGCONT' + signal. The `-f' option means to suspend even if the shell is a + login shell. + + When job control is not active, the `kill' and `wait' builtins do +not accept JOBSPEC arguments. They must be supplied process IDs. + + +File: bashref.info, Node: Job Control Variables, Prev: Job Control Builtins, Up: Job Control + +Job Control Variables +===================== + +`auto_resume' + This variable controls how the shell interacts with the user and + job control. If this variable exists then single word simple + commands without redirects are treated as candidates for resumption + of an existing job. There is no ambiguity allowed; if you have + more than one job beginning with the string that you have typed, + then the most recently accessed job will be selected. The name of + a stopped job, in this context, is the command line used to start + it. If this variable is set to the value `exact', the string + supplied must match the name of a stopped job exactly; if set to + `substring', the string supplied needs to match a substring of the + name of a stopped job. The `substring' value provides + functionality analogous to the `%?' job ID (*note Job Control + Basics::.). 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 `%' job ID. + + +File: bashref.info, Node: Using History Interactively, Next: Command Line Editing, Prev: Job Control, Up: Top + +Using History Interactively +*************************** + + This chapter describes how to use the GNU History Library +interactively, from a user's standpoint. It should be considered a +user's guide. For information on using the GNU History Library in your +own programs, see the GNU Readline Library Manual. + +* Menu: + +* Bash History Facilities:: How Bash lets you manipulate your command + history. +* History Interaction:: What it feels like using History as a user. + + +File: bashref.info, Node: Bash History Facilities, Next: History Interaction, Up: Using History Interactively + +Bash History Facilities +======================= + + When the `-o history' option to the `set' builtin is enabled (*note +The Set Builtin::.), the shell provides access to the COMMAND HISTORY, +the list of commands previously typed. The text of the last `HISTSIZE' +commands (default 500) is saved in a history list. The shell stores +each command in the history list prior to parameter and variable +expansion but after history expansion is performed, subject to the +values of the shell variables `HISTIGNORE' and `HISTCONTROL'. When the +shell starts up, the history is initialized from the file named by the +`HISTFILE' variable (default `~/.bash_history'). `HISTFILE' is +truncated, if necessary, to contain no more than the number of lines +specified by the value of the `HISTFILESIZE' variable. When an +interactive shell exits, the last `HISTSIZE' lines are copied from the +history list to `HISTFILE'. If the `histappend' shell option is set +(*note Bash Builtins::.), the lines are appended to the history file, +otherwise the history file is overwritten. If `HISTFILE' is unset, or +if the history file is unwritable, the history is not saved. After +saving the history, the history file is truncated to contain no more +than `$HISTFILESIZE' lines. If `HISTFILESIZE' is not set, no +truncation is performed. + + The builtin command `fc' (*note Korn Shell Builtins::.) may be used +to list or edit and re-execute a portion of the history list. The +`history' builtin (*note C Shell Builtins::.) can be used to display or +modify the history list and manipulate the history file. When using +the command-line editing, search commands are available in each editing +mode that provide access to the history list. + + The shell allows control over which commands are saved on the history +list. The `HISTCONTROL' and `HISTIGNORE' variables may be set to cause +the shell to save only a subset of the commands entered. The `cmdhist' +shell option, if enabled, causes the shell to attempt to save each line +of a multi-line command in the same history entry, adding semicolons +where necessary to preserve syntactic correctness. The `lithist' shell +option causes the shell to save the command with embedded newlines +instead of semicolons. *Note Bash Builtins:: for a description of +`shopt'. + + +File: bashref.info, Node: History Interaction, Prev: Bash History Facilities, Up: Using History Interactively + +Interactive History Expansion +============================= + + The History library provides a history expansion feature that is +similar to the history expansion provided by `csh'. This section +describes the syntax used to manipulate the history information. + + History expansions introduce words from the history list into the +input stream, making it easy to repeat commands, insert the arguments +to a previous command into the current input line, or fix errors in +previous commands quickly. + + History expansion takes place in two parts. The first is to +determine which line from the previous history should be used during +substitution. The second is to select portions of that line for +inclusion into the current one. The line selected from the previous +history is called the "event", and the portions of that line that are +acted upon are called "words". Various "modifiers" are available to +manipulate the selected words. The line is broken into words in the +same fashion that Bash does, so that several English (or Unix) words +surrounded by quotes are considered as one word. History expansions +are introduced by the appearance of the history expansion character, +which is `!' by default. Only `\' and `'' may be used to escape the +history expansion character. + + Several shell options settable with the `shopt' builtin (*note Bash +Builtins::.) may be used to tailor the behavior of history expansion. +If the `histverify' shell option is enabled, and Readline is being +used, history substitutions are not immediately passed to the shell +parser. Instead, the expanded line is reloaded into the Readline +editing buffer for further modification. If Readline is being used, +and the `histreedit' shell option is enabled, a failed history +expansion will be reloaded into the Readline editing buffer for +correction. The `-p' option to the `history' builtin command may be +used to see what a history expansion will do before using it. The `-s' +option to the `history' builtin may be used to add commands to the end +of the history list without actually executing them, so that they are +available for subsequent recall. + + The shell allows control of the various characters used by the +history expansion mechanism with the `histchars' variable. + +* Menu: + +* Event Designators:: How to specify which history line to use. +* Word Designators:: Specifying which words are of interest. +* Modifiers:: Modifying the results of substitution. + + +File: bashref.info, Node: Event Designators, Next: Word Designators, Up: History Interaction + +Event Designators +----------------- + + An event designator is a reference to a command line entry in the +history list. + +`!' + Start a history substitution, except when followed by a space, tab, + the end of the line, = or (. + +`!N' + Refer to command line N. + +`!-N' + Refer to the command N lines back. + +`!!' + Refer to the previous command. This is a synonym for `!-1'. + +`!STRING' + Refer to the most recent command starting with STRING. + +`!?STRING[?]' + Refer to the most recent command containing STRING. The trailing + `?' may be omitted if the STRING is followed immediately by a + newline. + +`^STRING1^STRING2^' + Quick Substitution. Repeat the last command, replacing STRING1 + with STRING2. Equivalent to `!!:s/STRING1/STRING2/'. + +`!#' + The entire command line typed so far. + + +File: bashref.info, Node: Word Designators, Next: Modifiers, Prev: Event Designators, Up: History Interaction + +Word Designators +---------------- + + Word designators are used to select desired words from the event. A +`:' separates the event specification from the word designator. It can +be omitted if the word designator begins with a `^', `$', `*', `-', or +`%'. Words are numbered from the beginning of the line, with the first +word being denoted by 0 (zero). Words are inserted into the current +line separated by single spaces. + +`0 (zero)' + The `0'th word. For many applications, this is the command word. + +`N' + The Nth word. + +`^' + The first argument; that is, word 1. + +`$' + The last argument. + +`%' + The word matched by the most recent `?STRING?' search. + +`X-Y' + A range of words; `-Y' abbreviates `0-Y'. + +`*' + All of the words, except the `0'th. This is a synonym for `1-$'. + It is not an error to use `*' if there is just one word in the + event; the empty string is returned in that case. + +`X*' + Abbreviates `X-$' + +`X-' + Abbreviates `X-$' like `X*', but omits the last word. + + If a word designator is supplied without an event specification, the +previous command is used as the event. + + +File: bashref.info, Node: Modifiers, Prev: Word Designators, Up: History Interaction + +Modifiers +--------- + + After the optional word designator, you can add a sequence of one or +more of the following modifiers, each preceded by a `:'. + +`h' + Remove a trailing pathname component, leaving only the head. + +`t' + Remove all leading pathname components, leaving the tail. + +`r' + Remove a trailing suffix of the form `.SUFFIX', leaving the + basename. + +`e' + Remove all but the trailing suffix. + +`p' + Print the new command but do not execute it. + +`q' + Quote the substituted words, escaping further substitutions. + +`x' + Quote the substituted words as with `q', but break into words at + spaces, tabs, and newlines. + +`s/OLD/NEW/' + Substitute NEW for the first occurrence of OLD in the event line. + Any delimiter may be used in place of `/'. The delimiter may be + quoted in OLD and NEW with a single backslash. If `&' appears in + NEW, it is replaced by OLD. A single backslash will quote the + `&'. The final delimiter is optional if it is the last character + on the input line. + +`&' + Repeat the previous substitution. + +`g' + Cause changes to be applied over the entire event line. Used in + conjunction with `s', as in `gs/OLD/NEW/', or with `&'. + + +File: bashref.info, Node: Command Line Editing, Next: Installing Bash, Prev: Using History Interactively, Up: Top + +Command Line Editing +******************** + + This chapter describes the basic features of the GNU command line +editing interface. + +* Menu: + +* Introduction and Notation:: Notation used in this text. +* Readline Interaction:: The minimum set of commands for editing a line. +* Readline Init File:: Customizing Readline from a user's view. +* Bindable Readline Commands:: A description of most of the Readline commands + available for binding +* Readline vi Mode:: A short description of how to make Readline + behave like the vi editor. + + +File: bashref.info, Node: Introduction and Notation, Next: Readline Interaction, Up: Command Line Editing + +Introduction to Line Editing +============================ + + The following paragraphs describe the notation used to represent +keystrokes. + + The text C-k is read as `Control-K' and describes the character +produced when the k key is pressed while the Control key is depressed. + + The text M-k is read as `Meta-K' and describes the character +produced when the meta key (if you have one) is depressed, and the k +key is pressed. If you do not have a meta key, the identical keystroke +can be generated by typing ESC first, and then typing k. Either +process is known as "metafying" the k key. + + The text M-C-k is read as `Meta-Control-k' and describes the +character produced by "metafying" C-k. + + In addition, several keys have their own names. Specifically, DEL, +ESC, LFD, SPC, RET, and TAB all stand for themselves when seen in this +text, or in an init file (*note Readline Init File::.). + + +File: bashref.info, Node: Readline Interaction, Next: Readline Init File, Prev: Introduction and Notation, Up: Command Line Editing + +Readline Interaction +==================== + + Often during an interactive session you type in a long line of text, +only to notice that the first word on the line is misspelled. The +Readline library gives you a set of commands for manipulating the text +as you type it in, allowing you to just fix your typo, and not forcing +you to retype the majority of the line. Using these editing commands, +you move the cursor to the place that needs correction, and delete or +insert the text of the corrections. Then, when you are satisfied with +the line, you simply press RETURN. You do not have to be at the end of +the line to press RETURN; the entire line is accepted regardless of the +location of the cursor within the line. + +* Menu: + +* Readline Bare Essentials:: The least you need to know about Readline. +* Readline Movement Commands:: Moving about the input line. +* Readline Killing Commands:: How to delete text, and how to get it back! +* Readline Arguments:: Giving numeric arguments to commands. +* Searching:: Searching through previous lines. + + +File: bashref.info, Node: Readline Bare Essentials, Next: Readline Movement Commands, Up: Readline Interaction + +Readline Bare Essentials +------------------------ + + In order to enter characters into the line, simply type them. The +typed character appears where the cursor was, and then the cursor moves +one space to the right. If you mistype a character, you can use your +erase character to back up and delete the mistyped character. + + Sometimes you may miss typing a character that you wanted to type, +and not notice your error until you have typed several other +characters. In that case, you can type C-b to move the cursor to the +left, and then correct your mistake. Afterwards, you can move the +cursor to the right with C-f. + + When you add text in the middle of a line, you will notice that +characters to the right of the cursor are `pushed over' to make room +for the text that you have inserted. Likewise, when you delete text +behind the cursor, characters to the right of the cursor are `pulled +back' to fill in the blank space created by the removal of the text. A +list of the basic bare essentials for editing the text of an input line +follows. + +C-b + Move back one character. + +C-f + Move forward one character. + +DEL + Delete the character to the left of the cursor. + +C-d + Delete the character underneath the cursor. + +Printing characters + Insert the character into the line at the cursor. + +C-_ + Undo the last thing that you did. You can undo all the way back + to an empty line. + + +File: bashref.info, Node: Readline Movement Commands, Next: Readline Killing Commands, Prev: Readline Bare Essentials, Up: Readline Interaction + +Readline Movement Commands +-------------------------- + + The above table describes the most basic possible keystrokes that +you need in order to do editing of the input line. For your +convenience, many other commands have been added in addition to C-b, +C-f, C-d, and DEL. Here are some commands for moving more rapidly +about the line. + +C-a + Move to the start of the line. + +C-e + Move to the end of the line. + +M-f + Move forward a word. + +M-b + Move backward a word. + +C-l + Clear the screen, reprinting the current line at the top. + + Notice how C-f moves forward a character, while M-f moves forward a +word. It is a loose convention that control keystrokes operate on +characters while meta keystrokes operate on words. + + +File: bashref.info, Node: Readline Killing Commands, Next: Readline Arguments, Prev: Readline Movement Commands, Up: Readline Interaction + +Readline Killing Commands +------------------------- + + "Killing" text means to delete the text from the line, but to save +it away for later use, usually by "yanking" (re-inserting) it back into +the line. If the description for a command says that it `kills' text, +then you can be sure that you can get the text back in a different (or +the same) place later. + + When you use a kill command, the text is saved in a "kill-ring". +Any number of consecutive kills save all of the killed text together, so +that when you yank it back, you get it all. The kill ring is not line +specific; the text that you killed on a previously typed line is +available to be yanked back later, when you are typing another line. + + Here is the list of commands for killing text. + +C-k + Kill the text from the current cursor position to the end of the + line. + +M-d + Kill from the cursor to the end of the current word, or if between + words, to the end of the next word. + +M-DEL + Kill from the cursor the start of the previous word, or if between + words, to the start of the previous word. + +C-w + Kill from the cursor to the previous whitespace. This is + different than M-DEL because the word boundaries differ. + + And, here is how to "yank" the text back into the line. Yanking +means to copy the most-recently-killed text from the kill buffer. + +C-y + Yank the most recently killed text back into the buffer at the + cursor. + +M-y + Rotate the kill-ring, and yank the new top. You can only do this + if the prior command is C-y or M-y. + + +File: bashref.info, Node: Readline Arguments, Next: Searching, Prev: Readline Killing Commands, Up: Readline Interaction + +Readline Arguments +------------------ + + You can pass numeric arguments to Readline commands. Sometimes the +argument acts as a repeat count, other times it is the sign of the +argument that is significant. If you pass a negative argument to a +command which normally acts in a forward direction, that command will +act in a backward direction. For example, to kill text back to the +start of the line, you might type `M-- C-k'. + + The general way to pass numeric arguments to a command is to type +meta digits before the command. If the first `digit' you type is a +minus sign (-), then the sign of the argument will be negative. Once +you have typed one meta digit to get the argument started, you can type +the remainder of the digits, and then the command. For example, to give +the C-d command an argument of 10, you could type `M-1 0 C-d'. + + +File: bashref.info, Node: Searching, Prev: Readline Arguments, Up: Readline Interaction + +Searching for Commands in the History +------------------------------------- + + Readline provides commands for searching through the command history +(*note Bash History Facilities::.) for lines containing a specified +string. There are two search modes: INCREMENTAL and NON-INCREMENTAL. + + Incremental searches begin before the user has finished typing the +search string. As each character of the search string is typed, +readline displays the next entry from the history matching the string +typed so far. An incremental search requires only as many characters +as needed to find the desired history entry. The Escape character is +used to terminate an incremental search. Control-J will also terminate +the search. Control-G will abort an incremental search and restore the +original line. When the search is terminated, the history entry +containing the search string becomes the current line. To find other +matching entries in the history list, type Control-S or Control-R as +appropriate. This will search backward or forward in the history for +the next entry matching the search string typed so far. Any other key +sequence bound to a readline command will terminate the search and +execute that command. For instance, a `newline' will terminate the +search and accept the line, thereby executing the command from the +history list. + + Non-incremental searches read the entire search string before +starting to search for matching history lines. The search string may be +typed by the user or part of the contents of the current line. + + +File: bashref.info, Node: Readline Init File, Next: Bindable Readline Commands, Prev: Readline Interaction, Up: Command Line Editing + +Readline Init File +================== + + Although the Readline library comes with a set of `emacs'-like +keybindings installed by default, it is possible that you would like to +use a different set of keybindings. You can customize programs that +use Readline by putting commands in an "inputrc" file in your home +directory. The name of this file is taken from the value of the shell +variable `INPUTRC'. If that variable is unset, the default is +`~/.inputrc'. + + When a program which uses the Readline library starts up, the init +file is read, and the key bindings are set. + + In addition, the `C-x C-r' command re-reads this init file, thus +incorporating any changes that you might have made to it. + +* Menu: + +* Readline Init File Syntax:: Syntax for the commands in the inputrc file. + +* Conditional Init Constructs:: Conditional key bindings in the inputrc file. + +* Sample Init File:: An example inputrc file. + + +File: bashref.info, Node: Readline Init File Syntax, Next: Conditional Init Constructs, Up: Readline Init File + +Readline Init File Syntax +------------------------- + + There are only a few basic constructs allowed in the Readline init +file. Blank lines are ignored. Lines beginning with a `#' are +comments. Lines beginning with a `$' indicate conditional constructs +(*note Conditional Init Constructs::.). Other lines denote variable +settings and key bindings. + +Variable Settings + You can change the state of a few variables in Readline by using + the `set' command within the init file. Here is how you would + specify that you wish to use `vi' line editing commands: + + set editing-mode vi + + Right now, there are only a few variables which can be set; so + few, in fact, that we just list them here: + + `bell-style' + Controls what happens when Readline wants to ring the + terminal bell. If set to `none', Readline never rings the + bell. If set to `visible', Readline uses a visible bell if + one is available. If set to `audible' (the default), + Readline attempts to ring the terminal's bell. + + `comment-begin' + The string to insert at the beginning of the line when the + `insert-comment' command is executed. The default value is + `"#"'. + + `completion-query-items' + The number of possible completions that determines when the + user is asked whether he wants to see the list of + possibilities. If the number of possible completions is + greater than this value, Readline will ask the user whether + or not he wishes to view them; otherwise, they are simply + listed. The default limit is `100'. + + `convert-meta' + If set to `on', Readline will convert characters with the + eigth bit set to an ASCII key sequence by stripping the eigth + bit and prepending an ESC character, converting them to a + meta-prefixed key sequence. The default value is `on'. + + `disable-completion' + If set to `On', readline will inhibit word completion. + Completion characters will be inserted into the line as if + they had been mapped to `self-insert'. The default is `off'. + + `editing-mode' + The `editing-mode' variable controls which editing mode you + are using. By default, Readline starts up in Emacs editing + mode, where the keystrokes are most similar to Emacs. This + variable can be set to either `emacs' or `vi'. + + `enable-keypad' + When set to `on', readline will try to enable the application + keypad when it is called. Some systems need this to enable + the arrow keys. The default is `off'. + + `expand-tilde' + If set to `on', tilde expansion is performed when Readline + attempts word completion. The default is `off'. + + `horizontal-scroll-mode' + This variable can be set to either `on' or `off'. Setting it + to `on' means that the text of the lines that you edit will + scroll horizontally on a single screen line when they are + longer than the width of the screen, instead of wrapping onto + a new screen line. By default, this variable is set to `off'. + + `keymap' + Sets Readline's idea of the current keymap for key binding + commands. Acceptable `keymap' names are `emacs', + `emacs-standard', `emacs-meta', `emacs-ctlx', `vi', + `vi-command', and `vi-insert'. `vi' is equivalent to + `vi-command'; `emacs' is equivalent to `emacs-standard'. The + default value is `emacs'. The value of the `editing-mode' + variable also affects the default keymap. + + `mark-directories' + If set to `on', completed directory names have a slash + appended. The default is `on'. + + `mark-modified-lines' + This variable, when set to `on', says to display an asterisk + (`*') at the start of history lines which have been modified. + This variable is `off' by default. + + `input-meta' + If set to `on', Readline will enable eight-bit input (it will + not strip the eighth bit from the characters it reads), + regardless of what the terminal claims it can support. The + default value is `off'. The name `meta-flag' is a synonym + for this variable. + + `output-meta' + If set to `on', Readline will display characters with the + eighth bit set directly rather than as a meta-prefixed escape + sequence. The default is `off'. + + `show-all-if-ambiguous' + This alters the default behavior of the completion functions. + If set to `on', words which have more than one possible + completion cause the matches to be listed immediately instead + of ringing the bell. The default value is `off'. + + `visible-stats' + If set to `on', a character denoting a file's type is + appended to the filename when listing possible completions. + The default is `off'. + +Key Bindings + The syntax for controlling key bindings in the init file is + simple. First you have to know the name of the command that you + want to change. The following pages contain tables of the command + name, the default keybinding, and a short description of what the + command does. + + Once you know the name of the command, simply place the name of + the key you wish to bind the command to, a colon, and then the + name of the command on a line in the init file. The name of the + key can be expressed in different ways, depending on which is most + comfortable for you. + + KEYNAME: FUNCTION-NAME or MACRO + KEYNAME is the name of a key spelled out in English. For + example: + Control-u: universal-argument + Meta-Rubout: backward-kill-word + Control-o: "> output" + + In the above example, `C-u' is bound to the function + `universal-argument', and `C-o' is bound to run the macro + expressed on the right hand side (that is, to insert the text + `> output' into the line). + + "KEYSEQ": FUNCTION-NAME or MACRO + KEYSEQ differs from KEYNAME above in that strings denoting an + entire key sequence can be specified, by placing the key + sequence in double quotes. Some GNU Emacs style key escapes + can be used, as in the following example, but the special + character names are not recognized. + + "\C-u": universal-argument + "\C-x\C-r": re-read-init-file + "\e[11~": "Function Key 1" + + In the above example, `C-u' is bound to the function + `universal-argument' (just as it was in the first example), + `C-x C-r' is bound to the function `re-read-init-file', and + `ESC [ 1 1 ~' is bound to insert the text `Function Key 1'. + The following escape sequences are available when specifying + key sequences: + + ``\C-'' + control prefix + + ``\M-'' + meta prefix + + ``\e'' + an escape character + + ``\\'' + backslash + + ``\"'' + " + + ``\''' + ' + + When entering the text of a macro, single or double quotes + should be used to indicate a macro definition. Unquoted text + is assumed to be a function name. Backslash will quote any + character in the macro text, including `"' and `''. For + example, the following binding will make `C-x \' insert a + single `\' into the line: + "\C-x\\": "\\" + + +File: bashref.info, Node: Conditional Init Constructs, Next: Sample Init File, Prev: Readline Init File Syntax, Up: Readline Init File + +Conditional Init Constructs +--------------------------- + + Readline implements a facility similar in spirit to the conditional +compilation features of the C preprocessor which allows key bindings +and variable settings to be performed as the result of tests. There +are three parser directives used. + +`$if' + The `$if' construct allows bindings to be made based on the + editing mode, the terminal being used, or the application using + Readline. The text of the test extends to the end of the line; no + characters are required to isolate it. + + `mode' + The `mode=' form of the `$if' directive is used to test + whether Readline is in `emacs' or `vi' mode. This may be + used in conjunction with the `set keymap' command, for + instance, to set bindings in the `emacs-standard' and + `emacs-ctlx' keymaps only if Readline is starting out in + `emacs' mode. + + `term' + The `term=' form may be used to include terminal-specific key + bindings, perhaps to bind the key sequences output by the + terminal's function keys. The word on the right side of the + `=' is tested against the full name of the terminal and the + portion of the terminal name before the first `-'. This + allows `sun' to match both `sun' and `sun-cmd', for instance. + + `application' + The APPLICATION construct is used to include + application-specific settings. Each program using the + Readline library sets the APPLICATION NAME, and you can test + for it. This could be used to bind key sequences to + functions useful for a specific program. For instance, the + following command adds a key sequence that quotes the current + or previous word in Bash: + $if Bash + # Quote the current or previous word + "\C-xq": "\eb\"\ef\"" + $endif + +`$endif' + This command, as you saw in the previous example, terminates an + `$if' command. + +`$else' + Commands in this branch of the `$if' directive are executed if the + test fails. + + +File: bashref.info, Node: Sample Init File, Prev: Conditional Init Constructs, Up: Readline Init File + +Sample Init File +---------------- + + Here is an example of an inputrc file. This illustrates key +binding, variable assignment, and conditional syntax. + + + # This file controls the behaviour of line input editing for + # programs that use the Gnu Readline library. Existing programs + # include FTP, Bash, and Gdb. + # + # You can re-read the inputrc file with C-x C-r. + # Lines beginning with '#' are comments. + # + # Set various bindings for emacs mode. + + set editing-mode emacs + + $if mode=emacs + + Meta-Control-h: backward-kill-word Text after the function name is ignored + + # + # Arrow keys in keypad mode + # + #"\M-OD" backward-char + #"\M-OC" forward-char + #"\M-OA" previous-history + #"\M-OB" next-history + # + # Arrow keys in ANSI mode + # + "\M-[D" backward-char + "\M-[C" forward-char + "\M-[A" previous-history + "\M-[B" next-history + # + # Arrow keys in 8 bit keypad mode + # + #"\M-\C-OD" backward-char + #"\M-\C-OC" forward-char + #"\M-\C-OA" previous-history + #"\M-\C-OB" next-history + # + # Arrow keys in 8 bit ANSI mode + # + #"\M-\C-[D" backward-char + #"\M-\C-[C" forward-char + #"\M-\C-[A" previous-history + #"\M-\C-[B" next-history + + C-q: quoted-insert + + $endif + + # An old-style binding. This happens to be the default. + TAB: complete + + # Macros that are convenient for shell interaction + $if Bash + # edit the path + "\C-xp": "PATH=${PATH}\e\C-e\C-a\ef\C-f" + # prepare to type a quoted word -- insert open and close double quotes + # and move to just after the open quote + "\C-x\"": "\"\"\C-b" + # insert a backslash (testing backslash escapes in sequences and macros) + "\C-x\\": "\\" + # Quote the current or previous word + "\C-xq": "\eb\"\ef\"" + # Add a binding to refresh the line, which is unbound + "\C-xr": redraw-current-line + # Edit variable on current line. + "\M-\C-v": "\C-a\C-k$\C-y\M-\C-e\C-a\C-y=" + $endif + + # use a visible bell if one is available + set bell-style visible + + # don't strip characters to 7 bits when reading + set input-meta on + + # allow iso-latin1 characters to be inserted rather than converted to + # prefix-meta sequences + set convert-meta off + + # display characters with the eighth bit set directly rather than + # as meta-prefixed characters + set output-meta on + + # if there are more than 150 possible completions for a word, ask the + # user if he wants to see all of them + set completion-query-items 150 + + # For FTP + $if Ftp + "\C-xg": "get \M-?" + "\C-xt": "put \M-?" + "\M-.": yank-last-arg + $endif + + +File: bashref.info, Node: Bindable Readline Commands, Next: Readline vi Mode, Prev: Readline Init File, Up: Command Line Editing + +Bindable Readline Commands +========================== + +* Menu: + +* Commands For Moving:: Moving about the line. +* Commands For History:: Getting at previous lines. +* Commands For Text:: Commands for changing text. +* Commands For Killing:: Commands for killing and yanking. +* Numeric Arguments:: Specifying numeric arguments, repeat counts. +* Commands For Completion:: Getting Readline to do the typing for you. +* Keyboard Macros:: Saving and re-executing typed characters +* Miscellaneous Commands:: Other miscellaneous commands. + + This section describes Readline commands that may be bound to key +sequences. + + +File: bashref.info, Node: Commands For Moving, Next: Commands For History, Up: Bindable Readline Commands + +Commands For Moving +------------------- + +`beginning-of-line (C-a)' + Move to the start of the current line. + +`end-of-line (C-e)' + Move to the end of the line. + +`forward-char (C-f)' + Move forward a character. + +`backward-char (C-b)' + Move back a character. + +`forward-word (M-f)' + Move forward to the end of the next word. Words are composed of + letters and digits. + +`backward-word (M-b)' + Move back to the start of this, or the previous, word. Words are + composed of letters and digits. + +`clear-screen (C-l)' + Clear the screen and redraw the current line, leaving the current + line at the top of the screen. + +`redraw-current-line ()' + Refresh the current line. By default, this is unbound. + + +File: bashref.info, Node: Commands For History, Next: Commands For Text, Prev: Commands For Moving, Up: Bindable Readline Commands + +Commands For Manipulating The History +------------------------------------- + +`accept-line (Newline, Return)' + Accept the line regardless of where the cursor is. If this line is + non-empty, add it to the history list according to the setting of + the `HISTCONTROL' variable. If this line was a history line, then + restore the history line to its original state. + +`previous-history (C-p)' + Move `up' through the history list. + +`next-history (C-n)' + Move `down' through the history list. + +`beginning-of-history (M-<)' + Move to the first line in the history. + +`end-of-history (M->)' + Move to the end of the input history, i.e., the line you are + entering. + +`reverse-search-history (C-r)' + Search backward starting at the current line and moving `up' + through the history as necessary. This is an incremental search. + +`forward-search-history (C-s)' + Search forward starting at the current line and moving `down' + through the the history as necessary. This is an incremental + search. + +`non-incremental-reverse-search-history (M-p)' + Search backward starting at the current line and moving `up' + through the history as necessary using a non-incremental search + for a string supplied by the user. + +`non-incremental-forward-search-history (M-n)' + Search forward starting at the current line and moving `down' + through the the history as necessary using a non-incremental search + for a string supplied by the user. + +`history-search-forward ()' + Search forward through the history for the string of characters + between the start of the current line and the current cursor + position (the `point'). This is a non-incremental search. By + default, this command is unbound. + +`history-search-backward ()' + Search backward through the history for the string of characters + between the start of the current line and the point. This is a + non-incremental search. By default, this command is unbound. + +`yank-nth-arg (M-C-y)' + Insert the first argument to the previous command (usually the + second word on the previous line). With an argument N, insert the + Nth word from the previous command (the words in the previous + command begin with word 0). A negative argument inserts the Nth + word from the end of the previous command. + +`yank-last-arg (M-., M-_)' + Insert last argument to the previous command (the last word of the + previous history entry). With an argument, behave exactly like + `yank-nth-arg'. + + +File: bashref.info, Node: Commands For Text, Next: Commands For Killing, Prev: Commands For History, Up: Bindable Readline Commands + +Commands For Changing Text +-------------------------- + +`delete-char (C-d)' + Delete the character under the cursor. If the cursor is at the + beginning of the line, there are no characters in the line, and + the last character typed was not `C-d', then return `EOF'. + +`backward-delete-char (Rubout)' + Delete the character behind the cursor. A numeric arg says to kill + the characters instead of deleting them. + +`quoted-insert (C-q, C-v)' + Add the next character that you type to the line verbatim. This is + how to insert key sequences like C-q, for example. + +`tab-insert (M-TAB)' + Insert a tab character. + +`self-insert (a, b, A, 1, !, ...)' + Insert yourself. + +`transpose-chars (C-t)' + Drag the character before the cursor forward over the character at + the cursor, moving the cursor forward as well. If the insertion + point is at the end of the line, then this transposes the last two + characters of the line. Negative argumentss don't work. + +`transpose-words (M-t)' + Drag the word behind the cursor past the word in front of the + cursor moving the cursor over that word as well. + +`upcase-word (M-u)' + Uppercase the current (or following) word. With a negative + argument, do the previous word, but do not move the cursor. + +`downcase-word (M-l)' + Lowercase the current (or following) word. With a negative + argument, do the previous word, but do not move the cursor. + +`capitalize-word (M-c)' + Capitalize the current (or following) word. With a negative + argument, do the previous word, but do not move the cursor. + + +File: bashref.info, Node: Commands For Killing, Next: Numeric Arguments, Prev: Commands For Text, Up: Bindable Readline Commands + +Killing And Yanking +------------------- + +`kill-line (C-k)' + Kill the text from the current cursor position to the end of the + line. + +`backward-kill-line (C-x Rubout)' + Kill backward to the beginning of the line. + +`unix-line-discard (C-u)' + Kill backward from the cursor to the beginning of the current line. + Save the killed text on the kill-ring. + +`kill-whole-line ()' + Kill all characters on the current line, no matter where the + cursor is. By default, this is unbound. + +`kill-word (M-d)' + Kill from the cursor to the end of the current word, or if between + words, to the end of the next word. Word boundaries are the same + as `forward-word'. + +`backward-kill-word (M-DEL)' + Kill the word behind the cursor. Word boundaries are the same as + `backward-word'. + +`unix-word-rubout (C-w)' + Kill the word behind the cursor, using white space as a word + boundary. The killed text is saved on the kill-ring. + +`delete-horizontal-space ()' + Delete all spaces and tabs around point. By default, this is + unbound. + +`kill-region ()' + Kill the text between the point and the *mark* (saved cursor + position. This text is referred to as the REGION. By default, + this command is unbound. + +`copy-region-as-kill ()' + Copy the text in the region to the kill buffer, so you can yank it + right away. By default, this command is unbound. + +`copy-backward-word ()' + Copy the word before point to the kill buffer. By default, this + command is unbound. + +`copy-forward-word ()' + Copy the word following point to the kill buffer. By default, + this command is unbound. + +`yank (C-y)' + Yank the top of the kill ring into the buffer at the current + cursor position. + +`yank-pop (M-y)' + Rotate the kill-ring, and yank the new top. You can only do this + if the prior command is yank or yank-pop. + + +File: bashref.info, Node: Numeric Arguments, Next: Commands For Completion, Prev: Commands For Killing, Up: Bindable Readline Commands + +Specifying Numeric Arguments +---------------------------- + +`digit-argument (M-0, M-1, ... M--)' + Add this digit to the argument already accumulating, or start a new + argument. M- starts a negative argument. + +`universal-argument ()' + Each time this is executed, the argument count is multiplied by + four. The argument count is initially one, so executing this + function the first time makes the argument count four. By + default, this is not bound to a key. + + +File: bashref.info, Node: Commands For Completion, Next: Keyboard Macros, Prev: Numeric Arguments, Up: Bindable Readline Commands + +Letting Readline Type For You +----------------------------- + +`complete (TAB)' + Attempt to do completion on the text before the cursor. This is + application-specific. Generally, if you are typing a filename + argument, you can do filename completion; if you are typing a + command, you can do command completion, if you are typing in a + symbol to GDB, you can do symbol name completion, if you are + typing in a variable to Bash, you can do variable name completion, + and so on. Bash attempts completion treating the text as a + variable (if the text begins with `$'), username (if the text + begins with `~'), hostname (if the text begins with `@'), or + command (including aliases and functions) in turn. If none of + these produces a match, filename completion is attempted. + +`possible-completions (M-?)' + List the possible completions of the text before the cursor. + +`insert-completions (M-*)' + Insert all completions of the text before point that would have + been generated by `possible-completions'. + +`complete-filename (M-/)' + Attempt filename completion on the text before point. + +`possible-filename-completions (C-x /)' + List the possible completions of the text before point, treating + it as a filename. + +`complete-username (M-~)' + Attempt completion on the text before point, treating it as a + username. + +`possible-username-completions (C-x ~)' + List the possible completions of the text before point, treating + it as a username. + +`complete-variable (M-$)' + Attempt completion on the text before point, treating it as a + shell variable. + +`possible-variable-completions (C-x $)' + List the possible completions of the text before point, treating + it as a shell variable. + +`complete-hostname (M-@)' + Attempt completion on the text before point, treating it as a + hostname. + +`possible-hostname-completions (C-x @)' + List the possible completions of the text before point, treating + it as a hostname. + +`complete-command (M-!)' + Attempt completion on the text before point, treating it as a + command name. Command completion attempts to match the text + against aliases, reserved words, shell functions, builtins, and + finally executable filenames, in that order. + +`possible-command-completions (C-x !)' + List the possible completions of the text before point, treating + it as a command name. + +`dynamic-complete-history (M-TAB)' + Attempt completion on the text before point, comparing the text + against lines from the history list for possible completion + matches. + +`complete-into-braces (M-{)' + Perform filename completion and return the list of possible + completions enclosed within braces so the list is available to the + shell (*note Brace Expansion::.). + + +File: bashref.info, Node: Keyboard Macros, Next: Miscellaneous Commands, Prev: Commands For Completion, Up: Bindable Readline Commands + +Keyboard Macros +--------------- + +`start-kbd-macro (C-x ()' + Begin saving the characters typed into the current keyboard macro. + +`end-kbd-macro (C-x ))' + Stop saving the characters typed into the current keyboard macro + and save the definition. + +`call-last-kbd-macro (C-x e)' + Re-execute the last keyboard macro defined, by making the + characters in the macro appear as if typed at the keyboard. + + +File: bashref.info, Node: Miscellaneous Commands, Prev: Keyboard Macros, Up: Bindable Readline Commands + +Some Miscellaneous Commands +--------------------------- + +`re-read-init-file (C-x C-r)' + Read in the contents of the inputrc file, and incorporate any + bindings or variable assignments found there. + +`abort (C-g)' + Abort the current editing command and ring the terminal's bell + (subject to the setting of `bell-style'). + +`do-uppercase-version (M-a, M-b, M-X, ...)' + If the metafied character X is lowercase, run the command that is + bound to the corresponding uppercase character. + +`prefix-meta (ESC)' + Make the next character that you type be metafied. This is for + people without a meta key. Typing `ESC f' is equivalent to typing + `M-f'. + +`undo (C-_, C-x C-u)' + Incremental undo, separately remembered for each line. + +`revert-line (M-r)' + Undo all changes made to this line. This is like typing the `undo' + command enough times to get back to the beginning. + +`tilde-expand (M-~)' + Perform tilde expansion on the current word. + +`set-mark (C-@)' + Set the mark to the current point. If a numeric argument is + supplied, the mark is set to that position. + +`exchange-point-and-mark (C-x C-x)' + Swap the point with the mark. The current cursor position is set + to the saved position, and the old cursor position is saved as the + mark. + +`character-search (C-])' + A character is read and point is moved to the next occurrence of + that character. A negative count searches for previous + occurrences. + +`character-search-backward (M-C-])' + A character is read and point is moved to the previous occurrence + of that character. A negative count searches for subsequent + occurrences. + +`insert-comment (M-#)' + The value of the `comment-begin' variable is inserted at the + beginning of the current line, and the line is accepted as if a + newline had been typed. This makes the current line a shell + comment. + +`dump-functions ()' + Print all of the functions and their key bindings to the readline + output stream. If a numeric argument is supplied, the output is + formatted in such a way that it can be made part of an INPUTRC + file. This command is unbound by default. + +`dump-variables ()' + Print all of the settable variables and their values to the + readline output stream. If a numeric argument is supplied, the + output is formatted in such a way that it can be made part of an + INPUTRC file. This command is unbound by default. + +`dump-macros ()' + Print all of the readline key sequences bound to macros and the + 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 INPUTRC + file. This command is unbound by default. + +`glob-expand-word (C-x *)' + The word before point is treated as a pattern for pathname + expansion, and the list of matching file names is inserted, + replacing the word. + +`glob-list-expansions (C-x g)' + The list of expansions that would have been generated by + `glob-expand-word' is inserted into the line, replacing the word + before point. + +`display-shell-version (C-x C-v)' + Display version information about the current instance of Bash. + +`shell-expand-line (M-C-e)' + Expand the line the way the shell does when it reads it. This + performs alias and history expansion as well as all of the shell + word expansions. + +`history-expand-line (M-^)' + Perform history expansion on the current line. + +`insert-last-argument (M-., M-_)' + A synonym for `yank-last-arg'. + +`operate-and-get-next (C-o)' + Accept the current line for execution and fetch the next line + relative to the current line from the history for editing. Any + argument is ignored. + +`emacs-editing-mode (C-e)' + When in `vi' editing mode, this causes a switch back to `emacs' + editing mode, as if the command `set -o emacs' had been executed. + + +File: bashref.info, Node: Readline vi Mode, Prev: Bindable Readline Commands, Up: Command Line Editing + +Readline vi Mode +================ + + While the Readline library does not have a full set of `vi' editing +functions, it does contain enough to allow simple editing of the line. +The Readline `vi' mode behaves as specified in the POSIX 1003.2 +standard. + + In order to switch interactively between `emacs' and `vi' editing +modes, use the `set -o emacs' and `set -o vi' commands (*note The Set +Builtin::.). The Readline default is `emacs' mode. + + When you enter a line in `vi' mode, you are already placed in +`insertion' mode, as if you had typed an `i'. Pressing ESC switches +you into `command' mode, where you can edit the text of the line with +the standard `vi' movement keys, move to previous history lines with +`k' and subsequent lines with `j', and so forth. + + +File: bashref.info, Node: Installing Bash, Next: Reporting Bugs, Prev: Command Line Editing, Up: Top + +Installing Bash +*************** + + This chapter provides basic instructions for installing Bash on the +various supported platforms. The distribution supports nearly every +version of Unix (and, someday, GNU). Other independent ports exist for +OS/2, Windows 95, and Windows NT. + +* Menu: + +* Basic Installation:: Generic installation instructions. + +* Compilers and Options:: How to set special options for various + systems. + +* Compiling For Multiple Architectures:: How to compile Bash for more + than one kind of system from + the same source tree. + +* Installation Names:: How to set the various paths used by the installation. + +* Specifying the System Type:: How to configure Bash for a particular system. + +* Sharing Defaults:: How to share default configuration values among GNU + programs. + +* Operation Controls:: Options recognized by the configuration program. + +* Optional Features:: How to enable and disable optional features when + building Bash. + + +File: bashref.info, Node: Basic Installation, Next: Compilers and Options, Up: Installing Bash + +Basic Installation +================== + + These are generic installation instructions for Bash. + + The `configure' shell script attempts to guess correct values for +various system-dependent variables used during compilation. It uses +those values to create a `Makefile' in each directory of the package +(the top directory, the `builtins' and `doc' directories, and the each +directory under `lib'). It also creates a `config.h' file containing +system-dependent definitions. Finally, it creates a shell script named +`config.status' that you can run in the future to recreate the current +configuration, a file `config.cache' that saves the results of its +tests to speed up reconfiguring, and a file `config.log' containing +compiler output (useful mainly for debugging `configure'). If at some +point `config.cache' contains results you don't want to keep, you may +remove or edit it. + + If you need to do unusual things to compile the package, please try +to figure out how `configure' could check whether or not to do them, +and mail diffs or instructions to `bash-maintainers@prep.ai.mit.edu' so +they can be considered for the next release. + + The file `configure.in' is used to create `configure' by a program +called Autoconf. You only need `configure.in' if you want to change it +or regenerate `configure' using a newer version of Autoconf. If you do +this, make sure you are using Autoconf version 2.9 or newer. + + The simplest way to compile Bash is: + + 1. `cd' to the directory containing the source code and type + `./configure' to configure Bash for your system. If you're using + `csh' on an old version of System V, you might need to type `sh + ./configure' instead to prevent `csh' from trying to execute + `configure' itself. + + Running `configure' takes awhile. While running, it prints some + messages telling which features it is checking for. + + 2. Type `make' to compile Bash and build the `bashbug' bug reporting + script. + + 3. Optionally, type `make tests' to run the Bash test suite. + + 4. Type `make install' to install `bash' and `bashbug'. This will + also install the manual pages and Info file. + + + You can remove the program binaries and object files from the source +code directory by typing `make clean'. To also remove the files that +`configure' created (so you can compile Bash for a different kind of +computer), type `make distclean'. + + +File: bashref.info, Node: Compilers and Options, Next: Compiling For Multiple Architectures, Prev: Basic Installation, Up: Installing Bash + +Compilers and Options +===================== + + Some systems require unusual options for compilation or linking that +the `configure' script does not know about. You can give `configure' +initial values for variables by setting them in the environment. Using +a Bourne-compatible shell, you can do that on the command line like +this: + + CC=c89 CFLAGS=-O2 LIBS=-lposix ./configure + + On systems that have the `env' program, you can do it like this: + + env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure + + The configuration process uses GCC to build Bash if it is available. + + +File: bashref.info, Node: Compiling For Multiple Architectures, Next: Installation Names, Prev: Compilers and Options, Up: Installing Bash + +Compiling For Multiple Architectures +==================================== + + You can compile Bash for more than one kind of computer at the same +time, by placing the object files for each architecture in their own +directory. To do this, you must use a version of `make' that supports +the `VPATH' variable, such as GNU `make'. `cd' to the directory where +you want the object files and executables to go and run the `configure' +script from the source directory. You may need to supply the +`--srcdir=PATH' argument to tell `configure' where the source files +are. `configure' automatically checks for the source code in the +directory that `configure' is in and in `..'. + + If you have to use a `make' that does not supports the `VPATH' +variable, you can compile Bash for one architecture at a time in the +source code directory. After you have installed Bash for one +architecture, use `make distclean' before reconfiguring for another +architecture. + + Alternatively, if your system supports symbolic links, you can use +the `support/mkclone' script to create a build tree which has symbolic +links back to each file in the source directory. Here's an example +that creates a build directory in the current directory from a source +directory `/usr/gnu/src/bash-2.0': + + bash /usr/gnu/src/bash-2.0/support/mkclone -s /usr/gnu/src/bash-2.0 . + +The `mkclone' script requires Bash, so you must have already built Bash +for at least one architecture before you can create build directories +for other architectures. + + +File: bashref.info, Node: Installation Names, Next: Specifying the System Type, Prev: Compiling For Multiple Architectures, Up: Installing Bash + +Installation Names +================== + + By default, `make install' will install into `/usr/local/bin', +`/usr/local/man', etc. You can specify an installation prefix other +than `/usr/local' by giving `configure' the option `--prefix=PATH'. + + You can specify separate installation prefixes for +architecture-specific files and architecture-independent files. If you +give `configure' the option `--exec-prefix=PATH', the package will use +`PATH' as the prefix for installing programs and libraries. +Documentation and other data files will still use the regular prefix. + + +File: bashref.info, Node: Specifying the System Type, Next: Sharing Defaults, Prev: Installation Names, Up: Installing Bash + +Specifying the System Type +========================== + + There may be some features `configure' can not figure out +automatically, but needs to determine by the type of host the package +will run on. Usually `configure' can figure that out, but if it prints +a message saying it can not guess the host type, give it the +`--host=TYPE' option. `TYPE' can either be a short name for the system +type, such as `sun4', or a canonical name with three fields: +`CPU-COMPANY-SYSTEM' (e.g., `sparc-sun-sunos4.1.2'). + +See the file `support/config.sub' for the possible values of each field. + + +File: bashref.info, Node: Sharing Defaults, Next: Operation Controls, Prev: Specifying the System Type, Up: Installing Bash + +Sharing Defaults +================ + + If you want to set default values for `configure' scripts to share, +you can create a site shell script called `config.site' that gives +default values for variables like `CC', `cache_file', and `prefix'. +`configure' looks for `PREFIX/share/config.site' if it exists, then +`PREFIX/etc/config.site' if it exists. Or, you can set the +`CONFIG_SITE' environment variable to the location of the site script. +A warning: the Bash `configure' looks for a site script, but not all +`configure' scripts do. + + +File: bashref.info, Node: Operation Controls, Next: Optional Features, Prev: Sharing Defaults, Up: Installing Bash + +Operation Controls +================== + + `configure' recognizes the following options to control how it +operates. + +`--cache-file=FILE' + Use and save the results of the tests in FILE instead of + `./config.cache'. Set FILE to `/dev/null' to disable caching, for + debugging `configure'. + +`--help' + Print a summary of the options to `configure', and exit. + +`--quiet' +`--silent' +`-q' + Do not print messages saying which checks are being made. + +`--srcdir=DIR' + Look for the Bash source code in directory DIR. Usually + `configure' can determine that directory automatically. + +`--version' + Print the version of Autoconf used to generate the `configure' + script, and exit. + + `configure' also accepts some other, not widely used, boilerplate +options. + + +File: bashref.info, Node: Optional Features, Prev: Operation Controls, Up: Installing Bash + +Optional Features +================= + + The Bash `configure' has a number of `--enable-FEATURE' options, +where FEATURE indicates an optional part of the package. There are +also several `--with-PACKAGE' options, where PACKAGE is something like +`gnu-malloc' or `purify' (for the Purify memory allocation checker). To +turn off the default use of a package, use `--without-PACKAGE'. To +configure Bash without a feature that is enabled by default, use +`--disable-FEATURE'. + + Here is a complete list of the `--enable-' and `--with-' options +that the Bash `configure' recognizes. + +`--with-gnu-malloc' + Use the GNU version of `malloc' in `lib/malloc/malloc.c'. This is + not the same `malloc' that appears in GNU libc, but an older + version derived from the 4.2 BSD `malloc'. This `malloc' is very + fast, but wastes a lot of space. This option is enabled by + default. The `NOTES' file contains a list of systems for which + this should be turned off. + +`--with-glibc-malloc' + Use the GNU libc version of `malloc' in `lib/malloc/gmalloc.c'. + This is somewhat slower than the default `malloc', but wastes + considerably less space. + +`--with-afs' + Define if you are using the Andrew File System from Transarc. + +`--with-purify' + Define this to use the Purify memory allocation checker from Pure + Software. + +`--enable-minimal-config' + This produces a shell with minimal features, close to the + historical Bourne shell. + +The `minimal-config' option can be used to disable all of the following +options, but it is processed first, so individual options may be +enabled using `enable-FEATURE'. + + All of the following options except for `disabled-builtins' and +`usg-echo-default' are enabled by default, unless the operating system +does not provide the necessary support. + +`--enable-job-control' + This enables job control features, if the OS supports them. + +`--enable-alias' + Allow alias expansion and include the `alias' and `unalias' + builtins. + +`--enable-readline' + Include support for command-line editing and history with the Bash + version of the Readline library. + +`--enable-history' + Include command history and the `fc' and `history' builtin + commands. + +`--enable-bang-history' + Include support for `csh'-like history substitution. + +`--enable-directory-stack' + Include support for a `csh'-like directory stack and the `pushd', + `popd', and `dirs' builtins. + +`--enable-restricted' + Include support for a "restricted shell". If this is enabled, + Bash, when called as `rbash', enters a restricted mode. See *Note + The Restricted Shell::, for a description of restricted mode. + +`--enable-process-substitution' + This enables process substitution (*note Process Substitution::.) + if the OS provides the necessary support. + +`--enable-prompt-string-decoding' + Turn on the interpretation of a number of backslash-escaped + characters in the `$PS1', `$PS2', `$PS3', and `$PS4' prompt + strings. + +`--enable-select' + Include the `ksh' `select' builtin, which allows the generation of + simple menus. + +`--enable-help-builtin' + Include the `help' builtin, which displays help on shell builtins + and variables. + +`--enable-array-variables' + Include support for one-dimensional array shell variables. + +`--enable-dparen-arithmetic' + Include support for the `ksh' `((...))' command. + +`--enable-brace-expansion' + Include `csh'-like brace expansion ( `b{a,b}c' ==> `bac bbc' ). + +`--enable-disabled-builtins' + Allow builtin commands to be invoked via `builtin xxx' even after + `xxx' has been disabled using `enable -n xxx'. See *Note Bash + Builtins::, for details of the `builtin' and `enable' builtin + commands. + +`--enable-command-timing' + Include support for recognizing `time' as a reserved word and for + displaying timing statistics for the pipeline following `time'. + This allows pipelines as well as shell builtins and functions to + be timed. + +`--enable-usg-echo-default' + Make the `echo' builtin expand backslash-escaped characters by + default, without requiring the `-e' option. This makes the Bash + `echo' behave more like the System V version. + + The file `config.h.top' contains C Preprocessor `#define' statements +for options which are not settable from `configure'. Some of these are +not meant to be changed; beware of the consequences if you do. Read +the comments associated with each definition for more information about +its effect. + + +File: bashref.info, Node: Reporting Bugs, Next: Builtin Index, Prev: Installing Bash, Up: Top + +Reporting Bugs +************** + + Please report all bugs you find in Bash. But first, you should make +sure that it really is a bug, and that it appears in the latest version +of Bash that you have. + + Once you have determined that a bug actually exists, use the +`bashbug' command to submit a bug report. If you have a fix, you are +welcome to mail that as well! Suggestions and `philosophical' bug +reports may be mailed to `bug-bash@prep.ai.MIT.Edu' or posted to the +Usenet newsgroup `gnu.bash.bug'. + + All bug reports should include: + * The version number of Bash. + + * The hardware and operating system. + + * The compiler used to compile Bash. + + * A description of the bug behaviour. + + * A short script or `recipe' which exercises the bug and may be used + to reproduce it. + +`bashbug' inserts the first three items automatically into the template +it provides for filing a bug report. + + Please send all reports concerning this manual to +`chet@ins.CWRU.Edu'. + + +File: bashref.info, Node: Builtin Index, Next: Reserved Word Index, Prev: Reporting Bugs, Up: Top + +Index of Shell Builtin Commands +******************************* + +* Menu: + +* .: Bourne Shell Builtins. +* :: Bourne Shell Builtins. +* [: Bourne Shell Builtins. +* alias: Alias Builtins. +* bg: Job Control Builtins. +* bind: Bash Builtins. +* break: Bourne Shell Builtins. +* builtin: Bash Builtins. +* cd: Bourne Shell Builtins. +* command: Bash Builtins. +* continue: Bourne Shell Builtins. +* declare: Bash Builtins. +* dirs: C Shell Builtins. +* disown: Job Control Builtins. +* echo: Bash Builtins. +* enable: Bash Builtins. +* eval: Bourne Shell Builtins. +* exec: Bourne Shell Builtins. +* exit: Bourne Shell Builtins. +* export: Bourne Shell Builtins. +* fc: Korn Shell Builtins. +* fg: Job Control Builtins. +* getopts: Bourne Shell Builtins. +* hash: Bourne Shell Builtins. +* help: Bash Builtins. +* history: C Shell Builtins. +* jobs: Job Control Builtins. +* kill: Job Control Builtins. +* let <1>: Arithmetic Builtins. +* let: Korn Shell Builtins. +* local: Bash Builtins. +* logout <1>: Bash Builtins. +* logout: C Shell Builtins. +* popd: C Shell Builtins. +* pushd: C Shell Builtins. +* pwd: Bourne Shell Builtins. +* read: Bash Builtins. +* readonly: Bourne Shell Builtins. +* return: Bourne Shell Builtins. +* set: The Set Builtin. +* shift: Bourne Shell Builtins. +* shopt: Bash Builtins. +* source: C Shell Builtins. +* suspend: Job Control Builtins. +* test: Bourne Shell Builtins. +* times: Bourne Shell Builtins. +* trap: Bourne Shell Builtins. +* type: Bash Builtins. +* typeset: Korn Shell Builtins. +* ulimit: Bash Builtins. +* umask: Bourne Shell Builtins. +* unalias: Alias Builtins. +* unset: Bourne Shell Builtins. +* wait: Job Control Builtins. + + +File: bashref.info, Node: Reserved Word Index, Next: Variable Index, Prev: Builtin Index, Up: Top + +Shell Reserved Words +******************** + +* Menu: + +* !: Pipelines. +* {: Command Grouping. +* }: Command Grouping. +* case: Conditional Constructs. +* do: Looping Constructs. +* done: Looping Constructs. +* elif: Conditional Constructs. +* else: Conditional Constructs. +* esac: Conditional Constructs. +* fi: Conditional Constructs. +* for: Looping Constructs. +* function: Shell Functions. +* if: Conditional Constructs. +* in: Conditional Constructs. +* select: Korn Shell Constructs. +* then: Conditional Constructs. +* time: Pipelines. +* until: Looping Constructs. +* while: Looping Constructs. + + +File: bashref.info, Node: Variable Index, Next: Function Index, Prev: Reserved Word Index, Up: Top + +Parameter and Variable Index +**************************** + +* Menu: + +* !: Special Parameters. +* #: Special Parameters. +* $: Special Parameters. +* *: Special Parameters. +* -: Special Parameters. +* 0: Special Parameters. +* ?: Special Parameters. +* @: Special Parameters. +* _: Special Parameters. +* auto_resume: Job Control Variables. +* BASH: Bash Variables. +* BASH_VERSINFO: Bash Variables. +* BASH_VERSION: Bash Variables. +* bell-style: Readline Init File Syntax. +* CDPATH: Bourne Shell Variables. +* comment-begin: Readline Init File Syntax. +* completion-query-items: Readline Init File Syntax. +* convert-meta: Readline Init File Syntax. +* DIRSTACK: Bash Variables. +* disable-completion: Readline Init File Syntax. +* editing-mode: Readline Init File Syntax. +* enable-keypad: Readline Init File Syntax. +* ENV: Korn Shell Variables. +* EUID: Bash Variables. +* expand-tilde: Readline Init File Syntax. +* FCEDIT: Korn Shell Variables. +* FIGNORE: Bash Variables. +* GLOBIGNORE: Bash Variables. +* histchars: Bash Variables. +* HISTCMD: Bash Variables. +* HISTCONTROL: Bash Variables. +* HISTFILE: Bash Variables. +* HISTFILESIZE: Bash Variables. +* HISTIGNORE: Bash Variables. +* HISTSIZE: Bash Variables. +* HOME: Bourne Shell Variables. +* horizontal-scroll-mode: Readline Init File Syntax. +* HOSTFILE: Bash Variables. +* HOSTNAME: Bash Variables. +* HOSTTYPE: Bash Variables. +* IFS: Bourne Shell Variables. +* IGNOREEOF <1>: Bash Variables. +* IGNOREEOF: C Shell Variables. +* input-meta: Readline Init File Syntax. +* INPUTRC: Bash Variables. +* keymap: Readline Init File Syntax. +* LANG: Bash Variables. +* LC_ALL: Bash Variables. +* LC_MESSAGES: Bash Variables. +* LINENO: Korn Shell Variables. +* MACHTYPE: Bash Variables. +* MAIL: Bourne Shell Variables. +* MAILCHECK: Bash Variables. +* MAILPATH: Bourne Shell Variables. +* mark-modified-lines: Readline Init File Syntax. +* meta-flag: Readline Init File Syntax. +* OLDPWD: Korn Shell Variables. +* OPTARG: Bourne Shell Variables. +* OPTERR: Bash Variables. +* OPTIND: Bourne Shell Variables. +* OSTYPE: Bash Variables. +* output-meta: Readline Init File Syntax. +* PATH: Bourne Shell Variables. +* PIPESTATUS: Bash Variables. +* PPID: Bash Variables. +* PROMPT_COMMAND: Bash Variables. +* PS1: Bourne Shell Variables. +* PS2: Bourne Shell Variables. +* PS3: Korn Shell Variables. +* PS4: Korn Shell Variables. +* PWD: Korn Shell Variables. +* RANDOM: Korn Shell Variables. +* REPLY: Korn Shell Variables. +* SECONDS: Korn Shell Variables. +* SHELLOPTS: Bash Variables. +* SHLVL: Bash Variables. +* show-all-if-ambiguous: Readline Init File Syntax. +* TIMEFORMAT: Bash Variables. +* TMOUT: Korn Shell Variables. +* UID: Bash Variables. +* visible-stats: Readline Init File Syntax. + + +File: bashref.info, Node: Function Index, Next: Concept Index, Prev: Variable Index, Up: Top + +Function Index +************** + +* Menu: + +* abort (C-g): Miscellaneous Commands. +* accept-line (Newline, Return): Commands For History. +* backward-char (C-b): Commands For Moving. +* backward-delete-char (Rubout): Commands For Text. +* backward-kill-line (C-x Rubout): Commands For Killing. +* backward-kill-word (M-DEL): Commands For Killing. +* backward-word (M-b): Commands For Moving. +* beginning-of-history (M-<): Commands For History. +* beginning-of-line (C-a): Commands For Moving. +* call-last-kbd-macro (C-x e): Keyboard Macros. +* capitalize-word (M-c): Commands For Text. +* character-search (C-]): Miscellaneous Commands. +* character-search-backward (M-C-]): Miscellaneous Commands. +* clear-screen (C-l): Commands For Moving. +* complete (TAB): Commands For Completion. +* copy-backward-word (): Commands For Killing. +* copy-forward-word (): Commands For Killing. +* copy-region-as-kill (): Commands For Killing. +* delete-char (C-d): Commands For Text. +* delete-horizontal-space (): Commands For Killing. +* digit-argument (M-0, M-1, ... M-): Numeric Arguments. +* do-uppercase-version (M-a, M-b, M-X, ...): Miscellaneous Commands. +* downcase-word (M-l): Commands For Text. +* dump-functions (): Miscellaneous Commands. +* dump-macros (): Miscellaneous Commands. +* dump-variables (): Miscellaneous Commands. +* end-kbd-macro (C-x )): Keyboard Macros. +* end-of-history (M->): Commands For History. +* end-of-line (C-e): Commands For Moving. +* exchange-point-and-mark (C-x C-x): Miscellaneous Commands. +* forward-char (C-f): Commands For Moving. +* forward-search-history (C-s): Commands For History. +* forward-word (M-f): Commands For Moving. +* history-search-backward (): Commands For History. +* history-search-forward (): Commands For History. +* insert-comment (M-#): Miscellaneous Commands. +* insert-completions (M-*): Commands For Completion. +* kill-line (C-k): Commands For Killing. +* kill-region (): Commands For Killing. +* kill-whole-line (): Commands For Killing. +* kill-word (M-d): Commands For Killing. +* next-history (C-n): Commands For History. +* non-incremental-forward-search-history (M-n): Commands For History. +* non-incremental-reverse-search-history (M-p): Commands For History. +* possible-completions (M-?): Commands For Completion. +* prefix-meta (ESC): Miscellaneous Commands. +* previous-history (C-p): Commands For History. +* quoted-insert (C-q, C-v): Commands For Text. +* re-read-init-file (C-x C-r): Miscellaneous Commands. +* redraw-current-line (): Commands For Moving. +* reverse-search-history (C-r): Commands For History. +* revert-line (M-r): Miscellaneous Commands. +* self-insert (a, b, A, 1, !, ...): Commands For Text. +* set-mark (C-@): Miscellaneous Commands. +* start-kbd-macro (C-x (): Keyboard Macros. +* tab-insert (M-TAB): Commands For Text. +* tilde-expand (M-~): Miscellaneous Commands. +* transpose-chars (C-t): Commands For Text. +* transpose-words (M-t): Commands For Text. +* undo (C-_, C-x C-u): Miscellaneous Commands. +* universal-argument (): Numeric Arguments. +* unix-line-discard (C-u): Commands For Killing. +* unix-word-rubout (C-w): Commands For Killing. +* upcase-word (M-u): Commands For Text. +* yank (C-y): Commands For Killing. +* yank-last-arg (M-., M-_): Commands For History. +* yank-nth-arg (M-C-y): Commands For History. +* yank-pop (M-y): Commands For Killing. + + +File: bashref.info, Node: Concept Index, Prev: Function Index, Up: Top + +Concept Index +************* + +* Menu: + +* alias expansion: Aliases. +* arithmetic evaluation: Arithmetic Evaluation. +* arithmetic expansion: Arithmetic Expansion. +* arithmetic, shell: Shell Arithmetic. +* arrays: Arrays. +* background: Job Control Basics. +* Bash configuration: Basic Installation. +* Bash installation: Basic Installation. +* Bourne shell: Basic Shell Features. +* brace expansion: Brace Expansion. +* builtin: Definitions. +* command editing: Readline Bare Essentials. +* command execution: Command Search and Execution. +* command history: Bash History Facilities. +* command search: Command Search and Execution. +* command substitution: Command Substitution. +* command timing: Pipelines. +* commands, conditional: Conditional Constructs. +* commands, grouping: Command Grouping. +* commands, lists: Lists. +* commands, looping: Looping Constructs. +* commands, pipelines: Pipelines. +* commands, simple: Simple Commands. +* comments, shell: Comments. +* configuration: Basic Installation. +* control operator: Definitions. +* editing command lines: Readline Bare Essentials. +* environment: Environment. +* evaluation, arithmetic: Arithmetic Evaluation. +* event designators: Event Designators. +* exit status <1>: Definitions. +* exit status: Exit Status. +* expansion: Shell Expansions. +* expansion, arithmetic: Arithmetic Expansion. +* expansion, brace: Brace Expansion. +* expansion, filename: Filename Expansion. +* expansion, parameter: Shell Parameter Expansion. +* expansion, pathname: Filename Expansion. +* expansion, tilde: Tilde Expansion. +* expressions, arithmetic: Arithmetic Evaluation. +* expressions, conditional: Bash Conditional Expressions. +* field: Definitions. +* filename: Definitions. +* filename expansion: Filename Expansion. +* foreground: Job Control Basics. +* functions, shell: Shell Functions. +* history events: Event Designators. +* history expansion: History Interaction. +* history list: Bash History Facilities. +* History, how to use: Job Control Variables. +* identifier: Definitions. +* initialization file, readline: Readline Init File. +* installation: Basic Installation. +* interaction, readline: Readline Interaction. +* interactive shell <1>: Is This Shell Interactive?. +* interactive shell: Invoking Bash. +* job: Definitions. +* job control <1>: Definitions. +* job control: Job Control Basics. +* kill ring: Readline Killing Commands. +* killing text: Readline Killing Commands. +* localization: Locale Translation. +* metacharacter: Definitions. +* name: Definitions. +* notation, readline: Readline Bare Essentials. +* operator, shell: Definitions. +* parameter expansion: Shell Parameter Expansion. +* parameters: Shell Parameters. +* parameters, positional: Positional Parameters. +* parameters, special: Special Parameters. +* pathname expansion: Filename Expansion. +* pipeline: Pipelines. +* POSIX: Definitions. +* POSIX Mode: Bash POSIX Mode. +* process group: Definitions. +* process group ID: Definitions. +* process substitution: Process Substitution. +* prompting: Printing a Prompt. +* quoting: Quoting. +* quoting, ANSI: ANSI-C Quoting. +* Readline, how to use: Modifiers. +* redirection: Redirections. +* reserved word: Definitions. +* restricted shell: The Restricted Shell. +* return status: Definitions. +* shell function: Shell Functions. +* shell script: Shell Scripts. +* shell variable: Shell Parameters. +* signal: Definitions. +* signal handling: Signals. +* special builtin: Definitions. +* startup files: Bash Startup Files. +* suspending jobs: Job Control Basics. +* tilde expansion: Tilde Expansion. +* token: Definitions. +* variable, shell: Shell Parameters. +* word: Definitions. +* word splitting: Word Splitting. +* yanking text: Readline Killing Commands. + + + +Tag Table: +Node: Top1009 +Node: Introduction3117 +Node: What is Bash?3342 +Node: What is a shell?4426 +Node: Definitions6307 +Node: Basic Shell Features8947 +Node: Shell Syntax10468 +Node: Shell Operation10758 +Node: Quoting11992 +Node: Escape Character13027 +Node: Single Quotes13458 +Node: Double Quotes13787 +Node: ANSI-C Quoting14483 +Node: Locale Translation15215 +Node: Comments15636 +Node: Simple Commands16160 +Node: Pipelines16749 +Node: Lists17820 +Node: Looping Constructs19095 +Node: Conditional Constructs20272 +Node: Command Grouping22337 +Node: Shell Functions23721 +Node: Shell Parameters25489 +Node: Positional Parameters26812 +Node: Special Parameters27506 +Node: Shell Expansions29998 +Node: Shell Parameter Expansion31998 +Node: Command Substitution38003 +Node: Process Substitution39003 +Node: Word Splitting39909 +Node: Filename Expansion41361 +Node: Quote Removal43727 +Node: Redirections44013 +Node: Executing Commands49754 +Node: Command Search and Execution50209 +Node: Environment51943 +Node: Exit Status53579 +Node: Signals54596 +Node: Shell Scripts55807 +Node: Bourne Shell Features57676 +Node: Bourne Shell Builtins58346 +Node: Bourne Shell Variables66619 +Node: Other Bourne Shell Features68156 +Node: Major Differences From The Bourne Shell68913 +Node: Csh Features79111 +Node: Brace Expansion80029 +Node: Tilde Expansion81584 +Node: C Shell Builtins82216 +Node: C Shell Variables86732 +Node: Korn Shell Features87140 +Node: Korn Shell Constructs87868 +Node: Korn Shell Builtins89562 +Node: Korn Shell Variables91720 +Node: Aliases93505 +Node: Alias Builtins95969 +Node: Bash Features96585 +Node: Invoking Bash97576 +Node: Bash Startup Files101441 +Node: Is This Shell Interactive?105024 +Node: Bash Builtins105755 +Node: The Set Builtin121569 +Node: Bash Conditional Expressions126939 +Node: Bash Variables131590 +Node: Shell Arithmetic141103 +Node: Arithmetic Evaluation141571 +Node: Arithmetic Expansion143601 +Node: Arithmetic Builtins144405 +Node: Arrays144876 +Node: Printing a Prompt147903 +Node: The Restricted Shell149501 +Node: Bash POSIX Mode150731 +Node: Job Control154303 +Node: Job Control Basics154768 +Node: Job Control Builtins158911 +Node: Job Control Variables161794 +Node: Using History Interactively162955 +Node: Bash History Facilities163544 +Node: History Interaction165942 +Node: Event Designators168504 +Node: Word Designators169427 +Node: Modifiers170676 +Node: Command Line Editing171993 +Node: Introduction and Notation172653 +Node: Readline Interaction173661 +Node: Readline Bare Essentials174849 +Node: Readline Movement Commands176378 +Node: Readline Killing Commands177268 +Node: Readline Arguments178970 +Node: Searching179943 +Node: Readline Init File181579 +Node: Readline Init File Syntax182635 +Node: Conditional Init Constructs190424 +Node: Sample Init File192705 +Node: Bindable Readline Commands195722 +Node: Commands For Moving196472 +Node: Commands For History197319 +Node: Commands For Text199992 +Node: Commands For Killing201734 +Node: Numeric Arguments203760 +Node: Commands For Completion204386 +Node: Keyboard Macros207348 +Node: Miscellaneous Commands207906 +Node: Readline vi Mode211937 +Node: Installing Bash212813 +Node: Basic Installation213890 +Node: Compilers and Options216389 +Node: Compiling For Multiple Architectures217123 +Node: Installation Names218780 +Node: Specifying the System Type219502 +Node: Sharing Defaults220213 +Node: Operation Controls220878 +Node: Optional Features221783 +Node: Reporting Bugs226408 +Node: Builtin Index227485 +Node: Reserved Word Index230898 +Node: Variable Index232206 +Node: Function Index237285 +Node: Concept Index241643 + +End Tag Table diff --git a/doc/bashref.texi b/doc/bashref.texi new file mode 100644 index 0000000..fe871c3 --- /dev/null +++ b/doc/bashref.texi @@ -0,0 +1,5331 @@ +\input texinfo.tex @c -*- texinfo -*- +@c %**start of header +@setfilename bashref.info +@settitle Bash Reference Manual +@c %**end of header + +@ignore +last change: Mon Nov 25 11:47:06 EST 1996 +@end ignore + +@set EDITION 2.0 +@set VERSION 2.0 +@set UPDATED 25 November 1996 +@set UPDATE-MONTH November 1996 + +@iftex +@finalout +@end iftex + +@setchapternewpage odd +@defcodeindex bt +@defcodeindex rw +@set BashFeatures + +@ifinfo +@format +This text is a brief description of the features that are present in +the Bash shell. + +This is Edition @value{EDITION}, last updated @value{UPDATED}, +of @cite{The GNU Bash Reference Manual}, +for @code{Bash}, Version @value{VERSION}. + +Copyright (C) 1991, 1993, 1996 Free Software Foundation, Inc. + +Permission is granted to make and distribute verbatim copies of +this manual provided the copyright notice and this permission notice +are 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 format +@end ifinfo + +@titlepage +@title Bash Reference Manual +@subtitle Reference Documentation for Bash +@subtitle Edition @value{EDITION}, for @code{bash} Version @value{VERSION}. +@subtitle @value{UPDATED} +@author Chet Ramey, Case Western Reserve University +@author Brian Fox, Free Software Foundation +@page +@vskip 0pt plus 1filll +Copyright @copyright{} 1991, 1993, 1996 Free Software Foundation, Inc. + +Permission is granted to make and distribute verbatim copies of +this manual provided the copyright notice and this permission notice +are preserved on all copies. + +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 Free Software Foundation. +@end titlepage + +@ifinfo +@node Top, Introduction, (dir), (dir) +@top Bash Features +@end ifinfo + +@ifinfo +This text is a brief description of the features that are present in +the Bash shell. + +This is Edition @value{EDITION}, last updated @value{UPDATED}, +of @cite{The GNU Bash Reference Manual}, +for @code{Bash}, Version @value{VERSION}. + +Copyright (C) 1991, 1993, 1996 Free Software Foundation, Inc. + +Bash contains features that appear in other popular shells, and some +features that only appear in Bash. Some of the shells that Bash has +borrowed concepts from are the Bourne Shell (@file{sh}), the Korn Shell +(@file{ksh}), and the C-shell (@file{csh} and its successor, +@file{tcsh}). The following menu breaks the features up into +categories based upon which one of these other shells inspired the +feature. + +This manual is meant as a brief introduction to features found in +Bash. The Bash manual page should be used as the definitive +reference on shell behavior. + +@menu +* Introduction:: An introduction to the shell. + +* Definitions:: Some definitions used in the rest of this + manual. + +* Basic Shell Features:: The shell "building blocks". + +* Bourne Shell Features:: Features similar to those found in the + Bourne shell. + +* Csh Features:: Features originally found in the + Berkeley C-Shell. + +* Korn Shell Features:: Features originally found in the Korn + Shell. + +* Bash Features:: Features found only in Bash. + +* Job Control:: A chapter describing what job control is + and how Bash allows you to use it. + +* Using History Interactively:: Chapter dealing with history expansion + rules. + +* Command Line Editing:: Chapter describing the command line + editing features. + +* Installing Bash:: How to build and install Bash on your system. + +* Reporting Bugs:: How to report bugs in Bash. + +* Builtin Index:: Index of Bash builtin commands. + +* Reserved Word Index:: Index of Bash reserved words. + +* Variable Index:: Quick reference helps you find the + variable you want. + +* Function Index:: Index of bindable Readline functions. + +* Concept Index:: General index for concepts described in + this manual. +@end menu +@end ifinfo + +@node Introduction +@chapter Introduction +@menu +* What is Bash?:: A short description of Bash. + +* What is a shell?:: A brief introduction to shells. +@end menu + +@node What is Bash? +@section What is Bash? + +Bash is the shell, or command language interpreter, +that will appear in the @sc{GNU} operating system. +The name is an acronym for the @samp{Bourne-Again SHell}, +a pun on Steve Bourne, the author of the direct ancestor of the current +Unix shell @code{/bin/sh}, +which appeared in the Seventh Edition Bell Labs Research version +of Unix. + +Bash is an @code{sh}-compatible shell that incorporates useful +features from the Korn shell @code{ksh} and the C shell @code{csh}. +It is ultimately intended to be a +conformant implementation of the @sc{IEEE} @sc{POSIX} Shell and Tools +specification (@sc{IEEE} Working Group 1003.2). It offers functional +improvements over @code{sh} for both interactive and programming use. + +While the @sc{GNU} operating system will include a version +of @code{csh}, Bash will be the default shell. +Like other @sc{GNU} software, Bash is quite portable. It currently runs +on nearly every version of Unix and a few other operating systems @minus{} +independently-supported ports exist for @sc{OS/2} and Windows @sc{NT}. + +@node What is a shell? +@section What is a shell? + +At its base, a shell is simply a macro processor that executes +commands. A Unix shell is both a command interpreter, which +provides the user interface to the rich set of Unix utilities, +and a programming language, allowing these utilitites to be +combined. The shell reads commands either from a terminal or a +file. Files containing commands can be created, and become +commands themselves. These new commands have the same status as +system commands in directories like @file{/bin}, allowing users +or groups to establish custom environments. + +A shell allows execution of Unix commands, both synchronously and +asynchronously. The @dfn{redirection} constructs permit +fine-grained control of the input and output of those commands, +and the shell allows control over the contents of their +environment. Unix shells also provide a small set of built-in +commands (@dfn{builtins}) implementing functionality impossible +(e.g., @code{cd}, @code{break}, @code{continue}, and +@code{exec}), or inconvenient (@code{history}, @code{getopts}, +@code{kill}, or @code{pwd}, for example) to obtain via separate +utilities. Shells may be used interactively or +non-interactively: they accept input typed from the keyboard or +from a file. All of the shell builtins are described in +subsequent sections. + +While executing commands is essential, most of the power (and +complexity) of shells is due to their embedded programming +languages. Like any high-level language, the shell provides +variables, flow control constructs, quoting, and functions. + +Shells have begun offering features geared specifically for +interactive use rather than to augment the programming language. +These interactive features include job control, command line +editing, history and aliases. Each of these features is +described in this manual. + +@node Definitions +@chapter Definitions +These definitions are used throughout the remainder of this manual. + +@table @code + +@item POSIX +@cindex POSIX +A family of open system standards based on Unix. Bash +is concerned with @sc{POSIX} 1003.2, the Shell and Tools Standard. + +@item blank +A space or tab character. + +@item builtin +@cindex builtin +A command that is implemented internally by the shell itself, rather +than by an executable program somewhere in the file system. + +@item control operator +@cindex control operator +A @code{word} that performs a control function. It is a @code{newline} +or one of the following: +@samp{||}, @samp{&&}, @samp{&}, @samp{;}, @samp{;;}, +@samp{|}, @samp{(}, or @samp{)}. + +@item exit status +@cindex exit status +The value returned by a command to its caller. + +@item field +@cindex field +A unit of text that is the result of one of the shell expansions. After +expansion, when executing a command, the resulting fields are used as +the command name and arguments. + +@item filename +@cindex filename +A string of characters used to identify a file. + +@item job +@cindex job +A set of processes comprising a pipeline, and any processes descended +from it, that are all in the same process group. + +@item job control +@cindex job control +A mechanism by which users can selectively start and stop execution +of processes. + +@item metacharacter +@cindex metacharacter +A character that, when unquoted, separates words. A metacharacter is +a @code{blank} or one of the following characters: +@samp{|}, @samp{&}, @samp{;}, @samp{(}, @samp{)}, @samp{<}, or +@samp{>}. + +@item name +@cindex name +@cindex identifier +A @code{word} consisting solely of letters, numbers, and underscores, +and beginning with a letter or underscore. @code{Name}s are used as +shell variable and function names. +Also referred to as an @code{identifier}. + +@item operator +@cindex operator, shell +A @code{control operator} or a @code{redirection operator}. +@xref{Redirections}, for a list of redirection operators. + +@item process group +@cindex process group +A collection of related processes each having the same process +group @sc{ID}. + +@item process group ID +@cindex process group ID +A unique identifer that represents a @code{process group} +during its lifetime. + +@item reserved word +@cindex reserved word +A @code{word} that has a special meaning to the shell. Most reserved +words introduce shell flow control constructs, such as @code{for} and +@code{while}. + +@item return status +@cindex return status +A synonym for @code{exit status}. + +@item signal +@cindex signal +A mechanism by which a process may be notified by the kernal +of an event occurring in the system. + +@item special builtin +@cindex special builtin +A shell builtin command that has been classified as special by the +@sc{POSIX.2} standard. + +@item token +@cindex token +A sequence of characters considered a single unit by the shell. It is +either a @code{word} or an @code{operator}. + +@item word +@cindex word +A @code{token} that is not an @code{operator}. +@end table + +@node Basic Shell Features +@chapter Basic Shell Features +@cindex Bourne shell + +Bash is an acronym for @samp{Bourne-Again SHell}. +The Bourne shell is +the traditional Unix shell originally written by Stephen Bourne. +All of the Bourne shell builtin commands are available in Bash, +and the rules for evaluation and quoting are taken from the @sc{POSIX} +1003.2 specification for the `standard' Unix shell. + +This chapter briefly summarizes the shell's "building blocks": +commands, control structures, shell functions, shell @i{parameters}, +shell expansions, +@i{redirections}, which are a way to direct input and output from +and to named files, and how the shell executes commands. + +@menu +* Shell Syntax:: What your input means to the shell. +* Simple Commands:: The most common type of command. +* Pipelines:: Connecting the input and output of several + commands. +* Lists:: How to execute commands sequentially. +* Looping Constructs:: Shell commands for iterative action. +* Conditional Constructs:: Shell commands for conditional execution. +* Command Grouping:: Ways to group commands. +* Shell Functions:: Grouping commands by name. +* Shell Parameters:: Special shell variables. +* Shell Expansions:: How Bash expands variables and the various + expansions available. +* Redirections:: A way to control where input and output go. +* Executing Commands:: What happens when you run a command. +* Shell Scripts:: Executing files of shell commands. +@end menu + +@node Shell Syntax +@section Shell Syntax +@menu +* Shell Operation:: The basic operation of the shell. + +* Quoting:: How to remove the special meaning from characters. + +* Comments:: How to specify comments. +@end menu + +@node Shell Operation +@subsection Shell Operation + +The following is a brief description of the shell's operation when it +reads and executes a command. Basically, the shell does the +following: + +@enumerate +@item +Reads its input from a file (@pxref{Shell Scripts}), from a string +supplied as an argument to the @samp{-c} invocation option +(@pxref{Invoking Bash}), or from the user's terminal. + +@item +Breaks the input into words and operators, obeying the quoting rules +described in @ref{Quoting}. Tokens are separated by +@code{metacharacters}. Alias expansion is performed by this step +(@pxref{Aliases}). + +@item +Parses the tokens into simple and compound commands. + +@item +Performs the various shell expansions (@pxref{Shell Expansions}), breaking +the expanded tokens into lists of filenames (@pxref{Filename Expansion}) +and commands and arguments. + +@item +Performs any necessary redirections (@pxref{Redirections}) and removes +the redirection operators and their operands from the argument list. + +@item +Executes the command (@pxref{Executing Commands}). + +@item +Optionally waits for the command to complete and collects its exit +status. + +@end enumerate + +@node Quoting +@subsection Quoting +@cindex quoting +@menu +* Escape Character:: How to remove the special meaning from a single + character. +* Single Quotes:: How to inhibit all interpretation of a sequence + of characters. +* Double Quotes:: How to suppress most of the interpretation of a + sequence of characters. +* ANSI-C Quoting:: How to expand ANSI-C sequences in quoted strings. + +* Locale Translation:: How to translate strings into different languages. +@end menu + +Quoting is used to remove the special meaning of certain +characters or words to the shell. Quoting can be used to +disable special treatment for special characters, to prevent +reserved words from being recognized as such, and to prevent +parameter expansion. + +Each of the shell @code{metacharacters} (@pxref{Definitions}) +has special meaning to the shell and must be quoted if they are to +represent themselves. There are three quoting mechanisms: the +@var{escape character}, single quotes, and double quotes. + +@node Escape Character +@subsubsection Escape Character +A non-quoted backslash @samp{\} is the Bash escape character. +It preserves the literal value of the next character that follows, +with the exception of @code{newline}. If a @code{\newline} pair +appears, and the backslash is not quoted, the @code{\newline} +is treated as a line continuation (that is, it is effectively ignored). + +@node Single Quotes +@subsubsection Single Quotes + +Enclosing characters in single quotes preserves the literal value +of each character within the quotes. A single quote may not occur +between single quotes, even when preceded by a backslash. + +@node Double Quotes +@subsubsection Double Quotes + +Enclosing characters in double quotes preserves the literal value +of all characters within the quotes, with the exception of +@samp{$}, @samp{`}, and @samp{\}. +The characters @samp{$} and @samp{`} +retain their special meaning within double quotes. The backslash +retains its special meaning only when followed by one of the following +characters: +@samp{$}, @samp{`}, @samp{"}, @samp{\}, or @code{newline}. +A double quote may be quoted within double quotes by preceding it with +a backslash. + +The special parameters @samp{*} and @samp{@@} have special meaning +when in double quotes (@pxref{Shell Parameter Expansion}). + +@node ANSI-C Quoting +@subsubsection ANSI-C Quoting +@cindex quoting, ANSI + +Words of the form @code{$'@var{string}'} are treated specially. The +word expands to @var{string}, with backslash-escaped characters replaced +as specifed by the ANSI C standard. Backslash escape sequences, if +present, are decoded as follows: + +@table @code +@item \a +alert (bell) +@item \b +backspace +@item \e +an escape character (not ANSI C) +@item \f +form feed +@item \n +newline +@item \r +carriage return +@item \t +horizontal tab +@item \v +vertical tab +@item \\ +backslash +@item \@var{nnn} +the character whose @code{ASCII} code is @var{nnn} in octal +@end table + +@noindent +The result is single-quoted, as if the dollar sign had not been present. + +@node Locale Translation +@subsubsection Locale-Specific Translation +@cindex localization + +A double-quoted string preceded by a dollar sign (@samp{$}) will cause +the string to be translated according to the current locale. +If the current locale is @code{C} or @code{POSIX}, the dollar sign +is ignored. +If the string is translated and replaced, the replacement is +double-quoted. + +@node Comments +@subsection Comments +@cindex comments, shell + +In a non-interactive shell, or an interactive shell in which the +@code{interactive_comments} option to the @code{shopt} +builtin is enabled (@pxref{Bash Builtins}), +a word beginning with @samp{#} +causes that word and all remaining characters on that line to +be ignored. An interactive shell without the @code{interactive_comments} +option enabled does not allow comments. The @code{interactive_comments} +option is on by default in interactive shells. + +@node Simple Commands +@section Simple Commands +@cindex commands, simple + +A simple command is the kind of command you'll encounter most often. +It's just a sequence of words separated by @code{blank}s, terminated +by one of the shell control operators (@pxref{Definitions}). The +first word generally specifies a command to be executed. + +The return status (@pxref{Exit Status}) of a simple command is +its exit status as provided +by the @sc{POSIX.1} @code{waitpid} function, or 128+@var{n} if the command +was terminated by signal @var{n}. + +@node Pipelines +@section Pipelines +@cindex pipeline +@cindex commands, pipelines + +A @code{pipeline} is a sequence of simple commands separated by +@samp{|}. + +@rwindex time +@rwindex ! +@cindex command timing +The format for a pipeline is +@example +[@code{time} [@code{-p}]] [@code{!}] @var{command1} [@code{|} @var{command2} @dots{}] +@end example + +@noindent +The output of each command in the pipeline is connected to the input of +the next command. That is, each command reads the previous command's +output. + +The reserved word @code{time} causes timing statistics +to be printed for the pipeline once it finishes. +The @samp{-p} option changes the output format to that specified +by @sc{POSIX}. +The @code{TIMEFORMAT} variable may be set to a format string that +specifies how the timing information should be displayed. +@xref{Bash Variables}, for a description of the available formats. + +Each command in a pipeline is executed in its own subshell. The exit +status of a pipeline is the exit status of the last command in the +pipeline. If the reserved word @samp{!} precedes the pipeline, the +exit status is the logical @sc{NOT} of the exit status of the last command. + +@node Lists +@section Lists of Commands +@cindex commands, lists + +A @code{list} is a sequence of one or more pipelines separated by one +of the operators @samp{;}, @samp{&}, @samp{&&}, or @samp{||}, +and optionally terminated by one of @samp{;}, @samp{&}, or a +@code{newline}. + +Of these list operators, @samp{&&} and @samp{||} +have equal precedence, followed by @samp{;} and @samp{&}, +which have equal precedence. + +If a command is terminated by the control operator @samp{&}, +the shell executes the command in the @var{background} +in a subshell. The shell does not wait for the command to +finish, and the return status is 0 (true). Commands separated by a +@samp{;} are executed sequentially; the shell waits for each +command to terminate in turn. The return status is the +exit status of the last command executed. + +The control operators @samp{&&} and @samp{||} +denote @sc{AND} lists and @sc{OR} lists, respectively. +An @sc{AND} list has the form +@example +@var{command} && @var{command2} +@end example + +@noindent +@var{command2} is executed if, and only if, @var{command} +returns an exit status of zero. + +An @sc{OR} list has the form +@example +@var{command} || @var{command2} +@end example + +@noindent +@var{command2} is executed if and only if @var{command} +returns a non-zero exit status. + +The return status of +@sc{AND} and @sc{OR} lists is the exit status of the last command +executed in the list. + +@node Looping Constructs +@section Looping Constructs +@cindex commands, looping + +Note that wherever you see a @samp{;} in the description of a +command's syntax, it may be replaced indiscriminately with +one or more newlines. + +Bash supports the following looping constructs. + +@table @code +@item until +@rwindex until +@rwindex do +@rwindex done +The syntax of the @code{until} command is: +@example +until @var{test-commands}; do @var{consequent-commands}; done +@end example +Execute @var{consequent-commands} as long as the final command in +@var{test-commands} has an exit status which is not zero. + +@item while +@rwindex while +The syntax of the @code{while} command is: +@example +while @var{test-commands}; do @var{consequent-commands}; done +@end example + +Execute @var{consequent-commands} as long as the final command in +@var{test-commands} has an exit status of zero. + +@item for +@rwindex for +The syntax of the @code{for} command is: + +@example +for @var{name} [in @var{words} @dots{}]; do @var{commands}; done +@end example +Execute @var{commands} for each member in @var{words}, with @var{name} +bound to the current member. If @samp{in @var{words}} is not +present, @samp{in "$@@"} is assumed. + +@end table + +The @code{break} and @code{continue} builtins (@pxref{Bourne Shell Builtins}) +may be used to control loop execution. + +@node Conditional Constructs +@section Conditional Constructs +@cindex commands, conditional + +@table @code +@item if +@rwindex if +@rwindex then +@rwindex else +@rwindex elif +@rwindex fi +The syntax of the @code{if} command is: + +@example +if @var{test-commands}; then + @var{consequent-commands}; +[elif @var{more-test-commands}; then + @var{more-consequents};] +[else @var{alternate-consequents};] +fi +@end example + +Execute @var{consequent-commands} only if the final command in +@var{test-commands} has an exit status of zero. +Otherwise, each @code{elif} list is executed in turn, +and if its exit status is zero, +the corresponding @var{more-consequents} is executed and the +command completes. +If @samp{else @var{alternate-consequents}} is present, and +the final command in the final @code{if} or @code{elif} clause +has a non-zero exit status, then execute @var{alternate-consequents}. + +@item case +@rwindex case +@rwindex in +@rwindex esac +The syntax of the @code{case} command is: + +@example +@code{case @var{word} in [@var{pattern} [| @var{pattern}]@dots{}) @var{commands} ;;]@dots{} esac} +@end example + +Selectively execute @var{commands} based upon @var{word} matching +@var{pattern}. The @samp{|} is used to separate multiple patterns. + +Here is an example using @code{case} in a script that could be used to +describe one interesting feature of an animal: + +@example +echo -n "Enter the name of an animal: " +read ANIMAL +echo -n "The $ANIMAL has " +case $ANIMAL in + horse | dog | cat) echo -n "four";; + man | kangaroo ) echo -n "two";; + *) echo -n "an unknown number of";; +esac +echo " legs." +@end example + +@item ((@dots{})) +@example +(( @var{expression} )) +@end example + +The @var{expression} is evaluated according to the rules described +below ((@pxref{Arithmetic Evaluation}). +If the value of the expression is non-zero, the return status is 0; +otherwise the return status is 1. This is exactly equivalent to +@example +let "@var{expression}" +@end example + +@end table + +The @code{select} construct, which allows users to choose from a list +of items presented as a menu, is also available. +@xref{Korn Shell Constructs}, for a full description of @code{select}. + +@node Command Grouping +@section Grouping Commands +@cindex commands, grouping + +Bash provides two ways to group a list of commands to be executed +as a unit. When commands are grouped, redirections may be applied +to the entire command list. For example, the output of all the +commands in the list may be redirected to a single stream. + +@table @code +@item () +@example +( @var{list} ) +@end example + +Placing a list of commands between parentheses causes a subshell +to be created, and each of the commands to be executed in that +subshell. Since the @var{list} is executed in a subshell, variable +assignments do not remain in effect after the subshell completes. + +@item @{@} +@rwindex @{ +@rwindex @} +@example +@{ @var{list}; @} +@end example + +Placing a list of commands between curly braces causes the list to +be executed in the current shell context. No subshell is created. +The semicolon following @var{list} is required. +@end table + +In addition to the creation of a subshell, there is a subtle difference +between these two constructs due to historical reasons. The braces +are @code{reserved words}, so they must be separated from the @var{list} +by @code{blank}s. The parentheses are @code{operators}, and are +recognized as separate tokens by the shell even if they are not separated +from @code{list} by whitespace. + +The exit status of both of these constructs is the exit status of +@var{list}. + +@node Shell Functions +@section Shell Functions +@cindex shell function +@cindex functions, shell + +Shell functions are a way to group commands for later execution +using a single name for the group. They are executed just like +a "regular" command. Shell functions are executed in the current +shell context; no new process is created to interpret them. + +Functions are declared using this syntax: +@rwindex function +@example +[ @code{function} ] @var{name} () @{ @var{command-list}; @} +@end example + +This defines a shell function named @var{name}. The reserved +word @code{function} is optional. The @var{body} of the +function is the @var{command-list} between @{ and @}. This list +is executed whenever @var{name} is specified as the +name of a command. The exit status of a function is +the exit status of the last command executed in the body. + +When a function is executed, the arguments to the +function become the positional parameters +during its execution (@pxref{Positional Parameters}). +The special parameter +@samp{#} that gives the number of positional parameters +is updated to reflect the change. Positional parameter @code{0} +is unchanged. + +If the builtin command @code{return} +is executed in a function, the function completes and +execution resumes with the next command after the function +call. When a function completes, the values of the +positional parameters and the special parameter @samp{#} +are restored to the values they had prior to function +execution. If a numeric argument is given to @code{return}, +that is the function return status. + +Variables local to the function may be declared with the +@code{local} builtin. These variables are visible only to +the function and the commands it invokes. + +Functions may be recursive. No limit is placed on the number of +recursive calls. + +@node Shell Parameters +@section Shell Parameters +@cindex parameters +@cindex variable, shell +@cindex shell variable + +@menu +* Positional Parameters:: The shell's command-line arguments. +* Special Parameters:: Parameters with special meanings. +@end menu + +A @var{parameter} is an entity that stores values. +It can be a @code{name}, a number, or one of the special characters +listed below. +For the shell's purposes, a @var{variable} is a parameter denoted by a +@code{name}. + +A parameter is set if it has been assigned a value. The null string is +a valid value. Once a variable is set, it may be unset only by using +the @code{unset} builtin command. + +A variable may be assigned to by a statement of the form +@example +@var{name}=[@var{value}] +@end example +@noindent +If @var{value} +is not given, the variable is assigned the null string. All +@var{value}s undergo tilde expansion, parameter and variable expansion, +command substitution, arithmetic expansion, and quote +removal (detailed below). If the variable has its @samp{-i} attribute +set (see the description of the @code{declare} builtin in +@ref{Bash Builtins}), then @var{value} +is subject to arithmetic expansion even if the @code{$((@dots{}))} +syntax does not appear (@pxref{Arithmetic Expansion}). +Word splitting is not performed, with the exception +of @code{"$@@"} as explained below. +Filename expansion is not performed. + +@node Positional Parameters +@subsection Positional Parameters +@cindex parameters, positional + +A @var{positional parameter} +is a parameter denoted by one or more +digits, other than the single digit @code{0}. Positional parameters are +assigned from the shell's arguments when it is invoked, +and may be reassigned using the @code{set} +builtin command. Positional parameters may not be assigned to +with assignment statements. The positional parameters are +temporarily replaced when a shell function is executed +(@pxref{Shell Functions}). + +When a positional parameter consisting of more than a single +digit is expanded, it must be enclosed in braces. + +@node Special Parameters +@subsection Special Parameters +@cindex parameters, special + +The shell treats several parameters specially. These parameters may +only be referenced; assignment to them is not allowed. + +@vtable @code + +@item * +Expands to the positional parameters, starting from one. When the +expansion occurs within double quotes, it expands to a single word +with the value of each parameter separated by the first character +of the @code{IFS} +special variable. That is, @code{"$*"} is equivalent +to @code{"$1@var{c}$2@var{c}@dots{}"}, where @var{c} +is the first character of the value of the @code{IFS} +variable. If @code{IFS} +is null or unset, the parameters are separated by spaces. + +@item @@ +Expands to the positional parameters, starting from one. When the +expansion occurs within double quotes, each parameter expands as a +separate word. That is, @code{"$@@"} is equivalent to +@code{"$1" "$2" @dots{}}. +When there are no positional parameters, @code{"$@@"} and +@code{$@@} +expand to nothing (i.e., they are removed). + +@item # +Expands to the number of positional parameters in decimal. + +@item ? +Expands to the exit status of the most recently executed foreground +pipeline. + +@item - +Expands to the current option flags as specified upon invocation, +by the @code{set} +builtin command, or those set by the shell itself +(such as the @samp{-i} option). + +@item $ +Expands to the process @sc{ID} of the shell. In a @code{()} subshell, it +expands to the process @sc{ID} of the current shell, not the +subshell. + +@item ! +Expands to the process @sc{ID} of the most recently executed background +(asynchronous) command. + +@item 0 +Expands to the name of the shell or shell script. This is set at +shell initialization. If Bash is invoked with a file of commands, +@code{$0} is set to the name of that file. If Bash +is started with the @samp{-c} option, then @code{$0} +is set to the first argument after the string to be +executed, if one is present. Otherwise, it is set +to the filename used to invoke Bash, as given by argument zero. + +@item _ +At shell startup, set to the absolute filename 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 filename 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. +@end vtable + +@node Shell Expansions +@section Shell Expansions +@cindex expansion + +Expansion is performed on the command line after it has been split into +@code{token}s. There are seven kinds of expansion performed: +@itemize @bullet +@item brace expansion +@item tilde expansion +@item parameter and variable expansion +@item command substitution +@item arithmetic expansion +@item word splitting +@item filename expansion +@end itemize + +@menu +* Shell Parameter Expansion:: How Bash expands variables to their values. +* Command Substitution:: Using the output of a command as an argument. +* Process Substitution:: A way to write and read to and from a + command. +* Word Splitting:: How the results of expansion are split into separate + arguments. +* Filename Expansion:: A shorthand for specifying filenames matching patterns. +* Quote Removal:: How and when quote characters are removed from + words. +@end menu + +Brace expansion, tilde expansion, and arithmetic expansion are described +in other sections. For brace expansion, see @ref{Brace Expansion}; for +tilde expansion, see @ref{Tilde Expansion}; and for arithmetic expansion, +see @ref{Arithmetic Expansion}. + +The order of expansions is: brace expansion, tilde expansion, +parameter, variable, and arithmetic expansion and +command substitution +(done in a left-to-right fashion), word splitting, and filename +expansion. + +On systems that can support it, there is an additional expansion +available: @var{process substitution}. This is performed at the +same time as parameter, variable, and arithemtic expansion and +command substitution. + +Only brace expansion, word splitting, and filename expansion +can change the number of words of the expansion; other expansions +expand a single word to a single word. +The only exceptions to this are the expansions of +@code{"$@@"} (@pxref{Special Parameters}) and @code{"$@{[@@]@}"} +(@pxref{Arrays}). + +After all expansions, @code{quote removal} (@pxref{Quote Removal}) +is performed. + +@node Shell Parameter Expansion +@subsection Shell Parameter Expansion +@cindex parameter expansion +@cindex expansion, parameter + +The @samp{$} character introduces parameter expansion, +command substitution, or arithmetic expansion. The parameter name +or symbol to be expanded may be enclosed in braces, which +are optional but serve to protect the variable to be expanded from +characters immediately following it which could be +interpreted as part of the name. + +The basic form of parameter expansion is $@{@var{parameter}@}. +The value of @var{parameter} is substituted. The braces are required +when @var{parameter} +is a positional parameter with more than one digit, +or when @var{parameter} +is followed by a character that is not to be +interpreted as part of its name. + +If the first character of @var{parameter} is an exclamation point, +a level of variable indirection is introduced. +Bash uses the value of the variable formed from the rest of +@var{parameter} as the name of the variable; this variable is then +expanded and that value used in the rest of the substitution, rather +than the value of @var{parameter} itself. +This is known as @code{indirect expansion}. + +In each of the cases below, @var{word} is subject to tilde expansion, +parameter expansion, command substitution, and arithmetic expansion. +When not performing substring expansion, Bash tests for a parameter +that is unset or null; omitting the colon results in a test only for a +parameter that is unset. + +@table @code + +@item $@{@var{parameter}:@minus{}@var{word}@} +If @var{parameter} is unset or null, the expansion of +@var{word} is substituted. Otherwise, the value of +@var{parameter} is substituted. + +@item $@{@var{parameter}:=@var{word}@} +If @var{parameter} +is unset or null, the expansion of @var{word} +is assigned to @var{parameter}. +The value of @var{parameter} +is then substituted. Positional parameters and special parameters may +not be assigned to in this way. + +@item $@{@var{parameter}:?@var{word}@} +If @var{parameter} +is null or unset, the expansion of @var{word} (or a message +to that effect if @var{word} +is not present) is written to the standard error and the shell, if it +is not interactive, exits. Otherwise, the value of @var{parameter} is +substituted. + +@item $@{@var{parameter}:+@var{word}@} +If @var{parameter} +is null or unset, nothing is substituted, otherwise the expansion of +@var{word} is substituted. + +@item $@{@var{parameter}:@var{offset}@} +@itemx $@{@var{parameter}:@var{offset}:@var{length}@} +Expands to up to @var{length} characters of @var{parameter}, +starting at @var{offset}. +If @var{length} is omitted, expands to the substring of +@var{parameter}, starting at the character specified by @var{offset}. +@var{length} and @var{offset} are arithmetic expressions +(@pxref{Arithmetic Evaluation}). +This is referred to as Substring Expansion. + +@var{length} must evaluate to a number greater than or equal to zero. +If @var{offset} evaluates to a number less than zero, the value +is used as an offset from the end of the value of @var{parameter}. +If @var{parameter} is @samp{@@}, the result is @var{length} positional +parameters beginning at @var{offset}. +If @var{parameter} is an array name indexed by @samp{@@} or @samp{*}, +the result is the @var{length} +members of the array beginning with $@{@var{parameter}[@var{offset}]@}. +Substring indexing is zero-based unless the positional parameters are +used, in which case the indexing starts at 1. + +@item $@{#@var{parameter}@} +The length in characters of the value of @var{parameter} is substituted. +If @var{parameter} +is @samp{*} or @samp{@@}, +the length substituted is the number of positional parameters. +If @var{parameter} +is an array name subscripted +by @samp{*} or @samp{@@}, +the length substituted is the number of elements in the array. + +@item $@{@var{parameter}#@var{word}@} +@itemx $@{@var{parameter}##@var{word}@} +The @var{word} +is expanded to produce a pattern just as in filename +expansion (@pxref{Filename Expansion}). If the pattern matches +the beginning of the value of @var{parameter}, +then the expansion is the value of @var{parameter} +with the shortest matching pattern (the @samp{#} case) or the +longest matching pattern (the @samp{##} case) deleted. +If @var{parameter} is @samp{@@} or @samp{*}, +the pattern removal operation is applied to each positional +parameter in turn, and the expansion is the resultant list. +If @var{parameter} is an array variable subscripted with +@samp{@@} or @samp{*}, +the pattern removal operation is applied to each member of the +array in turn, and the expansion is the resultant list. + +@item $@{@var{parameter}%@var{word}@} +@itemx $@{@var{parameter}%%@var{word}@} +The @var{word} is expanded to produce a pattern just as in +filename expansion. +If the pattern matches a trailing portion of the value of +@var{parameter}, then the expansion is the value of @var{parameter} +with the shortest matching pattern (the @samp{%} case) or the +longest matching pattern (the @samp{%%} case) deleted. +If @var{parameter} is @samp{@@} or @samp{*}, +the pattern removal operation is applied to each positional +parameter in turn, and the expansion is the resultant list. +If @var{parameter} +is an array variable subscripted with @samp{@@} or @samp{*}, +the pattern removal operation is applied to each member of the +array in turn, and the expansion is the resultant list. + +@item $@{@var{parameter}/@var{pattern}/@var{string}@} +@itemx $@{@var{parameter}//@var{pattern}/@var{string}@} + +The @var{pattern} is expanded to produce a pattern just as in +filename expansion. +@var{Parameter} is expanded and the longest match of @var{pattern} +against its value is replaced with @var{string}. +In the first form, only the first match is replaced. +The second form causes all matches of @var{pattern} to be +replaced with @var{string}. +If @var{pattern} begins with @samp{#}, it must match at the beginning +of @var{string}. +If @var{pattern} begins with @samp{%}, it must match at the end +of @var{string}. +If @var{string} is null, matches of @var{pattern} are deleted +and the @code{/} following @var{pattern} may be omitted. +If @var{parameter} is @samp{@@} or @samp{*}, +the substitution operation is applied to each positional +parameter in turn, and the expansion is the resultant list. +If @var{parameter} +is an array variable subscripted with @samp{@@} or @samp{*}, +the substitution operation is applied to each member of the +array in turn, and the expansion is the resultant list. + +@end table + +@node Command Substitution +@subsection Command Substitution +@cindex command substitution + +Command substitution allows the output of a command to replace +the command name. There are two forms: +@example +$(@var{command}) +@end example +@noindent +or +@example +`@var{command}` +@end example + +@noindent +Bash performs the expansion by executing @var{command} and +replacing the command substitution with the standard output of the +command, with any trailing newlines deleted. + +When the old-style backquote form of substitution is used, +backslash retains its literal meaning except when followed by +@samp{$}, @samp{`}, or @samp{\}. +When using the @code{$(@var{command})} form, all characters between +the parentheses make up the command; none are treated specially. + +Command substitutions may be nested. To nest when using the old form, +escape the inner backquotes with backslashes. + +If the substitution appears within double quotes, word splitting and +filename expansion are not performed on the results. + +@node Process Substitution +@subsection Process Substitution +@cindex process substitution + +Process substitution is supported on systems that support named +pipes (@sc{FIFO}s) or the @file{/dev/fd} method of naming open files. +It takes the form of +@example +<(@var{list}) +@end example +@noindent +or +@example +>(@var{list}) +@end example +@noindent +The process @var{list} is run with its input or output connected to a +@sc{FIFO} or some file in @file{/dev/fd}. The name of this file is +passed as an argument to the current command as the result of the +expansion. If the @code{>(@var{list})} form is used, writing to +the file will provide input for @var{list}. If the +@code{<(@var{list})} form is used, the file passed as an +argument should be read to obtain the output of @var{list}. + +On systems that support it, process substitution is performed +simultaneously with parameter and variable expansion, +command substitution, and arithmetic expansion. + +@node Word Splitting +@subsection Word Splitting +@cindex word splitting + +The shell scans the results of parameter expansion, command substitution, +and arithmetic expansion that did not occur within double quotes for +word splitting. + +The shell treats each character of @code{$IFS} +as a delimiter, and splits the results of the other +expansions into words on these characters. If +@code{IFS} is unset, or its value is exactly @code{}, +the default, then any sequence of @code{IFS} +characters serves to delimit words. If @code{IFS} +has a value other than the default, then sequences of +the whitespace characters @code{space} and @code{tab} +are ignored at the beginning and end of the +word, as long as the whitespace character is in the +value of @code{IFS} (an @code{IFS} whitespace character). +Any character in @code{IFS} that is not @code{IFS} +whitespace, along with any adjacent @code{IFS} +whitespace characters, delimits a field. A sequence of @code{IFS} +whitespace characters is also treated as a delimiter. +If the value of @code{IFS} is null, no word splitting occurs. + +Explicit null arguments (@code{""} or @code{''}) are retained. +Unquoted implicit null arguments, resulting from the expansion of +@var{parameter}s +that have no values, are removed. +If a parameter with no value is expanded within double quotes, a +null argument results and is retained. + +Note that if no expansion occurs, no splitting +is performed. + +@node Filename Expansion +@subsection Filename Expansion +@cindex expansion, filename +@cindex expansion, pathname +@cindex filename expansion +@cindex pathname expansion + +After word splitting, +unless the @samp{-f} +option has been set (@pxref{The Set Builtin}), +Bash scans each word for the characters +@samp{*}, @samp{?}, and @samp{[}. +If one of these characters appears, then the word is +regarded as a @var{pattern}, +and replaced with an alphabetically sorted list of +file names matching the pattern. If no matching file names are found, +and the shell option @code{nullglob} is disabled, the word is left +unchanged. If the option is set, and no matches are found, the word +is removed. When a pattern is used for filename generation, +the character @samp{.} +at the start of a filename or immediately following a slash +must be matched explicitly, unless the shell option @code{dotglob} +is set. The slash character must always be matched explicitly. +In other cases, the @samp{.} character is not treated specially. +See the description of @code{shopt} in @ref{Bash Builtins}, +for a description of the @code{nullglob} and @code{dotglob} options. + +The @code{GLOBIGNORE} +shell variable may be used to restrict the set of filenames matching a +@var{pattern}. If @code{GLOBIGNORE} +is set, each matching filename that also matches one of the patterns in +@code{GLOBIGNORE} is removed from the list of matches. The filenames +@file{.} and @file{..} +are always ignored, even when @code{GLOBIGNORE}. +is set. However, setting @code{GLOBIGNORE} has the effect of +enabling the @code{dotglob} +shell option, so all other filenames beginning with a +@samp{.} will match. +To get the old behavior of ignoring filenames beginning with a +@samp{.}, make @samp{.*} one of the patterns in @code{GLOBIGNORE}. +The @code{dotglob} option is disabled when @code{GLOBIGNORE} +is unset. + +The special pattern characters have the following meanings: +@table @code +@item * +Matches any string, including the null string. +@item ? +Matches any single character. +@item [@dots{}] +Matches any one of the enclosed characters. A pair of characters +separated by a minus sign denotes a @var{range}; +any character lexically between those two characters, inclusive, +is matched. If the first character following the +@samp{[} is a @samp{!} or a @samp{^} +then any character not enclosed is matched. A @samp{@minus{}} +may be matched by including it as the first or last character +in the set. A @samp{]} may be matched by including it as the first +character in the set. +@end table + +@node Quote Removal +@subsection Quote Removal + +After the preceding expansions, all unquoted occurrences of the +characters @samp{\}, @samp{'}, and @samp{"} that did not +result from one of the above expansions are removed. + +@node Redirections +@section Redirections +@cindex redirection + +Before a command is executed, its input and output +may be @var{redirected} +using a special notation interpreted by the shell. +Redirection may also be used to open and close files for the +current shell execution environment. The following redirection +operators may precede or appear anywhere within a +simple command or may follow a command. +Redirections are processed in the order they appear, from +left to right. + +In the following descriptions, if the file descriptor number is +omitted, and the first character of the redirection operator is +@samp{<}, the redirection refers to the standard input (file +descriptor 0). If the first character of the redirection operator +is @samp{>}, the redirection refers to the standard output (file +descriptor 1). + +The word that follows the redirection operator in the following +descriptions is subjected to brace expansion, tilde expansion, +parameter expansion, command substitution, arithmetic expansion, +quote removal, and filename expansion. If it expands to more +than one word, Bash reports an error. + +Note that the order of redirections is significant. For example, +the command +@example +ls > @var{dirlist} 2>&1 +@end example +@noindent +directs both standard output and standard error to the file +@var{dirlist}, while the command +@example +ls 2>&1 > @var{dirlist} +@end example +@noindent +directs only the standard output to file @var{dirlist}, +because the standard error was duplicated as standard output +before the standard output was redirected to @var{dirlist}. + +@subsection Redirecting Input +Redirection of input causes the file whose name results from +the expansion of @var{word} +to be opened for reading on file descriptor @code{n}, +or the standard input (file descriptor 0) if @code{n} +is not specified. + +The general format for redirecting input is: +@example +[n]<@var{word} +@end example + +@subsection Redirecting Output +Redirection of output causes the file whose name results from +the expansion of @var{word} +to be opened for writing on file descriptor @code{n}, +or the standard output (file descriptor 1) if @code{n} +is not specified. If the file does not exist it is created; +if it does exist it is truncated to zero size. + +The general format for redirecting output is: +@example +[n]>[|]@var{word} +@end example + +If the redirection operator is @samp{>}, and the @samp{-C} option to the +@code{set} builtin has been enabled, the redirection will fail if the +filename whose name results from the expansion of @var{word} exists. +If the redirection operator is @samp{>|}, +then the value of the @samp{-C} option to the @code{set} +builtin command is not tested, and the redirection is attempted even +if the file named by @var{word} exists. + +@subsection Appending Redirected Output +Redirection of output in this fashion +causes the file whose name results from +the expansion of @var{word} +to be opened for appending on file descriptor @code{n}, +or the standard output (file descriptor 1) if @code{n} +is not specified. If the file does not exist it is created. + +The general format for appending output is: +@example +[n]>>@var{word} +@end example + +@subsection Redirecting Standard Output and Standard Error +Bash allows both the +standard output (file descriptor 1) and +the standard error output (file descriptor 2) +to be redirected to the file whose name is the +expansion of @var{word} with this construct. + +There are two formats for redirecting standard output and +standard error: +@example +&>@var{word} +@end example +@noindent +and +@example +>&@var{word} +@end example +@noindent +Of the two forms, the first is preferred. +This is semantically equivalent to +@example +>@var{word} 2>&1 +@end example + +@subsection Here Documents +This type of redirection instructs the shell to read input from the +current source until a line containing only @var{word} +(with no trailing blanks) is seen. All of +the lines read up to that point are then used as the standard +input for a command. + +The format of here-documents is as follows: +@example +<<[@minus{}]@var{word} + @var{here-document} +@var{delimiter} +@end example + +No parameter expansion, command substitution, filename +expansion, or arithmetic expansion is performed on +@var{word}. If any characters in @var{word} are quoted, the +@var{delimiter} is the result of quote removal on @var{word}, +and the lines in the here-document are not expanded. Otherwise, +all lines of the here-document are subjected to parameter expansion, +command substitution, and arithmetic expansion. In the latter +case, the pair @code{\newline} is ignored, and @samp{\} +must be used to quote the characters +@samp{\}, @samp{$}, and @samp{`}. + +If the redirection operator is @samp{<<-}, +then all leading tab characters are stripped from input lines and the +line containing @var{delimiter}. +This allows here-documents within shell scripts to be indented in a +natural fashion. + +@subsection Duplicating File Descriptors +The redirection operator +@example +[n]<&@var{word} +@end example +@noindent +is used to duplicate input file descriptors. +If @var{word} +expands to one or more digits, the file descriptor denoted by @code{n} +is made to be a copy of that file descriptor. If @var{word} +evaluates to @samp{-}, file descriptor @code{n} is closed. If +@code{n} is not specified, the standard input (file descriptor 0) is used. + +The operator +@example +[n]>&@var{word} +@end example +@noindent +is used similarly to duplicate output file descriptors. If +@code{n} +is not specified, the standard output (file descriptor 1) is used. +As a special case, if @code{n} is omitted, and @var{word} does not +expand to one or more digits, the standard output and standard +error are redirected as described previously. + +@subsection Opening File Descriptors for Reading and Writing +The redirection operator +@example +[n]<>@var{word} +@end example +@noindent +causes the file whose name is the expansion of @var{word} +to be opened for both reading and writing on file descriptor +@code{n}, or on file descriptor 0 if @code{n} +is not specified. If the file does not exist, it is created. + +@node Executing Commands +@section Executing Commands + +@menu +* Command Search and Execution:: How Bash finds commands and runs them. + +* Environment:: The environment given to a command. + +* Exit Status:: The status returned by commands and how Bash + interprets it. + +* Signals:: What happens when Bash or a command it runs + receives a signal. +@end menu + +@node Command Search and Execution +@subsection Command Search and Execution +@cindex command execution +@cindex command search + +After a command has been split into words, if it results in a +simple command and an optional list of arguments, the following +actions are taken. + +@enumerate +@item +If the command name contains no slashes, the shell attempts to +locate it. If there exists a shell function by that name, that +function is invoked as described above in @ref{Shell Functions}. + +@item +If the name does not match a function, the shell searches for +it in the list of shell builtins. If a match is found, that +builtin is invoked. + +@item +If the name is neither a shell function nor a builtin, +and contains no slashes, Bash searches each element of +@code{$PATH} for a directory containing an executable file +by that name. Bash uses a hash table to remember the full +filenames of executable files (see the description of +@code{hash} in @ref{Bourne Shell Builtins}) to avoid multiple +@code{PATH} searches. +A full search of the directories in @code{$PATH} +is performed only if the command is not found in the hash table. +If the search is unsuccessful, the shell prints an error +message and returns a nonzero exit status. + +@item +If the search is successful, or if the command name contains +one or more slashes, the shell executes the named program. +Argument 0 is set to the name given, and the remaining arguments +to the command are set to the arguments supplied, if any. + +@item +If this execution fails because the file is not in executable +format, and the file is not a directory, it is assumed to be +@var{shell script} (@pxref{Shell Scripts}). +@end enumerate + +@node Environment +@subsection Environment +@cindex environment + +When a program is invoked it is given an array of strings +called the @var{environment}. +This is a list of name-value pairs, of the form @code{name=value}. + +Bash allows you to manipulate the environment in several +ways. On invocation, the shell scans its own environment and +creates a parameter for each name found, automatically marking +it for @var{export} +to child processes. Executed commands inherit the environment. +The @code{export} and @samp{declare -x} +commands allow parameters and functions to be added to and +deleted from the environment. If the value of a parameter +in the environment is modified, the new value becomes part +of the environment, replacing the old. The environment +inherited by any executed command consists of the shell's +initial environment, whose values may be modified in the shell, +less any pairs removed by the @code{unset} command, plus any +additions via the @code{export} and @samp{declare -x} commands. + +The environment for any simple command +or function may be augmented temporarily by prefixing it with +parameter assignments, as described in @ref{Shell Parameters}. +These assignment statements affect only the environment seen +by that command. + +If the @samp{-k} flag is set (@pxref{The Set Builtin}, then all +parameter assignments are placed in the environment for a command, +not just those that precede the command name. + +When Bash invokes an external command, the variable @samp{$_} +is set to the full path name of the command and passed to that +command in its environment. + +@node Exit Status +@subsection Exit Status +@cindex exit status + +For the purposes of the shell, a command which exits with a +zero exit status has succeeded. +A non-zero exit status indicates failure. +This seemingly counter-intuitive scheme is used so there +is one well-defined way to indicate success and a variety of +ways to indicate various failure modes. +When a command terminates on a fatal signal whose number is @var{n}, +Bash uses the value 128+@var{n} as the exit status. + +If a command is not found, the child process created to +execute it returns a status of 127. If a command is found +but is not executable, the return status is 126. + +The exit status is used by the Bash conditional commands +(@pxref{Conditional Constructs}) and some of the list +constructs (@pxref{Lists}). + +All of the Bash builtins return an exit status of zero if they succeed +and a non-zero status on failure, so they may be used by the +conditional and list constructs. + +@node Signals +@subsection Signals +@cindex signal handling + +When Bash is interactive, it ignores +@code{SIGTERM} (so that @samp{kill 0} does not kill an interactive shell), +and @code{SIGINT} +is caught and handled (so that the @code{wait} builtin is interruptible). +When Bash receives a @code{SIGINT}, it breaks out of any executing loops. +In all cases, Bash ignores @code{SIGQUIT}. +If job control is in effect (@pxref{Job Control}), Bash +ignores @code{SIGTTIN}, @code{SIGTTOU}, and @code{SIGTSTP}. + +Synchronous jobs started by Bash have signals set to the +values inherited by the shell from its parent. When job control +is not in effect, background jobs (commands terminated with @samp{&}) +ignore @code{SIGINT} and @code{SIGQUIT}. +Commands run as a result of command substitution ignore the +keyboard-generated job control signals +@code{SIGTTIN}, @code{SIGTTOU}, and @code{SIGTSTP}. + +The shell exits by default upon receipt of a @code{SIGHUP}. +Before exiting, it resends the @code{SIGHUP} +to all jobs, running or stopped. To prevent the shell from +sending the @code{SIGHUP} signal to a particular job, remove it +from the jobs table with the @code{disown} builtin +(@pxref{Job Control Builtins}) +or use @code{disown -h} to mark it to not receive @code{SIGHUP}. + +@node Shell Scripts +@section Shell Scripts +@cindex shell script + +A shell script is a text file containing shell commands. When such +a file is used as the first non-option argument when invoking Bash, +and neither the @samp{-c} nor @samp{-s} option is supplied +(@pxref{Invoking Bash}), +Bash reads and executes commands from the file, then exits. This +mode of operation creates a non-interactive shell. When Bash runs +a shell script, it sets the special parameter @code{0} to the name +of the file, rather than the name of the shell, and the positional +parameters are set to the remaining arguments, if any are given. +If no additional arguments are supplied, the positional parameters +are unset. + +A shell script may be made executable by using the @code{chmod} command +to turn on the execute bit. When Bash finds such a file while +searching the @code{$PATH} for a command, it spawns a subshell to +execute it. In other words, executing +@example +filename @var{arguments} +@end example +@noindent +is equivalent to executing +@example +bash filename @var{arguments} +@end example + +@noindent +if @code{filename} is an executable shell script. +This subshell reinitializes itself, so that the effect is as if a +new shell had been invoked to interpret the script. + +Most versions of Unix make this a part of the kernel's command +execution mechanism. If the first line of a script begins with +the two characters @samp{#!}, the remainder of the line specifies +an interpreter for the program. The arguments to the interpreter +consist of a single optional argument following the interpreter +name on the first line of the script file, followed by the name of +the script file, followed by the rest of the arguments. Bash +will perform this action on operating systems that do not handle it +themselves. Note that some older versions of Unix limit the interpreter +name and argument to a maximum of 32 characters. + +@node Bourne Shell Features +@chapter Bourne Shell Style Features + +@menu +* Bourne Shell Builtins:: Builtin commands inherited from the Bourne + Shell. +* Bourne Shell Variables:: Variables which Bash uses in the same way + as the Bourne Shell. +* Other Bourne Shell Features:: Addtional aspects of Bash which behave in + the same way as the Bourne Shell. +@end menu + +This section briefly summarizes things which Bash inherits from +the Bourne Shell: builtins, variables, +and other features. It also lists the significant differences +between Bash and the Bourne Shell. + +@node Bourne Shell Builtins +@section Bourne Shell Builtins + +The following shell builtin commands are inherited from the Bourne +Shell. These commands are implemented as specified by the @sc{POSIX} +1003.2 standard. + +@table @code +@item : +@btindex : +@example +: [@var{arguments}] +@end example +Do nothing beyond expanding @var{arguments} and performing redirections. + +@item . +@btindex . +@example +. @var{filename} +@end example +Read and execute commands from the @var{filename} argument in the +current shell context. + +@item break +@btindex break +@example +break [@var{n}] +@end example +Exit from a @code{for}, @code{while}, @code{until}, or @code{select} loop. +If @var{n} is supplied, the @var{n}th enclosing loop is exited. + +@item cd +@btindex cd +@example +cd [-LP] [@var{directory}] +@end example +Change the current working directory to @var{directory}. If @var{directory} +is not given, the value of the @code{HOME} shell variable is used. If the +shell variable @code{CDPATH} exists, it is used as a search path. If +@var{directory} begins with a slash, @code{CDPATH} is not used. +The @samp{-P} option means +to not follow symbolic links; symlinks are followed by default or with the +@samp{-L} option. + +@item continue +@btindex continue +@example +continue [@var{n}] +@end example +Resume the next iteration of an enclosing @code{for}, @code{while}, +@code{until}, or @code{select} loop. +If @var{n} is supplied, the execution of the +@var{n}th enclosing loop is resumed. + +@item eval +@btindex eval +@example +eval [@var{arguments}] +@end example +The arguments are concatenated together into a single +command, which is then read and executed. + +@item exec +@btindex exec +@example +exec [-cl] [-a @var{name}] [@var{command}] [@var{arguments}] +@end example +If @var{command} +is supplied, it replaces the shell. +If the @samp{-l} option is supplied, +the shell places a dash in the zeroth arg passed to @var{command}. +This is what the @code{login} program does. +The @samp{-c} option causes @var{command} +to be executed with an empty environment. +If @samp{-a} is supplied, the shell passes @var{name} +as the zeroth argument to @var{command}. +If no @var{command} is specified, redirections may be used to affect +the current shell environment. + +@item exit +@btindex exit +@example +exit [@var{n}] +@end example +Exit the shell, returning a status of @var{n} to the shell's parent. + +@item export +@btindex export +@example +export [-fn] [-p] [@var{name}[=@var{value}]] +@end example +Mark each @var{name} to be passed to child processes +in the environment. If the @samp{-f} option is supplied, the @var{name}s +refer to shell functions. The @samp{-n} option means to no longer mark +each @var{name} for export. +If no @var{names} are supplied, or if the @samp{-p} option is given, a +list of exported names is displayed. + +@item getopts +@btindex getopts +@example +getopts @var{optstring} @var{name} [@var{args}] +@end example +@code{getopts} is used by shell scripts to parse positional parameters. +@var{optstring} contains the option letters to be recognized; if a letter +is followed by a colon, the option is expected to have an +argument, which should be separated from it by white space. +Each time it is invoked, @code{getopts} +places the next option in the shell variable @var{name}, initializing +@var{name} if it does not exist, +and the index of the next argument to be processed into the +variable @code{OPTIND}. @code{OPTIND} +is initialized to 1 each time the shell or a shell script +is invoked. When an option requires an argument, +@code{getopts} places that argument into the variable @code{OPTARG}. +The shell does not reset @code{OPTIND} +automatically; it must be manually reset between multiple +calls to @code{getopts} +within the same shell invocation if a new set of parameters +is to be used. + +@code{getopts} can report errors in two ways. If the first character of +@var{optstring} is a colon, @var{silent} +error reporting is used. In normal operation diagnostic messages +are printed when illegal options or missing option arguments are +encountered. +If the variable @code{OPTERR} +is set to 0, no error message will be displayed, even if the first +character of @code{optstring} is not a colon. + +If an illegal option is seen, +@code{getopts} places @samp{?} into @var{name} and, if not silent, +prints an error message and unsets @code{OPTARG}. +If @code{getopts} is silent, the option character found is placed in +@code{OPTARG} and no diagnostic message is printed. + +If a required argument is not found, and @code{getopts} +is not silent, a question mark (@samp{?}) is placed in @var{name}, +@code{OPTARG} is unset, and a diagnostic message is printed. +If @code{getopts} is silent, then a colon (@samp{:}) is placed in +@var{name} and @code{OPTARG} is set to the option character found. + +@code{getopts} +normally parses the positional parameters, but if more arguments are +given in @var{args}, @code{getopts} parses those instead. + +@item hash +@btindex hash +@example +hash [-r] [-p @var{filename}] [@var{name}] +@end example +Remember the full filenames of commands specified as arguments, +so they need not be searched for on subsequent invocations. The +commands are found by searching through the directories listed in +@code{$PATH}. The @samp{-p} option inhibits the path search, and +@var{filename} is used as the location of @var{name}. +The @samp{-r} option causes the shell to forget +all remembered locations. If no arguments are given, information +about remembered commands is printed. + +@item pwd +@btindex pwd +@example +pwd [-LP] +@end example +Print the current working directory. If the @samp{-P} option is supplied, +the path printed will not contain symbolic links. If the @samp{-L} option +is supplied, the path printed may contain symbolic links. + +@item readonly +@btindex readonly +@example +readonly [-apf] [@var{name}] @dots{} +@end example +Mark each @var{name} as unchangable. The values of these names may not +be changed by subsequent assignment. If the @samp{-f} option is supplied, +each @var{name} refers to a shell function. The @samp{-a} option means +each @var{name} refers to an array variable. +If no @var{name} arguments are given, or if the @samp{-p} +option is supplied, a list of all readonly names is printed. + +@item return +@btindex return +@example +return [@var{n}] +@end example +Cause a shell function to exit with value @var{n}. This may also be used +to terminate execution of a script being executed with the @code{.} +builtin. + +@item shift +@btindex shift +@example +shift [@var{n}] +@end example +Shift positional parameters to the left by @var{n}. +The positional parameters from @var{n}+1 @dots{} +are renamed to +@code{$1} @dots{} . +Parameters represented by the numbers +@code{$#} to @var{n}+1 are unset. @var{n} +must be a non-negative number less than or equal to @code{$#}. + +@item test +@itemx [ +@btindex test +@btindex [ +Evaluate a conditional expression (@pxref{Bash Conditional Expressions}). + +@item times +@btindex times +@example +times +@end example +Print out the user and system times used by the shell and its children. + +@item trap +@btindex trap +@example +trap [-lp] [@var{arg}] [@var{sigspec}] +@end example +The commands in @var{arg} are to be read and executed when the +shell receives signal @var{sigspec}. If @var{arg} is absent or +equal to @samp{-}, all specified signals are reset to the values +they had when the shell was started. +If @var{arg} is the null string, then @var{sigspec} is ignored by +the shell and commands it invokes. +If @var{arg} is @samp{-p}, the shell displays the trap commands +associated with each @var{sigspec}. If no arguments are supplied, or +only @samp{-p} is given, @code{trap} prints the list of commands +associated with each signal number. @var{sigspec} is either a signal +name such as @code{SIGINT} or a signal number. If @var{sigspec} is +@code{0} or @code{EXIT}, @var{arg} is executed when the shell exits. +If @var{sigspec} is @code{DEBUG}, the command @var{arg} is executed +after every simple command. +The @samp{-l} option causes the shell to print a list of signal names +and their corresponding numbers. + +Signals ignored upon entry to the shell cannot be trapped or reset. +Trapped signals are reset to their original values in a child +process when it is created. + +@item umask +@btindex umask +@example +umask [-S] [@var{mode}] +@end example +Set the shell process's file creation mask to @var{mode}. If +@var{mode} begins with a digit, it is interpreted as an octal number; +if not, it is interpreted as a symbolic mode mask similar +to that accepted by the @code{chmod} command. If @var{mode} is +omitted, the current value of the mask is printed. If the @samp{-S} +option is supplied without a @var{mode} argument, the mask is printed +in a symbolic format. + +@item unset +@btindex unset +@example +unset [-fv] [@var{name}] +@end example +Each variable or function @var{name} is removed. +If no options are supplied, or the @samp{-v} option is given, each +@var{name} refers to a shell variable. +If the @samp{-f} option is given, the @var{name}s refer to shell +functions, and the function definition is removed. +Read-only variables and functions may not be unset. + +@end table + +@node Bourne Shell Variables +@section Bourne Shell Variables + +Bash uses certain shell variables in the same way as the Bourne shell. +In some cases, Bash assigns a default value to the variable. + +@vtable @code + +@item IFS +A list of characters that separate fields; used when the shell splits +words as part of expansion. + +@item PATH +A colon-separated list of directories in which the shell looks for +commands. + +@item HOME +The current user's home directory; the default for the @code{cd} builtin +command. + +@item CDPATH +A colon-separated list of directories used as a search path for +the @code{cd} command. + +@item MAILPATH +A colon-separated list of files which the shell periodically checks +for new mail. You can +also specify what message is printed by separating the file name from +the message with a @samp{?}. When used in the text of the message, +@code{$_} stands for the name of the current mailfile. + +@item MAIL +If this parameter is set to a filename and the @code{MAILPATH} variable +is not set, Bash informs the user of the arrival of mail in +the specified file. + +@item PS1 +The primary prompt string. The default value is @samp{\s-\v\$ }. + +@item PS2 +The secondary prompt string. The default value is @samp{> }. + +@item OPTIND +The index of the last option processed by the +@code{getopts} builtin. + +@item OPTARG +The value of the last option argument processed by the +@code{getopts} builtin. + +@end vtable + +@node Other Bourne Shell Features +@section Other Bourne Shell Features + +@menu +* Major Differences From The Bourne Shell:: Major differences between + Bash and the Bourne shell. +@end menu + +Bash implements essentially the same grammar, parameter and variable +expansion, redirection, and quoting as the Bourne Shell. Bash uses the +@sc{POSIX} 1003.2 standard as the specification of how these features are to be +implemented. There are some differences between the traditional Bourne +shell and the @sc{POSIX} standard; this section quickly details the differences +of significance. A number of these differences are explained in greater +depth in subsequent sections. + +@node Major Differences From The Bourne Shell +@subsection Major Differences From The SVR4.2 Bourne Shell + +Bash is @sc{POSIX}-conformant, even where the @sc{POSIX} specification +differs from traditional @code{sh} behavior. + +Bash has multi-character invocation options (@pxref{Invoking Bash}). + +Bash has command-line editing (@pxref{Command Line Editing}) and +the @code{bind} builtin. + +Bash has command history (@pxref{Bash History Facilities}) and the +@code{history} and @code{fc} builtins to manipulate it. + +Bash implements @code{csh}-like history expansion (@pxref{History Interaction}). + +Bash has one-dimensional array variables (@pxref{Arrays}), and the +appropriate variable expansions and assignment syntax to use them. +Some of the Bash builtins take options to act on arrays. Bash provides +some built-in array variables. + +Bash implements the @code{!} keyword to negate the return value of +a pipeline (@pxref{Pipelines}). +Very useful when an @code{if} statement needs to act only if a test fails. + +Bash includes the @code{select} compound command, which allows the +generation of simple menus (@pxref{Korn Shell Constructs}). + +Bash includes brace expansion (@pxref{Brace Expansion}) and tilde +expansion (@pxref{Tilde Expansion}). + +Bash implements command aliases and the @code{alias} and @code{unalias} +builtins (@pxref{Aliases}). + +Bash provides shell arithmetic and arithmetic expansion +(@pxref{Shell Arithmetic}). + +The @sc{POSIX} and @code{ksh}-style @code{$()} form of command substitution +is implemented (@pxref{Command Substitution}), +and preferred to the Bourne shell's @code{``} (which +is also implemented for backwards compatibility). + +Variables present in the shell's initial environment are automatically +exported to child processes. The Bourne shell does not normally do +this unless the variables are explicitly marked using the @code{export} +command. + +Bash includes the @sc{POSIX} and @code{ksh}-style pattern removal +@samp{%}, @samp{#}, @samp{%%} and @samp{##} constructs to remove +leading or trailing substrings from variable values +(@pxref{Shell Parameter Expansion}). + +The expansion @code{$@{#xx@}}, which returns the length of @code{$xx}, +is supported (@pxref{Shell Parameter Expansion}). + +The @code{$'@dots{}'} quoting syntax, which expands ANSI-C +backslash-escaped characters in the text between the single quotes, +is supported (@pxref{ANSI-C Quoting}). + +Bash supports the @code{$"@dots{}"} quoting syntax to do +locale-specific translation of the characters between the double +quotes. The @samp{-D} and @samp{--dump-strings} invocation options +list the translatable strings found in a script +(@pxref{Locale Translation}). + +The expansion @code{$@{var:}@var{length}@code{[:}@var{offset}@code{]@}}, +which expands to the substring of @code{var}'s value of length +@var{length}, optionally beginning at @var{offset}, is present +(@pxref{Shell Parameter Expansion}). + +The expansion +@code{$@{var/[/]}@var{pattern}@code{[/}@var{replacement}@code{]@}}, +which matches @var{pattern} and replaces it with @var{replacement} in +the value of @code{var}, is available (@pxref{Shell Parameter Expansion}). + +Bash has @var{indirect} variable expansion using @code{$@{!word@}} +(@pxref{Shell Parameter Expansion}). + +Bash can expand positional parameters beyond @code{$9} using +@code{$@{@var{num}@}}. + +Bash has process substitution (@pxref{Process Substitution}). + +Bash automatically assigns variables that provide information about the +current user (@code{UID} and @code{EUID}), the current host +(@code{HOSTTYPE}, @code{OSTYPE}, @code{MACHTYPE}, and @code{HOSTNAME}), +and the instance of Bash that is running (@code{BASH}, +@code{BASH_VERSION}, and @code{BASH_VERSINFO}. @xref{Bash Variables}, +for details. + +The @code{IFS} variable is used to split only the results of expansion, +not all words (@pxref{Word Splitting}). +This closes a longstanding shell security hole. + +It is possible to have a variable and a function with the same name; +@code{sh} does not separate the two name spaces. + +Bash functions are permitted to have local variables using the +@code{local} builtin, and thus useful recursive functions may be written. + +Variable assignments preceding commands affect only that command, even +builtins and functions. In @code{sh}, all variable assignments +preceding commands are global unless the command is executed from the +file system. + +Bash performs filename expansion on filenames specified as operands +to output redirection operators. + +Bash contains the @samp{<>} redirection operator, allowing a file to be +opened for both reading and writing, and the @samp{&>} redirection +operator, for directing standard output and standard error to the same +file (@pxref{Redirections}). + +The @code{noclobber} option is available to avoid overwriting existing +files with output redirection (@pxref{The Set Builtin}). +The @samp{>|} redirection operator may be used to override @code{noclobber}. + +Bash interprets special backslash-escaped characters in the prompt +strings when interactive (@pxref{Printing a Prompt}). + +Bash allows you to write a function to override a builtin, and provides +access to that builtin's functionality within the function via the +@code{builtin} and @code{command} builtins (@pxref{Bash Builtins}). + +The @code{command} builtin allows selective disabling of functions +when command lookup is performed (@pxref{Bash Builtins}). + +Individual builtins may be enabled or disabled using the @code{enable} +builtin (@pxref{Bash Builtins}). + +The Bash @code{hash} builtin allows a name to be associated with +an arbitrary filename, even when that filename cannot be found by +searching the @code{$PATH}, using @samp{hash -p}. + +Shell functions may be exported to children via the environment +(@pxref{Shell Functions}). + +Bash includes a @code{help} builtin for quick reference to shell +facilities (@pxref{Bash Builtins}). + +The Bash @code{read} builtin (@pxref{Bash Builtins}) +will read a line ending in @samp{\} with +the @samp{-r} option, and will use the @code{REPLY} variable as a +default if no arguments are supplied. The Bash @code{read} builtin +also accepts a prompt string with the @samp{-p} option and will use +Readline to obtain the line when given the @samp{-e} option. + +Bash includes the @code{shopt} builtin, for finer control of shell +optional capabilities (@pxref{Bash Builtins}). + +Bash has much more optional behavior controllable with the @code{set} +builtin (@pxref{The Set Builtin}). + +The @code{disown} builtin can remove a job from the internal shell +job table (@pxref{Job Control Builtins}). + +The @code{return} builtin may be used to abort execution of scripts +executed with the @code{.} or @code{source} builtins +(@pxref{Bourne Shell Builtins}). + +The @code{test} builtin (@pxref{Bourne Shell Builtins}) +is slightly different, as it implements the +@sc{POSIX} 1003.2 algorithm, which specifies the behavior based on the +number of arguments. + +The @code{trap} builtin (@pxref{Bourne Shell Builtins}) +allows a @code{DEBUG} pseudo-signal specification, +similar to @code{EXIT}. Commands specified with a @code{DEBUG} trap are +executed after every simple command. The @code{DEBUG} trap is not +inherited by shell functions. + +The Bash @code{export}, @code{readonly}, and @code{declare} builtins can +take a @samp{-f} option to act on shell functions, a @samp{-p} option to +display variables with various attributes set in a format that can be +used as shell input, a @samp{-n} option to remove various variable +attributes, and @samp{name=value} arguments to set variable attributes +and values simultaneously. + +The Bash @code{cd} and @code{pwd} builtins each take @samp{-L} and +@samp{-P} builtins to switch between logical and physical modes. + +The Bash @code{type} builtin is more extensive and gives more information +about the names it finds. + +Bash implements a @code{csh}-like directory stack, and provides the +@code{pushd}, @code{popd}, and @code{dirs} builtins to manipulate it. +Bash also makes the directory stack visible as the value of the +@code{DIRSTACK} shell variable. + +The Bash restricted mode is more useful (@pxref{The Restricted Shell}); +the @sc{SVR4.2} shell restricted mode is too limited. + +Bash has the @code{time} reserved word and command timing (@pxref{Pipelines}). +The display of the timing statistics may be controlled with the +@code{TIMEFORMAT} variable. + +The @sc{SVR4.2} shell has two privilege-related builtins +(@code{mldmode} and @code{priv}) not present in Bash. + +Bash does not have the @code{stop} or @code{newgrp} builtins. + +Bash does not use the @code{SHACCT} variable or perform shell accounting. + +The @sc{SVR4.2} @code{sh} uses a @code{TIMEOUT} variable like Bash uses +@code{TMOUT}. + +More features unique to Bash may be found in +@ref{Bash Features}. + +@subsection Implementation Differences From The SVR4.2 Shell + +Since Bash is a completely new implementation, it does not suffer from +many of the limitations of the @sc{SVR4.2} shell. For instance: + +@itemize @bullet + +@item +Bash does not fork a subshell when redirecting into or out of +a shell control structure such as an @code{if} or @code{while} +statement. + +@item +Bash does not allow unbalanced quotes. The @sc{SVR4.2} shell will silently +insert a needed closing quote at @code{EOF} under certain circumstances. +This can be the cause of some hard-to-find errors. + +@item +The @sc{SVR4.2} shell uses a baroque memory management scheme based on +trapping @code{SIGSEGV}. If the shell is started from a process with +@code{SIGSEGV} blocked (e.g., by using the @code{system()} C library +function call), the shell misbehaves badly. + +@item +In a questionable attempt at security, the @sc{SVR4.2} shell +will alter its real +and effective @sc{UID} and @sc{GID} if they are less than some +threshold value, commonly 100. This can lead to unexpected results. + +@item +The @sc{SVR4.2} shell does not allow users to trap @code{SIGALRM} or +@code{SIGCHLD}. + +@item +For some reason, the @sc{SVR4.2} shell does not allow the @code{MAILCHECK} +variable to be unset. + +@item +The @sc{SVR4.2} shell treats @samp{^} as the undocumented equivalent of +@samp{|}. + +@item +Bash allows multiple option arguments when it is invoked (@code{-x -v}); +the @sc{SVR4.2} shell allows only one option argument (@code{-xv}). In +fact, some versions of the shell dump core if the second argument begins +with a @samp{-}. + +@item +The @sc{SVR4.2} shell exits a script if any builtin fails; Bash exits +a script only if one of the @sc{POSIX.2} special builtins fails, and +only for certain failures, as enumerated in the @code{POSIX.2} standard. + +@item +The @sc{SVR4.2} shell behaves differently when invoked as @code{jsh} +(it turns on job control). +@end itemize + +@node Csh Features +@chapter C-Shell Style Features + +The C-Shell (@dfn{@code{csh}}) was created by Bill Joy at The +University of California at Berkeley. It +is generally considered to have better features for interactive use than +the original Bourne shell. Some of the @code{csh} features present in +Bash include job control, history expansion, `protected' redirection, and +several variables to control the interactive behaviour of the shell +(e.g., @code{IGNOREEOF}). + +@xref{Using History Interactively}, for details on history expansion. + +@menu +* Brace Expansion:: Expansion of expressions within braces. +* Tilde Expansion:: Expansion of the ~ character. +* C Shell Builtins:: Builtin commands adopted from the C Shell. +* C Shell Variables:: Variables which Bash uses in essentially + the same way as the C Shell. +@end menu + +@node Brace Expansion +@section Brace Expansion +@cindex brace expansion +@cindex expansion, brace + +Brace expansion +is a mechanism by which arbitrary strings +may be generated. This mechanism is similar to +@var{filename expansion} (@pxref{Filename Expansion}), +but the file names generated +need not exist. Patterns to be brace expanded take +the form of an optional @var{preamble}, +followed by a series of comma-separated strings +between a pair of braces, followed by an optional @var{postamble}. +The preamble is prepended to each string contained +within the braces, and the postamble is then appended +to each resulting string, expanding left to right. + +Brace expansions may be nested. The results of each expanded +string are not sorted; left to right order is preserved. +For example, +@example +bash$ echo a@{d,c,b@}e +ade ace abe +@end example + +Brace expansion is performed before any other expansions, +and any characters special to other expansions are preserved +in the result. It is strictly textual. Bash +does not apply any syntactic interpretation to the context of the +expansion or the text between the braces. + +A correctly-formed brace expansion must contain unquoted opening +and closing braces, and at least one unquoted comma. +Any incorrectly formed brace expansion is left unchanged. + +This construct is typically used as shorthand when the common +prefix of the strings to be generated is longer than in the +above example: +@example +mkdir /usr/local/src/bash/@{old,new,dist,bugs@} +@end example +or +@example +chown root /usr/@{ucb/@{ex,edit@},lib/@{ex?.?*,how_ex@}@} +@end example + +@node Tilde Expansion +@section Tilde Expansion +@cindex tilde expansion +@cindex expansion, tilde + +Bash has tilde (~) expansion, similar, but not identical, to that of +@code{csh}. The following table shows what unquoted words beginning +with a tilde expand to. + +@table @code +@item ~ +The current value of @code{$HOME}. +@item ~/foo +@file{$HOME/foo} + +@item ~fred/foo +The subdirectory @code{foo} of the home directory of the user +@code{fred}. + +@item ~+/foo +@file{$PWD/foo} + +@item ~-/foo +@file{$OLDPWD/foo} +@end table + +Bash will also tilde expand words following redirection operators +and words following @samp{=} in assignment statements. + +@node C Shell Builtins +@section C Shell Builtins + +Bash has several builtin commands whose definition is very similar +to @code{csh}. + +@table @code +@btindex pushd +@item pushd +@example +pushd [@var{dir} | @var{+N} | @var{-N}] [-n] +@end example + +Save the current directory on a list and then @code{cd} to +@var{dir}. With no +arguments, exchanges the top two directories. + +@table @code +@item +@var{N} +Brings the @var{N}th directory (counting from the left of the +list printed by @code{dirs}) to the top of the list by rotating +the stack. +@item -@var{N} +Brings the @var{N}th directory (counting from the right of the +list printed by @code{dirs}) to the top of the list by rotating +the stack. +@item -n +Suppresses the normal change of directory when adding directories +to the stack, so that only the stack is manipulated. +@item @var{dir} +Makes the current working directory be the top of the stack, and then +@code{cd}s to @var{dir}. You can see the saved directory list +with the @code{dirs} command. +@end table + +@item popd +@btindex popd +@example +popd [+@var{N} | -@var{N}] [-n] +@end example + +Pop the directory stack, and @code{cd} to the new top directory. When +no arguments are given, @code{popd} +removes the top directory from the stack and +performs a @code{cd} to the new top directory. The +elements are numbered from 0 starting at the first directory listed with +@code{dirs}; i.e., @code{popd} is equivalent to @code{popd +0}. +@table @code +@item +@var{N} +Removes the @var{N}th directory (counting from the left of the +list printed by @code{dirs}), starting with zero. +@item -@var{N} +Removes the @var{N}th directory (counting from the right of the +list printed by @code{dirs}), starting with zero. +@item -n +Suppresses the normal change of directory when removing directories +from the stack, so that only the stack is manipulated. +@end table + +@item dirs +@btindex dirs +@example +dirs [+@var{N} | -@var{N}] [-clvp] +@end example +Display the list of currently remembered directories. Directories +find their way onto the list with the @code{pushd} command; you can get +back up through the list with the @code{popd} command. +@table @code +@item +@var{N} +Displays the @var{N}th directory (counting from the left of the +list printed by @code{dirs} when invoked without options), starting +with zero. +@item -@var{N} +Displays the @var{N}th directory (counting from the right of the +list printed by @code{dirs} when invoked without options), starting +with zero. +@item -c +Clears the directory stack by deleting all of the elements. +@item -l +Produces a longer listing; the default listing format uses a +tilde to denote the home directory. +@item -p +Causes @code{dirs} to print the directory stack with one entry per +line. +@item -v +Causes @code{dirs} to print the directory stack with one entry per +line, prepending each entry with its index in the stack. +@end table + +@item history +@btindex history +@example +history [-c] [@var{n}] +history [-anrw] [@var{filename}] +history -ps @var{arg} +@end example + +Display the history list with line numbers. Lines prefixed with +with a @samp{*} have been modified. An argument of @var{n} says +to list only the last @var{n} lines. Options, if supplied, have +the following meanings: + +@table @code +@item -w +Write out the current history to the history file. + +@item -r +Read the current history file and append its contents to +the history list. + +@item -a +Append the new +history lines (history lines entered since the beginning of the +current Bash session) to the history file. + +@item -n +Append the history lines not already read from the history file +to the current history list. These are lines appended to the history +file since the beginning of the current Bash session. + +@item -c +Clear the history list. This may be combined +with the other options to replace the history list completely. + +@item -s +The @var{arg}s are added to the end of +the history list as a single entry. + +@item -p +Perform history substitution on the @var{arg}s and display the result +on the standard output, without storing the results in the history list. +@end table + +When the @samp{-w}, @samp{-r}, @samp{-a}, or @samp{-n} option is +used, if @var{filename} +is given, then it is used as the history file. If not, then +the value of the @code{HISTFILE} variable is used. + +@item logout +@btindex logout +Exit a login shell. + +@item source +@btindex source +A synonym for @code{.} (@pxref{Bourne Shell Builtins}). + +@end table + +@node C Shell Variables +@section C Shell Variables + +@vtable @code + +@item IGNOREEOF +If this variable is set, its value is used the number of consecutive +@code{EOF}s Bash will read before exiting. By default, Bash will exit +upon reading a single @code{EOF}. If @code{IGNOREEOF} is not set to +a numeric value, Bash acts as if its value were 10. + +@end vtable + +@node Korn Shell Features +@chapter Korn Shell Style Features + +This section describes features primarily inspired by the +Korn Shell (@code{ksh}). In some cases, the @sc{POSIX} 1003.2 +standard has adopted these commands and variables from the +Korn Shell; Bash implements those features using the @sc{POSIX} +standard as a guide. + +@menu +* Korn Shell Constructs:: Shell grammar constructs adopted from the + Korn Shell +* Korn Shell Builtins:: Builtin commands adopted from the Korn Shell. +* Korn Shell Variables:: Variables which Bash uses in essentially + the same way as the Korn Shell. +* Aliases:: Substituting one command for another. +@end menu + +@node Korn Shell Constructs +@section Korn Shell Constructs + +Bash includes the Korn Shell @code{select} construct. This construct +allows the easy generation of menus. It has almost the same syntax as +the @code{for} command. + +The syntax of the @code{select} command is: +@rwindex select +@example +select @var{name} [in @var{words} @dots{}]; do @var{commands}; done +@end example + +The list of words following @code{in} is expanded, generating a list +of items. The set of expanded words is printed on the standard +error, each preceded by a number. If the @samp{in @var{words}} +is omitted, the positional parameters are printed. The +@code{PS3} prompt is then displayed and a line is read from the standard +input. If the line consists of a number corresponding to one of +the displayed words, then the value of @var{name} +is set to that word. If the line is empty, the words and prompt +are displayed again. If @code{EOF} is read, the @code{select} +command completes. Any other value read causes @var{name} +to be set to null. The line read is saved in the variable +@code{REPLY}. + +The @var{commands} are executed after each selection until a +@code{break} or @code{return} command is executed, at which +point the @code{select} command completes. + +Bash also has adopted command timing from the Korn shell. If the +@code{time} reserved word precedes a pipeline or simple command, +timing statistics for the pipeline are displayed when it completes. +The statistics currently consist of elapsed (wall-clock) time and +user and system time consumed by the command's execution. + +The use of @code{time} as a reserved word permits the timing of +shell builtins, shell functions, and pipelines. An external +@code{time} command cannot time these easily. + +@node Korn Shell Builtins +@section Korn Shell Builtins + +This section describes Bash builtin commands taken from @code{ksh}. + +@table @code + +@item fc +@btindex fc +@example +@code{fc [-e @var{ename}] [-nlr] [@var{first}] [@var{last}]} +@code{fc -s [@var{pat}=@var{rep}] [@var{command}]} +@end example + +Fix Command. In the first form, a range of commands from @var{first} to +@var{last} is selected from the history list. Both @var{first} and +@var{last} may be specified as a string (to locate the most recent +command beginning with that string) or as a number (an index into the +history list, where a negative number is used as an offset from the +current command number). If @var{last} is not specified it is set to +@var{first}. If @var{first} is not specified it is set to the previous +command for editing and @minus{}16 for listing. If the @samp{-l} flag is +given, the commands are listed on standard output. The @samp{-n} flag +suppresses the command numbers when listing. The @samp{-r} flag +reverses the order of the listing. Otherwise, the editor given by +@var{ename} is invoked on a file containing those commands. If +@var{ename} is not given, the value of the following variable expansion +is used: @code{$@{FCEDIT:-$@{EDITOR:-vi@}@}}. This says to use the +value of the @code{FCEDIT} variable if set, or the value of the +@code{EDITOR} variable if that is set, or @code{vi} if neither is set. +When editing is complete, the edited commands are echoed and executed. + +In the second form, @var{command} is re-executed after each instance +of @var{pat} in the selected command is replaced by @var{rep}. + +A useful alias to use with the @code{fc} command is @code{r='fc -s'}, so +that typing @samp{r cc} runs the last command beginning with @code{cc} +and typing @samp{r} re-executes the last command (@pxref{Aliases}). + +@item let +@btindex let +The @code{let} builtin allows arithmetic to be performed on shell variables. +For details, refer to @ref{Arithmetic Builtins}. + +@item typeset +@btindex typeset +The @code{typeset} command is supplied for compatibility with the Korn +shell; however, it has been deprecated in favor of the +@code{declare} command (@pxref{Bash Builtins}). + +@end table + +@node Korn Shell Variables +@section Korn Shell Variables + +@vtable @code + +@item REPLY +The default variable for the @code{read} builtin. + +@item RANDOM +Each time this parameter is referenced, a random integer +between 0 and 32767 is generated. Assigning a value to this +variable seeds the random number generator. + +@item SECONDS +This variable expands to the number of seconds since the +shell was started. Assignment to this variable resets +the count to the value assigned, and the expanded value +becomes the value assigned plus the number of seconds +since the assignment. + +@item PS3 +The value of this variable is used as the prompt for the +@code{select} command. If this variable is not set, the +@code{select} command prompts with @samp{#? } + +@item PS4 +This is the prompt printed before the command line is echoed +when the @samp{-x} option is set (@pxref{The Set Builtin}). +The default is @samp{+ }. + +@item PWD +The current working directory as set by the @code{cd} builtin. + +@item OLDPWD +The previous working directory as set by the @code{cd} builtin. + +@item TMOUT +If set to a value greater than zero, the value is interpreted as +the number of seconds to wait for input after issuing the primary +prompt. +Bash terminates after that number of seconds if input does +not arrive. + +@item LINENO +The line number in the script or shell function currently executing. + +@item ENV +If this variable is set when Bash is invoked to execute a shell +script, its value is expanded and used as the name of a startup file +to read before executing the script. @xref{Bash Startup Files}. + +@item FCEDIT +The editor used as a default by the @code{fc} builtin command. + +@end vtable + +@node Aliases +@section Aliases +@cindex alias expansion + +@menu +* Alias Builtins:: Builtins commands to maniuplate aliases. +@end menu + +The shell maintains a list of @var{aliases} +that may be set and unset with the @code{alias} and +@code{unalias} builtin commands. + +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 alias name and the replacement text may contain any valid +shell input, including shell metacharacters, with the exception +that the alias name may not contain @key{=}. +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 +@code{ls} to @code{"ls -F"}, +for instance, and Bash does not try to recursively expand the +replacement text. If the last character of the alias value is a +space or tab character, then the next command word following the +alias is also checked for alias expansion. + +Aliases are created and listed with the @code{alias} +command, and removed with the @code{unalias} command. + +There is no mechanism for using arguments in the replacement text, +as in @code{csh}. +If arguments are needed, a shell function should be used +(@pxref{Shell Functions}). + +Aliases are not expanded when the shell is not interactive, +unless the @code{expand_aliases} shell option is set using +@code{shopt} (@pxref{Bash Builtins}). + +The rules concerning the definition and use of aliases are +somewhat confusing. Bash +always reads at least one complete line +of input before executing any +of the commands on that line. Aliases are expanded when a +command is read, not when it is executed. Therefore, an +alias definition appearing on the same line as another +command does not take effect until the next line of input is read. +The commands following the alias definition +on that line are not affected by the new alias. +This behavior is also an issue when functions are executed. +Aliases are expanded when the function definition is read, +not when the function is executed, because a function definition +is itself a compound command. As a consequence, aliases +defined in a function are not available until after that +function is executed. To be safe, always put +alias definitions on a separate line, and do not use @code{alias} +in compound commands. + +Note that for almost every purpose, aliases are superseded by +shell functions. + +@node Alias Builtins +@subsection Alias Builtins + +@table @code + +@item alias +@btindex alias +@example +alias [@code{-p}] [@var{name}[=@var{value}] @dots{}] +@end example + +Without arguments or with the @samp{-p} option, @code{alias} prints +the list of aliases on the standard output in a form that allows +them to be reused as input. +If arguments are supplied, an alias is defined for each @var{name} +whose @var{value} is given. If no @var{value} is given, the name +and value of the alias is printed. + +@item unalias +@btindex unalias +@example +unalias [-a] [@var{name} @dots{} ] +@end example + +Remove each @var{name} from the list of aliases. If @samp{-a} is +supplied, all aliases are removed. +@end table + +@node Bash Features +@chapter Bash Features + +This section describes features unique to Bash. + +@menu +* Invoking Bash:: Command line options that you can give + to Bash. +* Bash Startup Files:: When and how Bash executes scripts. +* Is This Shell Interactive?:: Determining the state of a running Bash. +* Bash Builtins:: Table of builtins specific to Bash. +* The Set Builtin:: This builtin is so overloaded it + deserves its own section. +* Bash Conditional Expressions:: Primitives used in composing expressions for + the @code{test} builtin. +* Bash Variables:: List of variables that exist in Bash. +* Shell Arithmetic:: Arithmetic on shell variables. +* Arrays:: Array Variables +* Printing a Prompt:: Controlling the PS1 string. +* The Restricted Shell:: A more controlled mode of shell execution. +* Bash POSIX Mode:: Making Bash behave more closely to what + the POSIX standard specifies. +@end menu + +@node Invoking Bash +@section Invoking Bash + +@example +bash [long-opt] [-ir] [-abefhkmnptuvxdBCDHP] [-o @var{option}] [@var{argument} @dots{}] +bash [long-opt] [-abefhkmnptuvxdBCDHP] [-o @var{option}] -c @var{string} [@var{argument} @dots{}] +bash [long-opt] -s [-abefhkmnptuvxdBCDHP] [-o @var{option}] [@var{argument} @dots{}] +@end example + +In addition to the single-character shell command-line options +(@pxref{The Set Builtin}), there are several multi-character +options that you can use. These options must appear on the command +line before the single-character options in order for them +to be recognized. + +@table @code +@item --dump-strings +Equivalent to @samp{-D}. + +@item --help +Display a usage message on standard output and exit sucessfully. + +@item --login +Make this shell act as if it were directly invoked by login. +This is equivalent to @samp{exec -l bash} but can be issued from +another shell, such as @code{csh}. If you wanted to replace your +current login shell with a Bash login shell, you would say +@samp{exec bash --login}. + +@item --noediting +Do not use the @sc{GNU} Readline library (@pxref{Command Line Editing}) +to read interactive command lines. + +@item --noprofile +Don't load the system-wide startup file @file{/etc/profile} +or any of the personal initialization files +@file{~/.bash_profile}, @file{~/.bash_login}, or @file{~/.profile} +when Bash is invoked as a login shell. + +@item --norc +Don't read the @file{~/.bashrc} initialization file in an +interactive shell. This is on by default if the shell is +invoked as @code{sh}. + +@item --posix +Change the behavior of Bash where the default operation differs +from the @sc{POSIX} 1003.2 standard to match the standard. This +is intended to make Bash behave as a strict superset of that +standard. @xref{Bash POSIX Mode}, for a description of the Bash +@sc{POSIX} mode. + +@item --rcfile @var{filename} +Execute commands from @var{filename} (instead of @file{~/.bashrc}) +in an interactive shell. + +@item --restricted +Make the shell a restricted shell (@pxref{The Restricted Shell}). + +@item --verbose +Equivalent to @samp{-v}. + +@item --version +Show version information for this instance of +Bash on the standard output and exit successfully. + +@end table + +There are several single-character options you can give which are +not available with the @code{set} builtin. + +@table @code +@item -c @var{string} +Read and execute commands from @var{string} after processing the +options, then exit. Any remaining arguments are assigned to the +positional parameters, starting with @code{$0}. + +@item -i +Force the shell to run interactively. + +@item -r +Make the shell restricted. + +@item -s +If this flag is present, or if no arguments remain after option +processing, then commands are read from the standard input. +This option allows the positional parameters to be set +when invoking an interactive shell. + +@item -D +A list of all double-quoted strings preceded by @samp{$} +is printed on the standard ouput. +These are the strings that +are subject to language translation when the current locale +is not @code{C} or @code{POSIX} (@pxref{Locale Translation}). +This implies the @samp{-n} option; no commands will be executed. + +@end table + +@cindex interactive shell +An @emph{interactive} shell is one whose input and output are both +connected to terminals (as determined by @code{isatty()}), or one +started with the @samp{-i} option. + +If arguments remain after option processing, and neither the +@samp{-c} nor the @samp{-s} +option has been supplied, the first argument is assumed to +be the name of a file containing shell commands (@pxref{Shell Scripts}). +When Bash is invoked in this fashion, @code{$0} +is set to the name of the file, and the positional parameters +are set to the remaining arguments. +Bash reads and executes commands from this file, then exits. +Bash's exit status is the exit status of the last command executed +in the script. If no commands are executed, the exit status is 0. + +@node Bash Startup Files +@section Bash Startup Files +@cindex startup files + +This section describs how bash executes its startup files. +If any of the files exist but cannot be read, bash reports an error. +Tildes are expanded in file names as described above under +Tilde Expansion (@pxref{Tilde Expansion}). + +When Bash is invoked as a login shell, it first reads and +executes commands from the file @file{/etc/profile}, if that file exists. +After reading that file, it looks for @file{~/.bash_profile}, +@file{~/.bash_login}, and @file{~/.profile}, in that order, and reads +and executes commands from the first one that exists and is readable. +The @samp{--noprofile} option may be used when the shell is started to +inhibit this behavior. + +When a login shell exits, Bash reads and executes commands from +the file @file{~/.bash_logout}, if it exists. + +When an interactive shell that is not a login shell is started, Bash +reads and executes commands from @file{~/.bashrc}, if that file exists. +This may be inhibited by using the @samp{--norc} option. +The @samp{--rcfile @var{file}} option will force Bash to read and +execute commands from @var{file} instead of @file{~/.bashrc}. + +So, typically, your @file{~/.bash_profile} contains the line +@example +@code{if [ -f @file{~/.bashrc} ]; then . @file{~/.bashrc}; fi} +@end example +@noindent +after (or before) any login-specific initializations. + +When Bash is started non-interactively, to run a shell script, +for example, it looks for the variable @code{BASH_ENV} in the environment, +expands its value if it appears there, and uses the expanded value as +the name of a file to read and execute. Bash behaves as if the +following command were executed: +@example +@code{if [ -n "$BASH_ENV" ]; then . "$BASH_ENV"; fi} +@end example +@noindent +but the value of the @code{PATH} variable is not used to search for the +file name. + +If Bash is invoked with the name @code{sh}, it tries to mimic the +startup behavior of historical versions of @code{sh} as closely as +possible, while conforming to the @sc{POSIX} standard as well. + +When invoked as a login shell, it first attempts to read and execute +commands from @file{/etc/profile} and @file{~/.profile}, in that order. +The @samp{--noprofile} option may be used to inhibit this behavior. +When invoked as an interactive shell with the name @code{sh}, +@code{bash} looks for the variable @code{ENV}, +expands its value if it is defined, and uses the +expanded value as the name of a file to read and execute. +Since a shell invoked as @code{sh} does not attempt to read and execute +commands from any other startup files, the @samp{--rcfile} option has +no effect. +A non-interactive shell invoked with the name @code{sh} does not attempt +to read any startup files. + +When invoked as @code{sh}, Bash enters @sc{POSIX} mode after +the startup files are read. + +When Bash is started in @sc{POSIX} mode, as with the +@samp{--posix} command line option, it follows the @sc{POSIX} standard +for startup files. +In this mode, the @code{ENV} variable is expanded and commands are read +and executed from the file whose name is the expanded value. +No other startup files are read. +This is done by both interactive and non-interactive shells. + +Bash attempts to determine when it is being run by the remote shell +daemon, usually @code{rshd}. If Bash determines it is being run by +rshd, it reads and executes commands from @file{~/.bashrc}, if that +file exists and is readable. +It will not do this if invoked as @code{sh}. +The @samp{--norc} option may be used to inhibit this behavior, and the +@samp{--rcfile} option may be used to force another file to be read, but +rshd does not generally invoke the shell with those options or allow +them to be specified. + +@node Is This Shell Interactive? +@section Is This Shell Interactive? +@cindex interactive shell + +As defined in @ref{Invoking Bash}, an interactive shell +is one whose input and output are both +connected to terminals (as determined by @code{isatty(3)}), +or one started with the @samp{-i} option. + +You may wish to determine within a startup script whether Bash is +running interactively or not. To do this, examine the variable +@code{$PS1}; it is unset in non-interactive shells, and set in +interactive shells. Thus: + +@example +if [ -z "$PS1" ]; then + echo This shell is not interactive +else + echo This shell is interactive +fi +@end example + +@node Bash Builtins +@section Bash Builtin Commands + +This section describes builtin commands which are unique to +or have been extended in Bash. + +@table @code + +@item bind +@btindex bind +@example +bind [-m @var{keymap}] [-lpsvPSV] [-q @var{name}] [-r @var{keyseq}] +bind [-m @var{keymap}] -f @var{filename} +bind [-m @var{keymap}] @var{keyseq:function-name} +@end example + +Display current Readline (@pxref{Command Line Editing}) +key and function bindings, or +bind a key sequence to a Readline function or macro. The +binding syntax accepted is identical to that of +@file{.inputrc} (@pxref{Readline Init File}), +but each binding must be passed as a separate argument: e.g., +@samp{"\C-x\C-r":re-read-init-file}. +Options, if supplied, have the following meanings: + +@table @code +@item -m @var{keymap} +Use @var{keymap} as the keymap to be affected by +the subsequent bindings. Acceptable @var{keymap} +names are +@code{emacs}, +@code{emacs-standard}, +@code{emacs-meta}, +@code{emacs-ctlx}, +@code{vi}, +@code{vi-command}, and +@code{vi-insert}. +@code{vi} is equivalent to @code{vi-command}; +@code{emacs} is equivalent to @code{emacs-standard}. + +@item -l +List the names of all Readline functions + +@item -p +Display Readline function names and bindings in such a way that they +can be re-read + +@item -P +List current Readline function names and bindings + +@item -v +Display Readline variable names and values in such a way that they +can be re-read + +@item -V +List current Readline variable names and values + +@item -s +Display Readline key sequences bound to macros and the strings they output +in such a way that they can be re-read + +@item -S +Display Readline key sequences bound to macros and the strings they output + +@item -f @var{filename} +Read key bindings from @var{filename} + +@item -q +Query about which keys invoke the named @var{function} + +@item -r @var{keyseq} +Remove any current binding for @var{keyseq} + +@end table + +@item builtin +@btindex builtin +@example +builtin [@var{shell-builtin} [@var{args}]] +@end example +Run a shell builtin. This is useful when you wish to rename a +shell builtin to be a function, but need the functionality of the +builtin within the function itself. + +@item command +@btindex command +@example +command [-pVv] @var{command} [@var{args} @dots{}] +@end example +Runs @var{command} with @var{arg} ignoring shell functions. If +you have a shell function called @code{ls}, and you wish to call +the command @code{ls}, you can say @samp{command ls}. The +@samp{-p} option means to use a default value for @code{$PATH} +that is guaranteed to find all of the standard utilities. + +If either the @samp{-V} or @samp{-v} option is supplied, a +description of @var{command} is printed. The @samp{-v} option +causes a single word indicating the command or file name used to +invoke @var{command} to be printed; the @samp{-V} option produces +a more verbose description. + +@item declare +@btindex declare +@example +declare [-afFrxi] [-p] [@var{name}[=@var{value}]] +@end example + +Declare variables and give them attributes. If no @var{name}s +are given, then display the values of variables instead. + +The @samp{-p} option will display the attributes and values of each +@var{name}. When @samp{-p} is used, additional options are ignored. +The @samp{-F} option inhibits the display of function definitions; +only the function name and attributes are printed. @samp{-F} implies +@samp{-f}. The following options can be used to restrict output +to variables with the specified attributes or to give variables +attributes: + +@table @code +@item -a +Each @var{name} is an array variable (@pxref{Arrays}). + +@item -f +Use function names only. + +@item -i +The variable is to be treated as +an integer; arithmetic evaluation (@pxref{Shell Arithmetic}) is +performed when the variable is assigned a value. + +@item -r +Make @var{name}s readonly. These names cannot then be assigned values +by subsequent assignment statements. + +@item -x +Mark each @var{name} for export to subsequent commands via +the environment. +@end table + +Using @samp{+} +instead of @samp{-} turns off the attribute instead. When used in +a function, @code{declare} makes each @var{name} local, as with the +@code{local} command. + +@item echo +@btindex echo +@example +echo [-neE] [arg @dots{}] +@end example +Output the @code{arg}s, separated by spaces, terminated with a +newline. The return status is always 0. If @samp{-n} is +specified, the trailing newline is suppressed. If the @samp{-e} +option is given, interpretation of the following backslash-escaped +characters is enabled. The @samp{-E} option disables the interpretation +of these escape characters, even on systems where they are interpreted +by default. +@code{echo} interprets the following escape sequences: +@table @code +@item \a +alert (bell) +@item \b +backspace +@item \c +suppress trailing newline +@item \e +escape +@item \f +form feed +@item \n +new line +@item \r +carriage return +@item \t +horizontal tab +@item \v +vertical tab +@item \\ +backslash +@item \nnn +the character whose ASCII code is @code{nnn} (octal) +@end table + +@item enable +@btindex enable +@example +enable [-n] [-p] [-f @var{filename}] [-ads] [@var{name} @dots{}] +@end example +Enable and disable builtin shell commands. This allows you to +use a disk command which has the same name as a shell builtin. +If @samp{-n} is used, the @var{name}s become disabled. Otherwise +@var{name}s are enabled. For example, to use the @code{test} binary +found via @code{$PATH} instead of the shell builtin version, type +@samp{enable -n test}. + +If the @samp{-p} option is supplied, or no @var{name} arguments appear, +a list of shell builtins is printed. With no other arguments, the list +consists of all enabled shell builtins. +The @samp{-a} option means to list +each builtin with an indication of whether or not it is enabled. + +The @samp{-f} option means to load the new builtin command @var{name} +from shared object @var{filename}, on systems that support dynamic loading. +The @samp{-d} option will delete a builtin loaded with @samp{-f}. +If there are no options, a list of the shell builtins is displayed. +The @samp{-s} option restricts @code{enable} to the @sc{POSIX.2} special +builtins. If @samp{-s} is used with @samp{-f}, the new builtin becomes +a special builtin. + +@item help +@btindex help +@example +help [@var{pattern}] +@end example +Display helpful information about builtin commands. If +@var{pattern} is specified, @code{help} gives detailed help +on all commands matching @var{pattern}, otherwise a list of +the builtins is printed. + +@item local +@btindex local +@example +local @var{name}[=@var{value}] +@end example +For each argument, create a local variable called @var{name}, and +give it @var{value}. +@code{local} can only be used within a function; it makes the variable +@var{name} have a visible scope restricted to that function and its +children. + +@item logout +@btindex logout +@example +logout [@var{n}] +@end example +Exit a login shell, returning a status of @var{n} to the shell's +parent. + +@item read +@btindex read +@example +read [-a @var{aname}] [-p @var{prompt}] [-er] [@var{name} @dots{}] +@end example +One line is read from the standard input, and the first word +is assigned to the first +@var{name}, the second word to the second @var{name}, +and so on, with leftover words assigned to the last @var{name}. +Only the characters in the value of the @code{IFS} variable +are recognized as word delimiters. If no names +are supplied, the line read is assigned to the variable @code{REPLY}. +The return code is zero, unless end-of-file is encountered. Options, +if supplied, have the following meanings: + +@table @code +@item -r +If this option is given, a backslash-newline pair is not ignored, and +the backslash is considered to be part of the line. + +@item -p @var{prompt} +Display @code{prompt}, without a +trailing newline, before attempting to read any input. The prompt +is displayed only if input is coming from a terminal. + +@item -a @var{aname} +The words are assigned to +sequential indices of the array variable @var{aname}, starting at 0. + +@item -e +Readline (@pxref{Command Line Editing}) +is used to obtain the line. +@end table + +@item shopt +@btindex shopt +@example +shopt [-pqsu] [-o] [@var{optname} @dots{}] +@end example +Toggle the values of variables controlling optional shell behavior. +With no options, or with the @samp{-p} +option, a list of all settable options is displayed, with +an indication of whether or not each is set. Other options have +the following meanings: + +@table @code +@item -s +Enable (set) each @var{optname} + +@item -u +Disable (unset) each @var{optname}. + +@item -q +Suppresses normal output; the return status +indicates whether the @var{optname} is set or unset. +If multiple @var{optname} arguments are given with @samp{-q}, +the return status is zero if all @var{optnames} are enabled; +non-zero otherwise. + +@item -o +Restricts the values of +@var{optname} to be those defined for the @samp{-o} option to the +@code{set} builtin (@pxref{The Set Builtin}). +@end table + +If either of +@samp{-s} or @samp{-u} +is used with no @var{optname} arguments, the display is limited to +those options which are set or unset, respectively. + +Unless otherwise noted, the @code{shopt} options are disabled (off) +by default. + +The return status when listing options is zero if all @var{optnames} +are enabled, non-zero otherwise. When setting or unsetting options, +the return status is zero unless an @var{optname} is not a legal shell +option. + +The list of @code{shopt} options is: +@table @code +@item cdable_vars +If this is set, an argument to the @code{cd} +builtin command that +is not a directory is assumed to be the name of a variable whose +value is the directory to change to. + +@item cdspell +If set, minor errors in the spelling of a directory component in a +@code{cd} command will be corrected. +The errors checked for are transposed characters, +a missing character, and a character too many. +If a correction is found, the corrected path is printed, +and the command proceeds. +This option is enabled by default, but is only used by interactive shells. + +@item checkhash +If this is set, Bash checks that a command found in the hash +table exists before trying to execute it. If a hashed command no +longer exists, a normal path search is performed. + +@item checkwinsize +If set, Bash checks the window size after each command +and, if necessary, updates the values of +@code{LINES} and @code{COLUMNS}. + +@item cmdhist +If set, Bash +attempts to save all lines of a multiple-line +command in the same history entry. This allows +easy re-editing of multi-line commands. + +@item dotglob +If set, Bash includes filenames beginning with a `.' in +the results of filename expansion. + +@item execfail +If this is set, a non-interactive shell will not exit if +it cannot execute the file specified as an argument to the @code{exec} +builtin command. An interactive shell does not exit if @code{exec} +fails. + +@item histappend +If set, the history list is appended to the file named by the value +of the @code{HISTFILE} +variable when the shell exits, rather than overwriting the file. + +@item histreedit +If set, and Readline +is being used, a user is given the opportunity to re-edit a +failed history substitution. + +@item histverify +If set, and Readline +is being used, the results of history substitution are not immediately +passed to the shell parser. Instead, the resulting line is loaded into +the Readline editing buffer, allowing further modification. + +@item hostcomplete +If set, and Readline is being used, Bash will attempt to perform +hostname completion when a word beginning with @samp{@@} is being +completed (@pxref{Commands For Completion}). + +@item interactive_comments +Allow a word beginning with @samp{#} +to cause that word and all remaining characters on that +line to be ignored in an interactive shell. +This option is enabled by default. + +@item lithist +If enabled, and the @code{cmdhist} +option is enabled, multi-line commands are saved to the history with +embedded newlines rather than using semicolon separators where possible. + +@item mailwarn +If set, and a file that Bash is checking for mail has been +accessed since the last time it was checked, the message +@code{"The mail in @var{mailfile} has been read"} is displayed. + +@item nullglob +If set, Bash allows filename patterns which match no +files to expand to a null string, rather than themselves. + +@item promptvars +If set, prompt strings undergo variable and parameter expansion after +being expanded (@pxref{Printing a Prompt}). +This option is enabled by default. + +@item shift_verbose +If this is set, the @code{shift} +builtin prints an error message when the shift count exceeds the +number of positional parameters. + +@item sourcepath +If set, the @code{source} builtin uses the value of @code{PATH} +to find the directory containing the file supplied as an argument. +This is enabled by default. +@end table + +@item type +@btindex type +@example +type [-all] [-type | -path] [@var{name} @dots{}] +@end example +For each @var{name}, indicate how it would be interpreted if used as a +command name. + +If the @samp{-type} flag is used, @code{type} returns a single word +which is one of @samp{alias}, @samp{function}, @samp{builtin}, +@samp{file} or @samp{keyword}, +if @var{name} is an alias, shell function, shell builtin, +disk file, or shell reserved word, respectively. +If the @var{name} is not found, then nothing is printed, and +@code{type} returns a failure status. + +If the @samp{-path} flag is used, @code{type} either returns the name +of the disk file that would be executed, or nothing if @samp{-type} +would not return @samp{file}. + +If the @samp{-all} flag is used, returns all of the places that contain +an executable named @var{file}. This includes aliases and functions, +if and only if the @samp{-path} flag is not also used. + +@code{type} accepts @samp{-a}, @samp{-t}, and @samp{-p} as equivalent to +@samp{-all}, @samp{-type}, and @samp{-path}, respectively. + +@item ulimit +@btindex ulimit +@example +ulimit [-acdflmnpstuvSH] [@var{limit}] +@end example +@code{ulimit} provides control over the resources available to processes +started by the shell, on systems that allow such control. If an +option is given, it is interpreted as follows: +@table @code +@item -S +change and report the soft limit associated with a resource. + +@item -H +change and report the hard limit associated with a resource. + +@item -a +all current limits are reported. + +@item -c +the maximum size of core files created. + +@item -d +the maximum size of a process's data segment. + +@item -f +the maximum size of files created by the shell. + +@item -l +The maximum size that may be locked into memory. + +@item -m +the maximum resident set size. + +@item -n +the maximum number of open file descriptors. + +@item -p +the pipe buffer size. + +@item -s +the maximum stack size. + +@item -t +the maximum amount of cpu time in seconds. + +@item -u +the maximum number of processes available to a single user. + +@item -v +the maximum amount of virtual memory available to the process. + +@end table + +If @var{limit} is given, it is the new value of the specified resource. +Otherwise, the current value of the soft limit for the specified resource +is printed, unless the @samp{-H} option is supplied. +When setting new limits, if neither @samp{-H} nor @samp{-S} is supplied, +both the hard and soft limits are set. +If no option is given, then @samp{-f} is assumed. Values are in 1024-byte +increments, except for @samp{-t}, which is in seconds, @samp{-p}, +which is in units of 512-byte blocks, and @samp{-n} and @samp{-u}, which +are unscaled values. + +@end table + +@node The Set Builtin +@section The Set Builtin + +This builtin is so overloaded that it deserves its own section. + +@table @code +@item set +@btindex set +@example +set [-abefhkmnptuvxdBCHP] [-o @var{option}] [@var{argument} @dots{}] +@end example + +@table @code +@item -a +Mark variables which are modified or created for export. + +@item -b +Cause the status of terminated background jobs to be reported +immediately, rather than before printing the next primary prompt. + +@item -e +Exit immediately if a simple command exits with a non-zero status. + +@item -f +Disable file name generation (globbing). + +@item -h +Locate and remember (hash) commands as they are looked up for execution. + +@item -k +All arguments in the form of assignment statements are placed +in the environment for a command, not just those that precede +the command name. + +@item -m +Job control is enabled (@pxref{Job Control}). + +@item -n +Read commands but do not execute them. + +@item -o @var{option-name} + +Set the flag corresponding to @var{option-name}: + +@table @code +@item allexport +same as @code{-a}. + +@item braceexpand +same as @code{-B}. + +@item emacs +use an @code{emacs}-style line editing interface (@pxref{Command Line Editing}). + +@item errexit +same as @code{-e}. + +@item hashall +same as @code{-h}. + +@item histexpand +same as @code{-H}. + +@item history +Enable command history, as described in @ref{Bash History Facilities}. +This option is on by default in interactive shells. + +@item ignoreeof +the shell will not exit upon reading EOF. + +@item keyword +same as @code{-k}. + +@item monitor +same as @code{-m}. + +@item noclobber +same as @code{-C}. + +@item noexec +same as @code{-n}. + +@item noglob +same as @code{-f}. + +@item notify +same as @code{-b}. + +@item nounset +same as @code{-u}. + +@item onecmd +same as @code{-t}. + +@item physical +same as @code{-P}. + +@item posix +change the behavior of Bash where the default operation differs +from the @sc{POSIX} 1003.2 standard to match the standard. This +is intended to make Bash behave as a strict superset of that +standard. + +@item privileged +same as @code{-p}. + +@item verbose +same as @code{-v}. + +@item vi +use a @code{vi}-style line editing interface. + +@item xtrace +same as @code{-x}. +@end table + +@item -p +Turn on privileged mode. +In this mode, the @code{$ENV} +file is not processed, and shell functions +are not inherited from the environment. This is enabled automatically +on startup if the effective user (group) id is not equal to the real +user (group) id. Turning this option off causes the effective user +and group ids to be set to the real user and group ids. + +@item -t +Exit after reading and executing one command. + +@item -u +Treat unset variables as an error when substituting. + +@item -v +Print shell input lines as they are read. + +@item -x +Print commands and their arguments as they are executed. + +@item -B +The shell will perform brace expansion (@pxref{Brace Expansion}). +This option is on by default. + +@item -C +Disallow output redirection to existing files. + +@item -H +Enable @samp{!} style history substitution (@pxref{History Interaction}). +This flag is on by default for interactive shells. + +@item -P +If set, do not follow symbolic links when performing commands such as +@code{cd} which change the current directory. The physical directory +is used instead. By default, Bash follows +the logical chain of directories when performing commands +which change the current directory. + +For example, if @file{/usr/sys} is a link to @file{/usr/local/sys} then: +@example +$ cd /usr/sys; echo $PWD +/usr/sys +$ cd ..; pwd +/usr +@end example + +@noindent +If @code{set -P} is on, then: +@example +$ cd /usr/sys; echo $PWD +/usr/local/sys +$ cd ..; pwd +/usr/local +@end example + +@item -- +If no arguments follow this flag, then the positional parameters are +unset. Otherwise, the positional parameters are set to the +@var{arguments}, even if some of them begin with a @samp{-}. + +@item - +Signal the end of options, cause all remaining @var{arguments} +to be assigned to the positional parameters. The @samp{-x} +and @samp{-v} options are turned off. +If there are no arguments, the positional parameters remain unchanged. +@end table + +Using @samp{+} rather than @samp{-} causes these flags to be +turned off. The flags can also be used upon invocation of the +shell. The current set of flags may be found in @code{$-}. + +The remaining N @var{arguments} are positional parameters and are +assigned, in order, to @code{$1}, @code{$2}, @dots{} @code{$N}. If +no arguments are given, all shell variables are printed. +@end table + +@node Bash Conditional Expressions +@section Bash Conditional Expressions +@cindex expressions, conditional + +Conditional expressions are used by the @code{test} and @code{[} builtins. + +Expressions may be unary or binary. Unary +expressions are often used to examine the status of a file. There +are string operators and numeric comparison operators as well. Each +operator and operand must be a separate argument. If @var{file} +is of the form @file{/dev/fd/@var{N}}, then file descriptor @var{N} is +checked. Expressions are composed of the following primaries: + +@table @code +@item -b @var{file} +True if @var{file} exists and is a block special file. + +@item -c @var{file} +True if @var{file} exists and is a character special file. + +@item -d @var{file} +True if @var{file} exists and is a directory. + +@item -e @var{file} +True if @var{file} exists. + +@item -f @var{file} +True if @var{file} exists and is a regular file. + +@item -g @var{file} +True if @var{file} exists and is set-group-id. + +@item -k @var{file} +True if @var{file} has its "sticky" bit set. + +@item -L @var{file} +True if @var{file} exists and is a symbolic link. + +@item -p @var{file} +True if @var{file} exists and is a named pipe. + +@item -r @var{file} +True if @var{file} exists and is readable. + +@item -s @var{file} +True if @var{file} exists and has a size greater than zero. + +@item -S @var{file} +True if @var{file} exists and is a socket. + +@item -t @var{fd} +True if @var{fd} is opened on a terminal. + +@item -u @var{file} +True if @var{file} exists and its set-user-id bit is set. + +@item -w @var{file} +True if @var{file} exists and is writable. + +@item -x @var{file} +True if @var{file} exists and is executable. + +@item -O @var{file} +True if @var{file} exists and is owned by the effective user id. + +@item -G @var{file} +True if @var{file} exists and is owned by the effective group id. + +@item @var{file1} -nt @var{file2} +True if @var{file1} is newer (according to +modification date) than @var{file2}. + +@item @var{file1} -ot @var{file2} +True if @var{file1} is older than @var{file2}. + +@item @var{file1} -ef @var{file2} +True if @var{file1} and @var{file2} have the same device and +inode numbers. + +@item -o @var{optname} +True if shell option @var{optname} is enabled. +The list of options appears in the description of the @samp{-o} +option to the @code{set} builtin (@pxref{The Set Builtin}). + +@item -z @var{string} +True if the length of @var{string} is zero. + +@item -n @var{string} +@itemx @var{string} +True if the length of @var{string} is non-zero. + +@item @var{string1} = @var{string2} +True if the strings are equal. @samp{==} may be used in place of +@samp{=}. + +@item @var{string1} != @var{string2} +True if the strings are not equal. + +@item @var{string1} < @var{string2} +True if @var{string1} sorts before @var{string2} lexicographically. + +@item @var{string1} > @var{string2} +True if @var{string1} sorts after @var{string2} lexicographically. + +@item ! @var{expr} +True if @var{expr} is false. + +@item @var{expr1} -a @var{expr2} +True if both @var{expr1} and @var{expr2} are true. + +@item @var{expr1} -o @var{expr2} +True if either @var{expr1} and @var{expr2} is true. + +@item @var{arg1} OP @var{arg2} +@code{OP} is one of +@samp{-eq}, @samp{-ne}, @samp{-lt}, @samp{-le}, @samp{-gt}, or @samp{-ge}. +These arithmetic binary operators return true if @var{arg1} +is equal to, not equal to, less than, less than or equal to, +greater than, or greater than or equal to @var{arg2}, +respectively. @var{Arg1} and @var{arg2} +may be positive or negative integers. + +@end table + +The Bash @code{test} and @code{[} builtins evaluate conditional +expressions using a set of rules based on the number of arguments. +These are the rules: + +@table @asis +@item 0 arguments +The expression is false. +@item 1 argument +The expression is true if and only if the argument is not null. +@item 2 arguments +If the first argument is @samp{!}, the expression is true if and +only if the second argument is null. If the first argument is +one of the listed unary operators, the expression is true if the +unary test is true. If the first argument is not a legal unary +operator, the expression is false. +@item 3 arguments +If the first argument is @samp{!}, the value is the negation of +the two-argument test using the second and third arguments. +If the second argument is one of the binary operators, the result +of the expression is the result of the binary test using the first +and third arguments as operands. +If the first argument is exactly @samp{(} and the third argument is +exactly @samp{)}, the result is the one-argument test of the second +argument. +Otherwise, the expression is false. +The @samp{-a} and @samp{-o} operators are considered binary operators +in this case. +@item 4 arguments +If the first argument is @samp{!}, the result is the negation of +the three-argument expression composed of the remaining arguments. +Otherwise, the expression is parsed and evaluated according to +precedence. @samp{-a} has a higher precedence than @samp{-o}. +@item 5 or more arguments +The expression is parsed and evaluated according to precedence, +with @samp{-a} having a higher precedence than @samp{-o}. +@end table + +@node Bash Variables +@section Bash Variables + +These variables are set or used by Bash, but other shells +do not normally treat them specially. + +@vtable @code + +@item TIMEFORMAT +The value of this parameter is used as a format string specifying +how the timing information for pipelines prefixed with the @code{time} +reserved word should be displayed. +The @samp{%} character introduces an +escape sequence that is expanded to a time value or other +information. +The escape sequences and their meanings are as +follows; the braces denote optional portions. + +@table @code + +@item %% +A literal @samp{%}. + +@item %[@var{p}][l]R +The elapsed time in seconds. + +@item %[@var{p}][l]U +The number of CPU seconds spent in user mode. + +@item %[@var{p}][l]S +The number of CPU seconds spent in system mode. + +@item %P +The CPU percentage, computed as (%U + %S) / %R. +@end table + +The optional @var{p} is a digit specifying the precision, the number of +fractional digits after a decimal point. +A value of 0 causes no decimal point or fraction to be output. +At most three places after the decimal point may be specified; values +of @var{p} greater than 3 are changed to 3. +If @var{p} is not specified, the value 3 is used. + +The optional @code{l} specifies a longer format, including minutes, of +the form @var{MM}m@var{SS}.@var{FF}s. +The value of @var{p} determines whether or not the fraction is included. + +If this variable is not set, bash acts as if it had the value +@code{$'\nreal\t%3lR\nuser\t%3lU\nsys\t%3lS'}. +If the value is null, no timing information is displayed. +A trailing newline is added when the format string is displayed. + +@item HISTCONTROL +Set to a value of @samp{ignorespace}, it means don't enter lines which +begin with a space or tab into the history list. Set to a value +of @samp{ignoredups}, it means don't enter lines which match the last +entered line. A value of @samp{ignoreboth} combines the two options. +Unset, or set to any other value than those above, means to save +all lines on the history list. + +@item HISTIGNORE +A colon-separated list of patterns used to decide which command +lines should be saved on the history list. Each pattern is +anchored at the beginning of the line and must fully specify the +line (no implicit @samp{*} is appended). Each pattern is tested +against the line after the checks specified by @code{HISTCONTROL} +are applied. In addition to the normal shell pattern matching +characters, @samp{&} matches the previous history line. @samp{&} +may be escaped using a backslash. The backslash is removed +before attempting a match. + +@code{HISTIGNORE} subsumes the function of @code{HISTCONTROL}. A +pattern of @samp{&} is identical to @code{ignoredups}, and a +pattern of @samp{[ ]*} is identical to @code{ignorespace}. +Combining these two patterns, separating them with a colon, +provides the functionality of @code{ignoreboth}. + +@item HISTFILE +The name of the file to which the command history is saved. The +default is @file{~/.bash_history}. + +@item HISTSIZE +If set, this is the maximum number of commands to remember in the +history. + +@item HISTFILESIZE +The maximum number of lines contained in the history file. When this +variable is assigned a value, the history file is truncated, if +necessary, to contain no more than that number of lines. The default +value is 500. The history file is also truncated to this size after +writing it when an interactive shell exits. + +@item histchars +Up to three characters which control history expansion, quick +substitution, and tokenization (@pxref{History Interaction}). +The first character is the +@dfn{history-expansion-char}, that is, the character which signifies the +start of a history expansion, normally @samp{!}. The second character is the +character which signifies `quick substitution' when seen as the first +character on a line, normally @samp{^}. The optional third character is the +character which signifies the remainder of the line is a comment, when +found as the first character of a word, usually @samp{#}. The history +comment character causes history substitution to be skipped for the +remaining words on the line. It does not necessarily cause the shell +parser to treat the rest of the line as a comment. + +@item HISTCMD +The history number, or index in the history list, of the current +command. If @code{HISTCMD} is unset, it loses its special properties, +even if it is subsequently reset. + +@item HOSTFILE +Contains the name of a file in the same format as @file{/etc/hosts} that +should be read when the shell needs to complete a hostname. You can +change the file interactively; the next time you attempt to complete a +hostname, Bash will add the contents of the new file to the already +existing database. + +@item MAILCHECK +How often (in seconds) that the shell should check for mail +in the files specified in @code{MAILPATH}. + +@item PROMPT_COMMAND +If present, this contains a string which is a command to execute +before the printing of each primary prompt (@code{$PS1}). + +@item UID +The numeric real user id of the current user. + +@item EUID +The numeric effective user id of the current user. + +@item PPID +The process id of the shell's parent process. + +@item HOSTNAME +The name of the current host. + +@item HOSTTYPE +A string describing the machine Bash is running on. + +@item OSTYPE +A string describing the operating system Bash is running on. + +@item MACHTYPE +A string that fully describes the system type on which Bash +is executing, in the standard GNU @var{cpu-company-system} format. + +@item SHELLOPTS +A colon-separated list of enabled shell options. Each word in +the list is a valid argument for the @samp{-o} option to the +@code{set} builtin command (@pxref{The Set Builtin}). +The options appearing in @code{SHELLOPTS} are those reported +as @samp{on} by @samp{set -o}. +If this variable is in the environment when Bash +starts up, each shell option in the list will be enabled before +reading any startup files. This variable is readonly. + +@item FIGNORE +A colon-separated list of suffixes to ignore when performing +filename completion. +A file name whose suffix matches one of the entries in +@code{FIGNORE} +is excluded from the list of matched file names. A sample +value is @samp{.o:~} + +@item GLOBIGNORE +A colon-separated list of patterns defining the set of filenames to +be ignored by filename expansion. +If a filename matched by a filename expansion pattern also matches one +of the patterns in @code{GLOBIGNORE}, it is removed from the list +of matches. + +@item DIRSTACK +An array variable (@pxref{Arrays}) +containing the current contents of the directory stack. +Directories appear in the stack in the order they are displayed by the +@code{dirs} builtin. +Assigning to members of this array variable may be used to modify +directories already in the stack, but the @code{pushd} and @code{popd} +builtins must be used to add and remove directories. +Assignment to this variable will not change the current directory. +If @code{DIRSTACK} is unset, it loses its special properties, even if +it is subsequently reset. + +@item PIPESTATUS +An array variable (@pxref{Arrays}) +containing a list of exit status values from the processes +in the most-recently-executed foreground pipeline (which may +contain only a single command). + +@item INPUTRC +The name of the Readline startup file, overriding the default +of @file{~/.inputrc}. + +@item BASH +The full filename used to execute the current instance of Bash. + +@item BASH_VERSION +The version number of the current instance of Bash. + +@item BASH_VERSINFO +An array variable whose members hold version information for this +instance of Bash. +The values assigned to the array members are as follows: + +@table @code + +@item BASH_VERSINFO[0] +The major version number (the @var{release}). + +@item BASH_VERSINFO[1] +The minor version number (the @var{version}). + +@item BASH_VERSINFO[2] +The patch level. + +@item BASH_VERSINFO[3] +The build version. + +@item BASH_VERSINFO[4] +The release status (e.g., @var{beta1}). + +@item BASH_VERSINFO[5] +The value of @code{MACHTYPE}. + +@end table + +@item SHLVL +Incremented by one each time a new instance of Bash is started. This is +intended to be an account of how deeply your Bash shells are nested. + +@item OPTERR +If set to the value 1, Bash displays error messages +generated by the @code{getopts} builtin command. + +@item LANG +Used to determine the locale category for any category not specifically +selected with a variable starting with @code{LC_}. + +@item LC_ALL +This variable overrides the value of @code{LANG} and any other +@code{LC_} variable specifying a locale category. + +@item LC_MESSAGES +This variable determines the locale used to translate double-quoted +strings preceded by a @samp{$}. + +@item IGNOREEOF +Controls the action of the shell on receipt of an @code{EOF} character +as the sole input. If set, then the value of it is the number +of consecutive @code{EOF} characters that can be read as the +first character on an input line +before the shell will exit. If the variable exists but does not +have a numeric value (or has no value) then the default is 10. +If the variable does not exist, then @code{EOF} signifies the end of +input to the shell. This is only in effect for interactive shells. + +@end vtable + +@node Shell Arithmetic +@section Shell Arithmetic +@cindex arithmetic, shell + +@menu +* Arithmetic Evaluation:: How shell arithmetic works. +* Arithmetic Expansion:: How to use arithmetic in shell expansions. +* Arithmetic Builtins:: Builtin commands that use shell arithmetic. +@end menu + +Bash includes several mechanisms to evaluate arithmetic expressions +and display the result or use it as part of a command. + +@node Arithmetic Evaluation +@subsection Arithmetic Evaluation +@cindex expressions, arithmetic +@cindex evaluation, arithmetic +@cindex arithmetic evaluation + +The shell allows arithmetic expressions to be evaluated, as one of +the shell expansions or by the @code{let} builtin. + +Evaluation is done in long integers with no check for overflow, +though division by 0 is trapped and flagged as an error. The +following list of operators is grouped into levels of +equal-precedence operators. The levels are listed in order of +decreasing precedence. + +@table @code +@item - + +unary minus and plus + +@item ! ~ +logical and bitwise negation + +@item * / % +multiplication, division, remainder + +@item + - +addition, subtraction + +@item << >> +left and right bitwise shifts + +@item <= >= < > +comparison + +@item == != +equality and inequality + +@item & +bitwise AND + +@item ^ +bitwise exclusive OR + +@item | +bitwise OR + +@item && +logical AND + +@item || +logical OR + +@item expr ? expr : expr +conditional evaluation + +@item = *= /= %= += -= <<= >>= &= ^= |= +assignment +@end table + +Shell variables are allowed as operands; parameter expansion is +performed before the expression is evaluated. +The value of a parameter is coerced to a long integer within +an expression. A shell variable need not have its integer attribute +turned on to be used in an expression. + +Constants with a leading 0 are interpreted as octal numbers. +A leading @samp{0x} or @samp{0X} denotes hexadecimal. Otherwise, +numbers take the form [@var{base}@code{#}]@var{n}, where @var{base} +is a decimal number between 2 and 64 representing the arithmetic +base, and @var{n} is a number in that base. If @var{base} is +omitted, then base 10 is used. +The digits greater than 9 are represented by the lowercase letters, +the uppercase letters, @samp{_}, and @samp{@@}, in that order. +If @var{base} is less than or equal to 36, lowercase and uppercase +letters may be used interchangably to represent numbers between 10 +and 35. + +Operators are evaluated in order of precedence. Sub-expressions in +parentheses are evaluated first and may override the precedence +rules above. + +@node Arithmetic Expansion +@subsection Arithmetic Expansion +@cindex expansion, arithmetic +@cindex arithmetic expansion + +Arithmetic expansion allows the evaluation of an arithmetic expression +and the substitution of the result. The format for arithmetic expansion is: + +@example +$(( @var{expression} )) +@end example + +The expression is treated as if it were within double quotes, but +a double quote inside the braces or parentheses is not treated +specially. All tokens in the expression undergo parameter +expansion, command substitution, and quote removal. Arithmetic +substitutions may be nested. + +The evaluation is performed according to the rules listed above. +If the expression is invalid, Bash +prints a message indicating failure and no substitution occurs. + +@node Arithmetic Builtins +@subsection Arithmetic Builtins + +@table @code + +@item let +@btindex let +@example +let @var{expression} [@var{expression}] +@end example +The @code{let} builtin allows arithmetic to be performed on shell +variables. Each @var{expression} is evaluated according to the +rules given previously (@pxref{Arithmetic Evaluation}). If the +last @var{expression} evaluates to 0, @code{let} returns 1; +otherwise 0 is returned. +@end table + +@node Arrays +@section Arrays +@cindex arrays + +Bash provides one-dimensional array variables. Any variable may be used as +an array; the @code{declare} builtin will explicitly declare an array. +There is no maximum +limit on the size of an array, nor any requirement that members +be indexed or assigned contiguously. Arrays are zero-based. + +An array is created automatically if any variable is assigned to using +the syntax +@example +name[@var{subscript}]=@var{value} +@end example + +@noindent +The @var{subscript} +is treated as an arithmetic expression that must evaluate to a number +greater than or equal to zero. To explicitly declare an array, use +@example +declare -a @var{name} +@end example +@noindent +The syntax +@example +declare -a @var{name}[@var{subscript}] +@end example +@noindent +is also accepted; the @var{subscript} is ignored. Attributes may be +specified for an array variable using the @code{declare} and +@code{readonly} builtins. Each attribute applies to all members of +an array. + +Arrays are assigned to using compound assignments of the form +@example +name=(value@var{1} @dots{} value@var{n}) +@end example +@noindent +where each +@var{value} is of the form @code{[[@var{subscript}]=]}@var{string}. If +the optional subscript is supplied, that index is assigned to; +otherwise the index of the element assigned is the last index assigned +to by the statement plus one. Indexing starts at zero. +This syntax is also accepted by the @code{declare} +builtin. Individual array elements may be assigned to using the +@code{name[}@var{subscript}@code{]=}@var{value} syntax introduced above. + +Any element of an array may be referenced using +@code{$@{name[}@var{subscript}@code{]@}}. +The braces are required to avoid +conflicts with the shell's filename expansion operators. If the +@var{subscript} is @samp{@@} or @samp{*}, the word expands to all members +of the array @var{name}. These subscripts differ only when the word +appears within double quotes. If the word is double-quoted, +@code{$@{name[*]@}} expands to a single word with +the value of each array member separated by the first character of the +@code{IFS} variable, and @code{$@{name[@@]@}} expands each element of +@var{name} to a separate word. When there are no array members, +@code{$@{name[@@]@}} expands to nothing. This is analogous to the +expansion of the special parameters @samp{@@} and @samp{*}. +@code{$@{#name[}@var{subscript}@code{]@}} expands to the length of +@code{$@{name[}@var{subscript}@code{]@}}. +If @var{subscript} is @samp{@@} or +@samp{*}, the expansion is the number of elements in the array. +Referencing an array variable without a subscript is equivalent to +referencing element zero. + +The @code{unset} builtin is used to destroy arrays. +@code{unset} @var{name[subscript]} +destroys the array element at index @var{subscript}. +@code{unset} @var{name}, where @var{name} is an array, removes the +entire array. A subscript of @samp{*} or @samp{@@} also removes the +entire array. + +The @code{declare}, @code{local}, and @code{readonly} +builtins each accept a @samp{-a} +option to specify an array. The @code{read} +builtin accepts a @samp{-a} +option to assign a list of words read from the standard input +to an array, and can read values from the standard input into +individual array elements. The @code{set} and @code{declare} +builtins display array values in a way that allows them to be +reused as input. + +@node Printing a Prompt +@section Controlling the Prompt +@cindex prompting + +The value of the variable @code{PROMPT_COMMAND} is examined just before +Bash prints each primary prompt. If it is set and non-null, then the +value is executed just as if you had typed it on the command line. + +In addition, the following table describes the special characters which +can appear in the prompt variables: + +@table @code +@item \a +a bell character. +@item \d +the date, in "Weekday Month Date" format (e.g., "Tue May 26"). +@item \e +an escape character. +@item \h +the hostname, up to the first `.'. +@item \H +the hostname. +@item \n +newline. +@item \s +the name of the shell, the basename of @code{$0} (the portion +following the final slash). +@item \t +the time, in 24-hour HH:MM:SS format. +@item \T +the time, in 12-hour HH:MM:SS format. +@item \@@ +the time, in 12-hour am/pm format. +@item \v +the version of Bash (e.g., 2.00) +@item \V +the release of Bash, version + patchlevel (e.g., 2.00.0) +@item \w +the current working directory. +@item \W +the basename of @code{$PWD}. +@item \u +your username. +@item \! +the history number of this command. +@item \# +the command number of this command. +@item \$ +if the effective uid is 0, @code{#}, otherwise @code{$}. +@item \nnn +the character corresponding to the octal number @code{nnn}. +@item \\ +a backslash. +@item \[ +begin a sequence of non-printing characters. This could be used to +embed a terminal control sequence into the prompt. +@item \] +end a sequence of non-printing characters. +@end table + +@node The Restricted Shell +@section The Restricted Shell +@cindex restricted shell + +If Bash is started with the name @code{rbash}, or the +@samp{--restricted} +option is supplied at invocation, the shell becomes restricted. +A restricted shell is used to +set up an environment more controlled than the standard shell. +A restricted shell behaves identically to @code{bash} +with the exception that the following are disallowed: +@itemize @bullet +@item +Changing directories with the @code{cd} builtin. +@item +Setting or unsetting the values of the @code{SHELL} or @code{PATH} +variables. +@item +Specifying command names containing slashes. +@item +Specifying a filename containing a slash as an argument to the @code{.} +builtin command. +@item +Importing function definitions from the shell environment at startup. +@item +Redirecting output using the @samp{>}, @samp{>|}, @samp{<>}, @samp{>&}, +@samp{&>}, and @samp{>>} redirection operators. +@item +Using the @code{exec} builtin to replace the shell with another command. +@item +Adding or deleting builtin commands with the +@samp{-f} and @samp{-d} options to the @code{enable} builtin. +@item +Specifying the @samp{-p} option to the @code{command} builtin. +@item +Turning off restricted mode with @samp{set +r}. +@end itemize + +@node Bash POSIX Mode +@section Bash POSIX Mode +@cindex POSIX Mode + +Starting Bash with the @samp{--posix} command-line option or executing +@samp{set -o posix} while Bash is running will cause Bash to conform more +closely to the @sc{POSIX.2} standard by changing the behavior to match that +specified by @sc{POSIX.2} in areas where the Bash default differs. + +The following list is what's changed when `@sc{POSIX} mode' is in effect: + +@enumerate +@item +When a command in the hash table no longer exists, Bash will re-search +@code{$PATH} to find the new location. This is also available with +@samp{shopt -s checkhash}. + +@item +The @samp{>&} redirection does not redirect stdout and stderr. + +@item +The message printed by the job control code and builtins when a job +exits with a non-zero status is `Done(status)'. + +@item +Reserved words may not be aliased. + +@item +The @sc{POSIX.2} @code{PS1} and @code{PS2} expansions of @samp{!} to +the history number and @samp{!!} to @samp{!} are enabled, +and parameter expansion is performed on +the value regardless of the setting of the @code{promptvars} option. + +@item +Interactive comments are enabled by default. (Note that Bash has +them on by default anyway.) + +@item +The @sc{POSIX.2} startup files are executed (@code{$ENV}) rather than +the normal Bash files. + +@item +Tilde expansion is only performed on assignments preceding a command +name, rather than on all assignment statements on the line. + +@item +The default history file is @file{~/.sh_history} (this is the +default value of @code{$HISTFILE}). + +@item +The output of @samp{kill -l} prints all the signal names on a single line, +separated by spaces. + +@item +Non-interactive shells exit if @var{filename} in @code{.} @var{filename} +is not found. + +@item +Redirection operators do not perform filename expansion on the word +in the redirection unless the shell is interactive. + +@item +Function names must be valid shell @code{name}s. That is, they may not +contain characters other than letters, digits, and underscores, and +may not start with a digit. Declaring a function with an illegal name +causes a fatal syntax error in non-interactive shells. + +@item +@sc{POSIX.2} `special' builtins are found before shell functions +during command lookup. + +@item +If a @sc{POSIX.2} special builtin returns an error status, a +non-interactive shell exits. The fatal errors are those listed in +the POSIX.2 standard, and include things like passing incorrect options, +redirection errors, variable assignment errors for assignments preceding +the command name, and so on. + +@ignore +@item +The environment passed to executed commands is not sorted. Neither is +the output of @code{set}. This is not strictly Posix.2 behavior, but +@code{sh} does it this way. @code{ksh} does not. It's not necessary to +sort the environment; no program should rely on it being sorted. +@end ignore + +@item +If the @code{cd} builtin finds a directory to change to +using @code{$CDPATH}, the +value it assigns to the @code{PWD} variable does not contain any +symbolic links, as if @samp{cd -P} had been executed. + +@item +A non-interactive shell exits with an error status if a variable +assignment error occurs when no command name follows the assignment +statements. +A variable assignment error occurs, for example, when trying to assign +a value to a read-only variable. + +@item +A non-interactive shell exits with an error status if the iteration +variable in a @code{for} statement or the selection variable in a +@code{select} statement is a read-only variable. + +@item +Process substitution is not available. + +@item +Assignment statements preceding @sc{POSIX.2} @code{special} builtins +persist in the shell environment after the builtin completes. + +@end enumerate + +There is other @sc{POSIX.2} behavior that Bash does not implement. +Specifically: + +@enumerate +@item +Assignment statements affect the execution environment of all +builtins, not just special ones. +@end enumerate + +@node Job Control +@chapter Job Control + +This chapter disusses what job control is, how it works, and how +Bash allows you to access its facilities. + +@menu +* Job Control Basics:: How job control works. +* Job Control Builtins:: Bash builtin commands used to interact + with job control. +* Job Control Variables:: Variables Bash uses to customize job + control. +@end menu + +@node Job Control Basics +@section Job Control Basics +@cindex job control +@cindex foreground +@cindex background +@cindex suspending jobs + +Job control +refers to the ability to selectively stop (suspend) +the execution of processes and continue (resume) +their execution at a later point. A user typically employs +this facility via an interactive interface supplied jointly +by the system's terminal driver and Bash. + +The shell associates a @var{job} with each pipeline. It keeps a +table of currently executing jobs, which may be listed with the +@code{jobs} command. When Bash starts a job +asynchronously (in the background), it prints a line that looks +like: +@example +[1] 25647 +@end example +@noindent +indicating that this job is job number 1 and that the process @sc{ID} +of the last process in the pipeline associated with this job is +25647. All of the processes in a single pipeline are members of +the same job. Bash uses the @var{job} abstraction as the +basis for job control. + +To facilitate the implementation of the user interface to job +control, the system maintains the notion of a current terminal +process group @sc{ID}. Members of this process group (processes whose +process group @sc{ID} is equal to the current terminal process group +@sc{ID}) receive keyboard-generated signals such as @code{SIGINT}. +These processes are said to be in the foreground. Background +processes are those whose process group @sc{ID} differs from the +terminal's; such processes are immune to keyboard-generated +signals. Only foreground processes are allowed to read from or +write to the terminal. Background processes which attempt to +read from (write to) the terminal are sent a @code{SIGTTIN} +(@code{SIGTTOU}) signal by the terminal driver, which, unless +caught, suspends the process. + +If the operating system on which Bash is running supports +job control, Bash allows you to use it. Typing the +@var{suspend} character (typically @samp{^Z}, Control-Z) while a +process is running causes that process to be stopped and returns +you to Bash. Typing the @var{delayed suspend} character +(typically @samp{^Y}, Control-Y) causes the process to be stopped +when it attempts to read input from the terminal, and control to +be returned to Bash. You may then manipulate the state of +this job, using the @code{bg} command to continue it in the +background, the @code{fg} command to continue it in the +foreground, or the @code{kill} command to kill it. A @samp{^Z} +takes effect immediately, and has the additional side effect of +causing pending output and typeahead to be discarded. + +There are a number of ways to refer to a job in the shell. The +character @samp{%} introduces a job name. Job number @code{n} +may be referred to as @samp{%n}. A job may also be referred to +using a prefix of the name used to start it, or using a substring +that appears in its command line. For example, @samp{%ce} refers +to a stopped @code{ce} job. Using @samp{%?ce}, on the +other hand, refers to any job containing the string @samp{ce} in +its command line. If the prefix or substring matches more than one job, +Bash reports an error. The symbols @samp{%%} and +@samp{%+} refer to the shell's notion of the current job, which +is the last job stopped while it was in the foreground. The +previous job may be referenced using @samp{%-}. In output +pertaining to jobs (e.g., the output of the @code{jobs} command), +the current job is always flagged with a @samp{+}, and the +previous job with a @samp{-}. + +Simply naming a job can be used to bring it into the foreground: +@samp{%1} is a synonym for @samp{fg %1}, bringing job 1 from the +background into the foreground. Similarly, @samp{%1 &} resumes +job 1 in the background, equivalent to @samp{bg %1} + +The shell learns immediately whenever a job changes state. +Normally, Bash waits until it is about to print a prompt +before reporting changes in a job's status so as to not interrupt +any other output. If the +the @samp{-b} option to the @code{set} builtin is set, +Bash reports such changes immediately (@pxref{The Set Builtin}). + +If you attempt to exit Bash while jobs are stopped, the +shell prints a message warning you that you have stopped jobs. +You may then use the +@code{jobs} command to inspect their status. If you do this, or +try to exit again immediately, you are not warned again, and the +stopped jobs are terminated. + +@node Job Control Builtins +@section Job Control Builtins + +@table @code + +@item bg +@btindex bg +@example +bg [@var{jobspec}] +@end example +Place @var{jobspec} into the background, as if it had been started +with @samp{&}. If @var{jobspec} is not supplied, the current job +is used. + +@item fg +@btindex fg +@example +fg [@var{jobspec}] +@end example +Bring @var{jobspec} into the foreground and make it the current job. +If @var{jobspec} is not supplied, the current job is used. + +@item jobs +@btindex jobs +@example +jobs [-lpnrs] [@var{jobspec}] +jobs -x @var{command} [@var{jobspec}] +@end example + +The first form lists the active jobs. The options have the +following meanings: + +@table @code +@item -l +List process @sc{ID}s in addition to the normal information + +@item -n +Display information only about jobs that have changed status since +you were last notified of their status. + +@item -p +List only the process @sc{ID} of the job's process group +leader. + +@item -r +Restrict output to running jobs. + +@item -s +Restrict output to stopped jobs. +@end table + +If @var{jobspec} is given, +output is restricted to information about that job. +If @var{jobspec} is not supplied, the status of all jobs is +listed. + +If the @samp{-x} option is supplied, @code{jobs} replaces any +@var{jobspec} found in @var{command} or @var{arguments} with the +corresponding process group @sc{ID}, and executes @var{command}, +passing it @var{argument}s, returning its exit status. + +@item kill +@btindex kill +@example +kill [-s @var{sigspec}] [-n @var{signum}] [-@var{sigspec}] @var{jobspec} +kill -l [@var{sigspec}] +@end example +Send a signal specified by @var{sigspec} or @var{signum} to the process +named by @var{jobspec}. @var{sigspec} is either a signal name such as +@code{SIGINT} or a signal number; @var{signum} is a signal number. If +@var{sigspec} and @var{signum} are not present, @code{SIGTERM} is used. +The @samp{-l} option lists the signal names, or the signal name +corresponding to @var{sigspec}. + +@item wait +@btindex wait +@example +wait [@var{jobspec}|@var{pid}] +@end example +Wait until the child process specified by process @sc{ID} @var{pid} or job +specification @var{jobspec} exits and report its exit status. If a job +spec is given, all processes in the job are waited for. If no arguments +are given, all currently active child processes are waited for. + +@item disown +@btindex disown +@example +disown [-h] [@var{jobspec} @dots{}] +@end example +Without options, each @var{jobspec} is removed from the table of +active jobs. +If the @samp{-h} option is given, the job is not removed from the table, +but is marked so that @code{SIGHUP} is not sent to the job if the shell +receives a @code{SIGHUP}. +If @var{jobspec} is not present, the current job is used. + +@item suspend +@btindex suspend +@example +suspend [-f] +@end example +Suspend the execution of this shell until it receives a +@code{SIGCONT} signal. The @samp{-f} option means to suspend +even if the shell is a login shell. + +@end table + +When job control is not active, the @code{kill} and @code{wait} +builtins do not accept @var{jobspec} arguments. They must be +supplied process @sc{ID}s. + +@node Job Control Variables +@section Job Control Variables + +@vtable @code + +@item auto_resume +This variable controls how the shell interacts with the user and +job control. If this variable exists then single word simple +commands without redirects are treated as candidates for resumption +of an existing job. There is no ambiguity allowed; if you have +more than one job beginning with the string that you have typed, then +the most recently accessed job will be selected. +The name of a stopped job, in this context, is the command line +used to start it. If this variable is set to the value @samp{exact}, +the string supplied must match the name of a stopped job exactly; +if set to @samp{substring}, +the string supplied needs to match a substring of the name of a +stopped job. The @samp{substring} value provides functionality +analogous to the @samp{%?} job @sc{ID} (@pxref{Job Control Basics}). +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 @samp{%} job @sc{ID}. + +@end vtable + +@set readline-appendix +@set history-appendix +@cindex History, how to use +@include hsuser.texinfo +@cindex Readline, how to use +@include rluser.texinfo +@clear readline-appendix +@clear history-appendix + +@node Installing Bash +@chapter Installing Bash + +This chapter provides basic instructions for installing Bash on +the various supported platforms. The distribution supports nearly every +version of Unix (and, someday, @sc{GNU}). Other independent ports exist for +@sc{OS/2}, Windows 95, and Windows @sc{NT}. + +@menu +* Basic Installation:: Generic installation instructions. + +* Compilers and Options:: How to set special options for various + systems. + +* Compiling For Multiple Architectures:: How to compile Bash for more + than one kind of system from + the same source tree. + +* Installation Names:: How to set the various paths used by the installation. + +* Specifying the System Type:: How to configure Bash for a particular system. + +* Sharing Defaults:: How to share default configuration values among GNU + programs. + +* Operation Controls:: Options recognized by the configuration program. + +* Optional Features:: How to enable and disable optional features when + building Bash. +@end menu + +@node Basic Installation +@section Basic Installation +@cindex installation +@cindex configuration +@cindex Bash installation +@cindex Bash configuration + +These are generic installation instructions for Bash. + +The @code{configure} shell script attempts to guess correct +values for various system-dependent variables used during +compilation. It uses those values to create a @file{Makefile} in +each directory of the package (the top directory, the +@file{builtins} and @file{doc} directories, and the +each directory under @file{lib}). It also creates a +@file{config.h} file containing system-dependent definitions. +Finally, it creates a shell script named @code{config.status} that you +can run in the future to recreate the current configuration, a +file @file{config.cache} that saves the results of its tests to +speed up reconfiguring, and a file @file{config.log} containing +compiler output (useful mainly for debugging @code{configure}). +If at some point +@file{config.cache} contains results you don't want to keep, you +may remove or edit it. + +If you need to do unusual things to compile the package, please +try to figure out how @code{configure} could check whether or not +to do them, and mail diffs or instructions to +@code{bash-maintainers@@prep.ai.mit.edu} so they can be +considered for the next release. + +The file @file{configure.in} is used to create @code{configure} +by a program called Autoconf. You only need +@file{configure.in} if you want to change it or regenerate +@code{configure} using a newer version of Autoconf. If +you do this, make sure you are using Autoconf version 2.9 or +newer. + +The simplest way to compile Bash is: + +@enumerate +@item +@code{cd} to the directory containing the source code and type +@samp{./configure} to configure Bash for your system. If you're +using @code{csh} on an old version of System V, you might need to +type @samp{sh ./configure} instead to prevent @code{csh} from trying +to execute @code{configure} itself. + +Running @code{configure} takes awhile. While running, it prints some +messages telling which features it is checking for. + +@item +Type @samp{make} to compile Bash and build the @code{bashbug} bug +reporting script. + +@item +Optionally, type @samp{make tests} to run the Bash test suite. + +@item +Type @samp{make install} to install @code{bash} and @code{bashbug}. +This will also install the manual pages and Info file. + +@end enumerate + +You can remove the program binaries and object files from the +source code directory by typing @samp{make clean}. To also remove the +files that @code{configure} created (so you can compile Bash for +a different kind of computer), type @samp{make distclean}. + +@node Compilers and Options +@section Compilers and Options + +Some systems require unusual options for compilation or linking +that the @code{configure} script does not know about. You can +give @code{configure} initial values for variables by setting +them in the environment. Using a Bourne-compatible shell, you +can do that on the command line like this: + +@example +CC=c89 CFLAGS=-O2 LIBS=-lposix ./configure +@end example + +On systems that have the @code{env} program, you can do it like this: + +@example +env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure +@end example + +The configuration process uses GCC to build Bash if it +is available. + +@node Compiling For Multiple Architectures +@section Compiling For Multiple Architectures + +You can compile Bash for more than one kind of computer at the +same time, by placing the object files for each architecture in their +own directory. To do this, you must use a version of @code{make} that +supports the @code{VPATH} variable, such as GNU @code{make}. +@code{cd} to the +directory where you want the object files and executables to go and run +the @code{configure} script from the source directory. You may need to +supply the @samp{--srcdir=PATH} argument to tell @code{configure} where the +source files are. @code{configure} automatically checks for the +source code in the directory that @code{configure} is in and in `..'. + +If you have to use a @code{make} that does not supports the @code{VPATH} +variable, you can compile Bash for one architecture at a +time in the source code directory. After you have installed +Bash for one architecture, use @samp{make distclean} before +reconfiguring for another architecture. + +Alternatively, if your system supports symbolic links, you can use the +@file{support/mkclone} script to create a build tree which has +symbolic links back to each file in the source directory. Here's an +example that creates a build directory in the current directory from a +source directory @file{/usr/gnu/src/bash-2.0}: + +@example +bash /usr/gnu/src/bash-2.0/support/mkclone -s /usr/gnu/src/bash-2.0 . +@end example + +@noindent +The @code{mkclone} script requires Bash, so you must have already built +Bash for at least one architecture before you can create build +directories for other architectures. + +@node Installation Names +@section Installation Names + +By default, @samp{make install} will install into +@file{/usr/local/bin}, @file{/usr/local/man}, etc. You can +specify an installation prefix other than @file{/usr/local} by +giving @code{configure} the option @samp{--prefix=PATH}. + +You can specify separate installation prefixes for +architecture-specific files and architecture-independent files. +If you give @code{configure} the option +@samp{--exec-prefix=PATH}, the package will use @samp{PATH} as the +prefix for installing programs and libraries. Documentation and +other data files will still use the regular prefix. + +@node Specifying the System Type +@section Specifying the System Type + +There may be some features @code{configure} can not figure out +automatically, but needs to determine by the type of host the +package will run on. Usually @code{configure} can figure that +out, but if it prints a message saying it can not guess the host +type, give it the @samp{--host=TYPE} option. @samp{TYPE} can +either be a short name for the system type, such as @samp{sun4}, +or a canonical name with three fields: @samp{CPU-COMPANY-SYSTEM} +(e.g., @samp{sparc-sun-sunos4.1.2}). + +@noindent See the file @file{support/config.sub} for the possible +values of each field. + +@node Sharing Defaults +@section Sharing Defaults + +If you want to set default values for @code{configure} scripts to +share, you can create a site shell script called +@code{config.site} that gives default values for variables like +@code{CC}, @code{cache_file}, and @code{prefix}. @code{configure} +looks for @file{PREFIX/share/config.site} if it exists, then +@file{PREFIX/etc/config.site} if it exists. Or, you can set the +@code{CONFIG_SITE} environment variable to the location of the site +script. A warning: the Bash @code{configure} looks for a site script, +but not all @code{configure} scripts do. + +@node Operation Controls +@section Operation Controls + +@code{configure} recognizes the following options to control how it +operates. + +@table @code + +@item --cache-file=@var{FILE} +Use and save the results of the tests in +@var{FILE} instead of @file{./config.cache}. Set @var{FILE} to +@file{/dev/null} to disable caching, for debugging +@code{configure}. + +@item --help +Print a summary of the options to @code{configure}, and exit. + +@item --quiet +@itemx --silent +@itemx -q +Do not print messages saying which checks are being made. + +@item --srcdir=@var{DIR} +Look for the Bash source code in directory @var{DIR}. Usually +@code{configure} can determine that directory automatically. + +@item --version +Print the version of Autoconf used to generate the @code{configure} +script, and exit. +@end table + +@code{configure} also accepts some other, not widely used, boilerplate +options. + +@node Optional Features +@section Optional Features + +The Bash @code{configure} has a number of @samp{--enable-@var{FEATURE}} +options, where @var{FEATURE} indicates an optional part of the +package. There are also several @samp{--with-@var{PACKAGE}} options, +where @var{PACKAGE} is something like @samp{gnu-malloc} or +@samp{purify} (for the Purify memory allocation checker). To +turn off the default use of a package, use +@samp{--without-@var{PACKAGE}}. To configure Bash without a feature +that is enabled by default, use @samp{--disable-@var{FEATURE}}. + +Here is a complete list of the @samp{--enable-} and +@samp{--with-} options that the Bash @code{configure} recognizes. + +@table @code +@item --with-gnu-malloc +Use the @sc{GNU} version of +@code{malloc} in @file{lib/malloc/malloc.c}. This is not the same +@code{malloc} that appears in @sc{GNU} libc, but an older version +derived from the 4.2 @sc{BSD} @code{malloc}. This @code{malloc} is +very fast, but wastes a lot of space. This option is enabled by +default. The @file{NOTES} file contains a list of systems for +which this should be turned off. + +@item --with-glibc-malloc +Use the @sc{GNU} libc version of @code{malloc} in +@file{lib/malloc/gmalloc.c}. This is somewhat slower than the +default @code{malloc}, but wastes considerably less space. + +@item --with-afs +Define if you are using the Andrew File System from Transarc. + +@item --with-purify +Define this to use the Purify memory allocation checker from Pure +Software. + +@item --enable-minimal-config +This produces a shell with minimal features, close to the historical +Bourne shell. +@end table + +@noindent +The @samp{minimal-config} option can be used to disable all of +the following options, but it is processed first, so individual +options may be enabled using @samp{enable-@var{FEATURE}}. + +All of the following options except for @samp{disabled-builtins} and +@samp{usg-echo-default} are +enabled by default, unless the operating system does not provide the +necessary support. + +@table @code +@item --enable-job-control +This enables job control features, if the @sc{OS} supports them. + +@item --enable-alias +Allow alias expansion and include the @code{alias} and @code{unalias} +builtins. + +@item --enable-readline +Include support for command-line editing and history with the Bash +version of the Readline library. + +@item --enable-history +Include command history and the @code{fc} and @code{history} +builtin commands. + +@item --enable-bang-history +Include support for @code{csh}-like history substitution. + +@item --enable-directory-stack +Include support for a @code{csh}-like directory stack and the +@code{pushd}, @code{popd}, and @code{dirs} builtins. + +@item --enable-restricted +Include support for a @dfn{restricted shell}. If this is enabled, Bash, +when called as @code{rbash}, enters a restricted mode. See +@ref{The Restricted Shell}, for a description of restricted mode. + +@item --enable-process-substitution +This enables process substitution (@pxref{Process Substitution}) if +the @sc{OS} provides the necessary support. + +@item --enable-prompt-string-decoding +Turn on the interpretation of a number of backslash-escaped characters +in the @code{$PS1}, @code{$PS2}, @code{$PS3}, and @code{$PS4} prompt +strings. + +@item --enable-select +Include the @code{ksh} @code{select} builtin, which allows the +generation of simple menus. + +@item --enable-help-builtin +Include the @code{help} builtin, which displays help on shell builtins and +variables. + +@item --enable-array-variables +Include support for one-dimensional array shell variables. + +@item --enable-dparen-arithmetic +Include support for the @code{ksh} @code{((@dots{}))} command. + +@item --enable-brace-expansion +Include @code{csh}-like brace expansion +( @code{b@{a,b@}c} @expansion{} @code{bac bbc} ). + +@item --enable-disabled-builtins +Allow builtin commands to be invoked via @samp{builtin xxx} +even after @code{xxx} has been disabled using @samp{enable -n xxx}. +See @ref{Bash Builtins}, for details of the @code{builtin} and +@code{enable} builtin commands. + +@item --enable-command-timing +Include support for recognizing @code{time} as a reserved word and for +displaying timing statistics for the pipeline following @code{time}. This +allows pipelines as well as shell builtins and functions to be timed. + +@item --enable-usg-echo-default +Make the @code{echo} builtin expand backslash-escaped characters by default, +without requiring the @samp{-e} option. This makes the Bash @code{echo} +behave more like the System V version. + +@end table + +The file @file{config.h.top} contains C Preprocessor +@samp{#define} statements for options which are not settable from +@code{configure}. +Some of these are not meant to be changed; beware of the consequences if +you do. +Read the comments associated with each definition for more +information about its effect. + +@node Reporting Bugs +@appendix Reporting Bugs + +Please report all bugs you find in Bash. +But first, you should +make sure that it really is a bug, and that it appears in the latest +version of Bash that you have. + +Once you have determined that a bug actually exists, use the +@code{bashbug} command to submit a bug report. +If you have a fix, you are welcome to mail that as well! +Suggestions and `philosophical' bug reports may be mailed +to @code{bug-bash@@prep.ai.MIT.Edu} or posted to the Usenet +newsgroup @code{gnu.bash.bug}. + +All bug reports should include: +@itemize @bullet +@item +The version number of Bash. +@item +The hardware and operating system. +@item +The compiler used to compile Bash. +@item +A description of the bug behaviour. +@item +A short script or `recipe' which exercises the bug and may be used +to reproduce it. +@end itemize + +@noindent +@code{bashbug} inserts the first three items automatically into +the template it provides for filing a bug report. + +Please send all reports concerning this manual to +@code{chet@@ins.CWRU.Edu}. + +@node Builtin Index +@appendix Index of Shell Builtin Commands +@printindex bt + +@node Reserved Word Index +@appendix Shell Reserved Words +@printindex rw + +@node Variable Index +@appendix Parameter and Variable Index +@printindex vr + +@node Function Index +@appendix Function Index +@printindex fn + +@node Concept Index +@appendix Concept Index +@printindex cp + +@contents +@bye diff --git a/doc/builtins.1 b/doc/builtins.1 new file mode 100644 index 0000000..d0aa631 --- /dev/null +++ b/doc/builtins.1 @@ -0,0 +1,15 @@ +.\" This is a hack to force bash builtins into the whatis database +.\" and to get the list of builtins to come up with the man command. +.TH BASH_BUILTINS 1 "1996 March 20" GNU +.SH NAME +bash, :, ., alias, bg, bind, break, builtin, case, cd, command, +continue, declare, dirs, disown, echo, enable, eval, exec, exit, +export, fc, fg, for, getopts, hash, help, history, if, jobs, kill, +let, local, logout, popd, pushd, pwd, read, readonly, return, set, +shift, shopt, source, suspend, test, times, trap, type, typeset, +ulimit, umask, unalias, unset, until, wait, while \- bash built-in commands, see \fBbash\fR(1) +.SH BASH BUILTIN COMMANDS +.nr zZ 1 +.so bash.1 +.SH SEE ALSO +bash(1), sh(1) diff --git a/documentation/readline.3 b/doc/readline.3 similarity index 66% rename from documentation/readline.3 rename to doc/readline.3 index bbe9d91..e122cb7 100644 --- a/documentation/readline.3 +++ b/doc/readline.3 @@ -6,9 +6,9 @@ .\" Case Western Reserve University .\" chet@ins.CWRU.Edu .\" -.\" Last Change: Wed Jul 20 16:13:11 EDT 1994 +.\" Last Change: Mon Jul 8 13:07:48 EDT 1996 .\" -.TH READLINE 3 "1994 July 26" GNU +.TH READLINE 3 "1996 July 8" GNU .\" .\" File Name macro. This used to be `.PN', for Path Name, .\" but Sun doesn't seem to like that very much. @@ -29,132 +29,13 @@ readline \- get a line from a user with editing .LP .nf .ft B -typedef int Function (); -.LP -.nf -.ft B char *readline (prompt) char *prompt; .ft .fi -.LP -.nf -.ft B -int rl_add_defun (name, function, key) -char *name; -Function *function; -int key; -.ft -.fi -.LP -.nf -.ft B -int rl_bind_key (key, function) -int key; -Function *function; -.ft -.fi -.LP -.nf -.ft B -int rl_unbind_key (key) -int key; -.ft -.fi -.LP -.nf -.ft B -int rl_bind_key_in_map (key, function, keymap) -int key; -Function *function; -Keymap keymap; -.ft -.fi -.LP -.nf -.ft B -int rl_unbind_key_in_map (key, keymap) -int key; -Keymap keymap; -.ft -.fi -.LP -.nf -.ft B -int rl_macro_bind (keyseq, macro, keymap) -char *keyseq, *macro; -Keymap keymap; -.ft -.fi -.LP -.nf -.ft B -int rl_variable_bind (variable, value) -char *variable, *value; -.ft -.fi -.LP -.nf -.ft B -int rl_parse_and_bind (line) -char *line; -.ft -.fi -.LP -.nf -.ft B -int rl_translate_keyseq (keyseq, array, len) -char *keyseq, *array; -int *len; -.ft -.fi -.LP -.nf -.ft B -Function *rl_named_function (command) -char *command; -.ft -.fi -.LP -.nf -.ft B -Function *rl_function_of_keyseq (keyseq, keymap, type) -char *keyseq; -Keymap keymap; -int *type; -.ft -.fi -.LP -.nf -.ft B -char **rl_invoking_keyseqs (function) -Function *function; -.ft -.fi -.LP -.nf -.ft B -char **rl_invoking_keyseqs_in_map (function, keymap) -Function *function; -Keymap keymap; -.ft -.fi -.LP -.nf -.ft B -void rl_function_dumper (readable) -int readable; -.ft -.fi -.LP -.nf -.ft B -char **rl_funmap_names () -.ft -.fi .SH COPYRIGHT -.if n Readline is Copyright (C) 1989, 1991 by the Free Software Foundation, Inc. -.if t Readline is Copyright \(co 1989, 1991 by the Free Software Foundation, Inc. +.if n Readline is Copyright (C) 1989, 1991, 1993, 1995, 1996 by the Free Software Foundation, Inc. +.if t Readline is Copyright \(co 1989, 1991, 1993, 1995, 1996 by the Free Software Foundation, Inc. .SH DESCRIPTION .LP .B readline @@ -175,119 +56,6 @@ line. By default, the line editing commands are similar to those of emacs. A vi\-style line editing interface is also available. -.LP -In the following descriptions, -.B keymap -can be one of \fIemacs_keymap, emacs_meta_keymap, emacs_ctlx_keymap, -vi_insertion_keymap, or vi_movement_keymap\fP. -.LP -.B rl_add_defun -makes -.B name -appear as a bindable readline command, and makes -.B function -be the function called when that command is invoked. If -.B key -is not \-1, it is bound to -.B function -in the current keymap. -.LP -.B rl_bind_key -causes -.B key -to invoke -.BR function . -The binding is made in the current keymap. -.LP -.B rl_unbind_key -removes the binding for -.B key -in the current keymap. -.LP -.B rl_bind_key_in_map -makes the -.B key -entry in -.B keymap -invoke -.BR function . -.LP -.B rl_unbind_key_in_map -removes the binding for -.B key -in keymap -.BR keymap . -.LP -.B rl_macro_bind -makes -.B keyseq -insert the string -.BR macro . -The binding is performed in -.BR keymap . -.LP -.B rl_variable_bind -sets the value of the readline variable -.B variable -to -.BR value . -.LP -.B rl_parse_and_bind -takes as an argument a line of the same form as the readline startup -file (see -.SM -.B INITIALIZATION FILE -below) and executes the commands therein. -.LP -.B rl_translate_keyseq -converts -.B keyseq -into a new string, storing the result in -.BR array . -This translates control and meta prefixes and the readline -character escape sequences (see -.SM -.B Key Bindings -below). The length of the translated sequence is returned in -.BR *len . -.LP -.B rl_named_function -returns the function that is executed when the readline -command -.B command -is invoked. -.LP -.B rl_function_of_keyseq -returns the function that is executed when -.B keyseq -is read and -.B keymap -is the current keymap. -.B type -is set to indicate whether the return value corresponds to a -function, macro, or auxiliary keymap. -.LP -.B rl_invoking_keyseqs -returns all of the key sequences in the current keymap that -invoke -.BR function . -.LP -.B rl_invoking_keyseqs_in_map -returns all of the key sequences in -.B keymap -that invoke -.BR function . -.LP -.B rl_function_dumper -prints all of the readline functions and their bindings to the -readline output stream. If -.B readable -is non\-zero, the output is formattted so that it can be read -back in to restore the bindings. -.LP -.B rl_funmap_names -returns an array of all known readline bindable function names. -The array is sorted. .SH RETURN VALUE .LP .B readline @@ -300,12 +68,9 @@ is returned. If an .B EOF is read with a non\-empty line, it is treated as a newline. -.LP -Unless otherwise stated, -the other functions return 0 on success and non\-zero on failure. .SH NOTATION .LP -An emacs\-style notation is used to denote +An emacs-style notation is used to denote keystrokes. Control keys are denoted by C\-\fIkey\fR, e.g., C\-n means Control\-N. Similarly, .I meta @@ -333,25 +98,25 @@ behavior with arguments deviates from this are noted. When a command is described as \fIkilling\fP text, the text deleted is saved for possible future retrieval (\fIyanking\fP). The killed text is saved in a -\fIkill\-ring\fP. Consecutive kills cause the text to be +\fIkill ring\fP. Consecutive kills cause the text to be accumulated into one unit, which can be yanked all at once. Commands which do not kill text separate the chunks of text -on the kill\-ring. +on the kill ring. .SH INITIALIZATION FILE .LP Readline is customized by putting commands in an initialization -file. The name of this file is taken from the value of the +file (the \fIinputrc\fP file). +The name of this file is taken from the value of the .B INPUTRC -variable. If that variable is unset, the default is +environment variable. If that variable is unset, the default is .IR ~/.inputrc . When a program which uses the readline library starts up, the init file is read, and the key bindings and variables are set. There are only a few basic constructs allowed in the readline init file. Blank lines are ignored. Lines beginning with a \fB#\fP are comments. -Lines beginning with a \fB$\fP indicate conditional -constructs. Other lines -denote key bindings and variable settings. +Lines beginning with a \fB$\fP indicate conditional constructs. +Other lines denote key bindings and variable settings. Each program using this library may add its own commands and bindings. .PP @@ -365,7 +130,7 @@ or C\-Meta\-u: universal\-argument .RE into the -.FN ~/.inputrc +.I inputrc would make M\-C\-u execute the readline command .IR universal\-argument . .PP @@ -388,7 +153,7 @@ to a string that is inserted when the key is pressed (a \fImacro\fP). .SS Key Bindings .PP The syntax for controlling key bindings in the -.I ~/.inputrc +.I inputrc file is simple. All that is required is the name of the command or the text of a macro and a key sequence to which it should be bound. The name may be specified in one of two ways: @@ -451,10 +216,10 @@ is bound to insert the text The full set of escape sequences is .RS .TP -.B \eC- +.B \eC\- control prefix .TP -.B \eM- +.B \eM\- meta prefix .TP .B \ee @@ -487,7 +252,7 @@ option to the builtin command. Other programs using this library provide similar mechanisms. The .I inputrc -file may be edited and re\-read if a program does not provide +file may be edited and re-read if a program does not provide any other means to incorporate new bindings. .SS Variables .PP @@ -508,24 +273,6 @@ The variables and their default values are: .PP .PD 0 .TP -.B horizontal\-scroll\-mode (Off) -When set to \fBOn\fP, makes readline use a single line for display, -scrolling the input horizontally on a single screen line when it -becomes longer than the screen width rather than wrapping to a new line. -.TP -.B editing\-mode (emacs) -Controls whether readline begins with a set of key bindings similar -to \fIemacs\fP or \fIvi\fP. -.B editing\-mode -can be set to either -.B emacs -or -.BR vi . -.TP -.B mark\-modified\-lines (Off) -If set to \fBOn\fP, history lines that have been modified are displayed -with a preceding asterisk (\fB*\fP). -.TP .B bell\-style (audible) Controls what happens when readline wants to ring the terminal bell. If set to \fBnone\fP, readline never rings the bell. If set to @@ -534,24 +281,13 @@ If set to \fBaudible\fP, readline attempts to ring the terminal's bell. .TP .B comment\-begin (``#'') The string that is inserted in \fBvi\fP mode when the -.B vi\-comment +.B insert\-comment command is executed. -.TP -.B meta\-flag (Off) -If set to \fBOn\fP, readline will enable eight-bit input (that is, -it will not strip the high bit from the characters it reads), -regardless of what the terminal claims it can support. -.TP -.B convert\-meta (On) -If set to \fBOn\fP, readline will convert characters with the -eighth bit set to an ASCII key sequence -by stripping the eighth bit and prepending an -escape character (in effect, using escape as the \fImeta prefix\fP). -.TP -.B output\-meta (Off) -If set to \fBOn\fP, readline will display characters with the -eighth bit set directly rather than as a meta-prefixed escape -sequence. +This command is bound to +.B M\-# +in emacs mode and to +.B # +in vi command mode. .TP .B completion\-query\-items (100) This determines when the user is queried about viewing @@ -563,6 +299,40 @@ or equal to the value of this variable, the user is asked whether or not he wishes to view them; otherwise they are simply listed on the terminal. .TP +.B convert\-meta (On) +If set to \fBOn\fP, readline will convert characters with the +eighth bit set to an ASCII key sequence +by stripping the eighth bit and prepending an +escape character (in effect, using escape as the \fImeta prefix\fP). +.TP +.B disable\-completion (Off) +If set to \fBOn\fP, readline will inhibit word completion. Completion +characters will be inserted into the line as if they had been +mapped to \fBself-insert\fP. +.TP +.B editing\-mode (emacs) +Controls whether readline begins with a set of key bindings similar +to \fIemacs\fP or \fIvi\fP. +.B editing\-mode +can be set to either +.B emacs +or +.BR vi . +.TP +.B enable\-keypad (Off) +When set to \fBOn\fP, readline will try to enable the application +keypad when it is called. Some systems need this to enable the +arrow keys. +.TP +.B expand\-tilde (Off) +If set to \fBon\fP, tilde expansion is performed when readline +attempts word completion. +.TP +.B horizontal\-scroll\-mode (Off) +When set to \fBOn\fP, makes readline use a single line for display, +scrolling the input horizontally on a single screen line when it +becomes longer than the screen width rather than wrapping to a new line. +.TP .B keymap (emacs) Set the current readline keymap. The set of legal keymap names is \fIemacs, emacs-standard, emacs-meta, emacs-ctlx, vi, vi-move, @@ -575,6 +345,24 @@ the value of .B editing\-mode also affects the default keymap. .TP +.B mark\-directories (On) +If set to \fBOn\fP, completed directory names have a slash +appended. +.TP +.B mark\-modified\-lines (Off) +If set to \fBOn\fP, history lines that have been modified are displayed +with a preceding asterisk (\fB*\fP). +.TP +.B meta\-flag (Off) +If set to \fBOn\fP, readline will enable eight-bit input (that is, +it will not strip the high bit from the characters it reads), +regardless of what the terminal claims it can support. +.TP +.B output\-meta (Off) +If set to \fBOn\fP, readline will display characters with the +eighth bit set directly rather than as a meta-prefixed escape +sequence. +.TP .B show\-all\-if\-ambiguous (Off) This alters the default behavior of the completion functions. If set to @@ -582,9 +370,10 @@ set to words which have more than one possible completion cause the matches to be listed immediately instead of ringing the bell. .TP -.B expand\-tilde (Off) -If set to \fBon\fP, tilde expansion is performed when readline -attempts word completion. +.B visible\-stats (Off) +If set to \fBOn\fP, a character denoting a file's type as reported +by \fBstat\fP(2) is appended to the filename when listing possible +completions. .PD .SS Conditional Constructs .PP @@ -622,7 +411,7 @@ and for instance. .IP \fBapplication\fP The \fBapplication\fP construct is used to include -application\-specific settings. Each program using the readline +application-specific settings. Each program using the readline library sets the \fIapplication name\fP, and an initialization file can test for a particular value. This could be used to bind key sequences to functions useful for @@ -643,10 +432,44 @@ This command, as you saw in the previous example, terminates an .IP \fB$else\fP Commands in this branch of the \fB$if\fP directive are executed if the test fails. +.SH SEARCHING +.PP +Readline provides commands for searching through the command history +for lines containing a specified string. +There are two search modes: +.I incremental +and +.IR non-incremental . +.PP +Incremental searches begin before the user has finished typing the +search string. +As each character of the search string is typed, readline displays +the next entry from the history matching the string typed so far. +An incremental search requires only as many characters as needed to +find the desired history entry. +The Escape character is used to terminate an incremental search. +Control-J will also terminate the search. +Control-G will abort an incremental search and restore the original +line. +When the search is terminated, the history entry containing the +search string becomes the current line. +To find other matching entries in the history list, type Control-S or +Control-R as appropriate. +This will search backward or forward in the history for the next +line matching the search string typed so far. +Any other key sequence bound to a readline command will terminate +the search and execute that command. +For instance, a \fInewline\fP will terminate the search and accept +the line, thereby executing the command from the history list. +.PP +Non-incremental searches read the entire search string before starting +to search for matching history lines. The search string may be +typed by the user or part of the contents of the current line. .SH EDITING COMMANDS .PP The following is a list of the names of the commands and the default key sequences to which they are bound. +Command names without an accompanying key sequence are unbound by default. .SS Commands for Moving .PP .PD 0 @@ -677,7 +500,7 @@ With an argument, refresh the current line without clearing the screen. .TP .B redraw\-current\-line -Refresh the current line. By default, this is unbound. +Refresh the current line. .PD .SS Commands for Manipulating the History .PP @@ -685,7 +508,7 @@ Refresh the current line. By default, this is unbound. .TP .B accept\-line (Newline, Return) Accept the line regardless of where the cursor is. If this line is -non\-empty, add it to the history list. If the line is a modified +non-empty, add it to the history list. If the line is a modified history line, then restore the history line to its original state. .TP .B previous\-history (C\-p) @@ -713,21 +536,22 @@ the history as necessary. This is an incremental search. .TP .B non\-incremental\-reverse\-search\-history (M\-p) Search backward through the history starting at the current line -using a non\-incremental search for a string supplied by the user. +using a non-incremental search for a string supplied by the user. .TP .B non\-incremental\-forward\-search\-history (M\-n) -Search forward through the history using a non\-incremental search +Search forward through the history using a non-incremental search for a string supplied by the user. .TP .B history\-search\-forward Search forward through the history for the string of characters -between the start of the current line and the current point. This -is a non-incremental search. By default, this command is unbound. +between the start of the current line and the current cursor +position (the \fIpoint\fP). +This is a non-incremental search. .TP .B history\-search\-backward Search backward through the history for the string of characters -between the start of the current line and the current point. This -is a non-incremental search. By default, this command is unbound. +between the start of the current line and the point. +This is a non-incremental search. .TP .B yank\-nth\-arg (M\-C\-y) Insert the first argument to the previous command (usually @@ -740,9 +564,9 @@ inserts the \fIn\fPth word from the end of the previous command. .TP .B yank\-last\-arg (M\-.\^, M\-_\^) -Insert the last argument to the previous command (the last word on -the previous line). With an argument, -behave exactly like \fByank-nth-arg\fP. +Insert the last argument to the previous command (the last word of +the previous history entry). With an argument, +behave exactly like \fByank\-nth\-arg\fP. .PD .SS Commands for Changing Text .PP @@ -759,7 +583,7 @@ then return .TP .B backward\-delete\-char (Rubout) Delete the character behind the cursor. When given a numeric argument, -save the deleted text on the kill\-ring. +save the deleted text on the kill ring. .TP .B quoted\-insert (C\-q, C\-v) Add the next character that you type to the line verbatim. This is @@ -808,7 +632,7 @@ Kill backward from point to the beginning of the line. .TP .B kill\-whole\-line Kill all characters on the current line, no matter where the -cursor is. By default, this is unbound. +cursor is. .TP .B kill\-word (M\-d) Kill from the cursor to the end of the current word, or if between @@ -824,14 +648,27 @@ Kill the word behind the cursor, using white space as a word boundary. The word boundaries are different from .BR backward\-kill\-word . .TP -.B delete\-horizontal\-space -Delete all spaces and tabs around point. By default, this is unbound. +.B delete\-horizontal\-space (M\-\e) +Delete all spaces and tabs around point. +.TP +.B kill\-region +Kill the text between the point and \fImark\fP (saved cursor position). +This text is referred to as the \fIregion\fP. +.TP +.B copy\-region\-as\-kill +Copy the text in the region to the kill buffer. +.TP +.B copy\-backward\-word +Copy the word before point to the kill buffer. +.TP +.B copy\-forward\-word +Copy the word following point to the kill buffer. .TP .B yank (C\-y) Yank the top of the kill ring into the buffer at the cursor. .TP .B yank\-pop (M\-y) -Rotate the kill\-ring, and yank the new top. Only works following +Rotate the kill ring, and yank the new top. Only works following .B yank or .BR yank\-pop . @@ -847,8 +684,7 @@ argument. M\-\- starts a negative argument. .B universal\-argument Each time this is executed, the argument count is multiplied by four. The argument count is initially one, so executing this function the -first time makes the argument count four. By default, this is not -bound to a key. +first time makes the argument count four. .PD .SS Completing .PP @@ -868,27 +704,26 @@ on the other hand, allows completion of program functions and variables, and only attempts filename completion under certain circumstances. .TP -.B possible\-completions (M-?) +.B possible\-completions (M\-?) List the possible completions of the text before point. .TP -.B insert\-completions +.B insert\-completions (M\-*) Insert all completions of the text before point that would have been generated by -\fBpossible\-completions\fP. By default, this -is not bound to a key. +\fBpossible\-completions\fP. .PD .SS Keyboard Macros .PP .PD 0 .TP -.B start\-kbd\-macro (C-x (\^) +.B start\-kbd\-macro (C\-x (\^) Begin saving the characters typed into the current keyboard macro. .TP -.B end\-kbd\-macro (C-x )\^) +.B end\-kbd\-macro (C\-x )\^) Stop saving the characters typed into the current keyboard macro -and save the definition. +and store the definition. .TP -.B call\-last\-kbd\-macro (C-x e) +.B call\-last\-kbd\-macro (C\-x e) Re-execute the last keyboard macro defined, by making the characters in the macro appear as if typed at the keyboard. .PD @@ -896,8 +731,8 @@ in the macro appear as if typed at the keyboard. .PP .PD 0 .TP -.B re-read-init-file (C\-x C\-r) -Read in the contents of your init file, and incorporate +.B re\-read\-init\-file (C\-x C\-r) +Read in the contents of the \fIinputrc\fP file, and incorporate any bindings or variable assignments found there. .TP .B abort (C\-g) @@ -905,9 +740,9 @@ Abort the current editing command and ring the terminal's bell (subject to the setting of .BR bell\-style ). .TP -.B do\-uppercase\-version (M\-a, M\-b, ...) -Run the command that is bound to the corresponding uppercase -character. +.B do\-uppercase\-version (M\-a, M\-b, M\-\fIx\fP, ...) +If the metafied character \fIx\fP is lowercase, run the command +that is bound to the corresponding uppercase character. .TP .B prefix\-meta (ESC) Metafy the next character typed. @@ -928,12 +763,56 @@ command enough times to return the line to its initial state. .B tilde\-expand (M\-~) Perform tilde expansion on the current word. .TP +.B set\-mark (C\-@, M-) +Set the mark to the current point. If a +numeric argument is supplied, the mark is set to that position. +.TP +.B exchange\-point\-and\-mark (C\-x C\-x) +Swap the point with the mark. The current cursor position is set to +the saved position, and the old cursor position is saved as the mark. +.TP +.B character\-search (C\-]) +A character is read and point is moved to the next occurrence of that +character. A negative count searches for previous occurrences. +.TP +.B character\-search\-backward (M\-C\-]) +A character is read and point is moved to the previous occurrence of that +character. A negative count searches for subsequent occurrences. +.TP +.B insert\-comment (M\-#) +The value of the readline +.B comment\-begin +variable is inserted at the beginning of the current line, and the line +is accepted as if a newline had been typed. This makes the current line +a shell comment. +.TP +.B glob\-expand\-word (C\-x *) +The word before point is treated as a pattern for pathname expansion, +and the list of matching file names is inserted, replacing the word. +.TP +.B glob\-list\-expansions (C\-x g) +The list of expansions that would have been generated by +.B glob\-expand\-word +is inserted into the line, replacing the word before point. +.TP .B dump\-functions Print all of the functions and their key bindings to the readline output stream. 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 +.B dump\-variables +Print all of the settable variables and their values to the +readline output stream. 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 +.B dump\-macros +Print all of the readline key sequences bound to macros and the +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 .B emacs\-editing\-mode (C\-e) When in .B vi @@ -951,7 +830,7 @@ editing mode. .SH DEFAULT KEY BINDINGS .LP The following is a list of the default emacs and vi bindings. -Characters with the 8th bit set are written as M-, and +Characters with the 8th bit set are written as M\-, and are referred to as .I metafied characters. @@ -981,82 +860,93 @@ variable). .sp Emacs Standard bindings .sp -"C-A" -> beginning-of-line -"C-B" -> backward-char -"C-D" -> delete-char -"C-E" -> end-of-line -"C-F" -> forward-char -"C-G" -> abort -"C-H" -> backward-delete-char -"C-I" -> complete -"C-J" -> accept-line -"C-K" -> kill-line -"C-L" -> clear-screen -"C-M" -> accept-line -"C-N" -> next-history -"C-P" -> previous-history -"C-Q" -> quoted-insert -"C-R" -> reverse-search-history -"C-S" -> forward-search-history -"C-T" -> transpose-chars -"C-U" -> unix-line-discard -"C-V" -> quoted-insert -"C-W" -> unix-word-rubout -"C-Y" -> yank -"C-_" -> undo -"\^ " to "/" -> self-insert -"0" to "9" -> self-insert -":" to "~" -> self-insert -"C-?" -> backward-delete-char +"C-@" set-mark +"C-A" beginning-of-line +"C-B" backward-char +"C-D" delete-char +"C-E" end-of-line +"C-F" forward-char +"C-G" abort +"C-H" backward-delete-char +"C-I" complete +"C-J" accept-line +"C-K" kill-line +"C-L" clear-screen +"C-M" accept-line +"C-N" next-history +"C-P" previous-history +"C-Q" quoted-insert +"C-R" reverse-search-history +"C-S" forward-search-history +"C-T" transpose-chars +"C-U" unix-line-discard +"C-V" quoted-insert +"C-W" unix-word-rubout +"C-Y" yank +"C-]" character-search +"C-_" undo +"\^ " to "/" self-insert +"0" to "9" self-insert +":" to "~" self-insert +"C-?" backward-delete-char .PP Emacs Meta bindings .sp -"M-C-H" -> backward-kill-word -"M-C-I" -> tab-insert -"M-C-J" -> vi-editing-mode -"M-C-M" -> vi-editing-mode -"M-C-R" -> revert-line -"M-C-Y" -> yank-nth-arg -"M-C-[" -> complete -"M-&" -> tilde-expand -"M--" -> digit-argument -"M-0" -> digit-argument -"M-1" -> digit-argument -"M-2" -> digit-argument -"M-3" -> digit-argument -"M-4" -> digit-argument -"M-5" -> digit-argument -"M-6" -> digit-argument -"M-7" -> digit-argument -"M-8" -> digit-argument -"M-9" -> digit-argument -"M-<" -> beginning-of-history -"M->" -> end-of-history -"M-?" -> possible-completions -"M-B" -> backward-word -"M-C" -> capitalize-word -"M-D" -> kill-word -"M-F" -> forward-word -"M-L" -> downcase-word -"M-N" -> non-incremental-forward-search-history -"M-O" -> arrow-key-prefix -"M-P" -> non-incremental-reverse-search-history -"M-R" -> revert-line -"M-T" -> transpose-words -"M-U" -> upcase-word -"M-Y" -> yank-pop -"M-C-Y" -> yank-nth-arg -"M-C-?" -> backward-delete-word +"M-C-G" abort +"M-C-H" backward-kill-word +"M-C-I" tab-insert +"M-C-J" vi-editing-mode +"M-C-M" vi-editing-mode +"M-C-R" revert-line +"M-C-Y" yank-nth-arg +"M-C-[" complete +"M-C-]" character-search-backward +"M-space" set-mark +"M-#" insert-comment +"M-&" tilde-expand +"M-*" insert-completions +"M--" digit-argument +"M-." yank-last-arg +"M-0" digit-argument +"M-1" digit-argument +"M-2" digit-argument +"M-3" digit-argument +"M-4" digit-argument +"M-5" digit-argument +"M-6" digit-argument +"M-7" digit-argument +"M-8" digit-argument +"M-9" digit-argument +"M-<" beginning-of-history +"M-=" possible-completions +"M->" end-of-history +"M-?" possible-completions +"M-B" backward-word +"M-C" capitalize-word +"M-D" kill-word +"M-F" forward-word +"M-L" downcase-word +"M-N" non-incremental-forward-search-history +"M-P" non-incremental-reverse-search-history +"M-R" revert-line +"M-T" transpose-words +"M-U" upcase-word +"M-Y" yank-pop +"M-\e" delete-horizontal-space +"M-~" tilde-expand +"M-C-?" backward-delete-word +"M-_" yank-last-arg .PP Emacs Control-X bindings .sp -"C-XC-G" -> abort -"C-XC-R" -> re-read-init-file -"C-XC-U" -> undo -"C-X(" -> start-kbd-macro -"C-X)" -> end-kbd-macro -"C-Xe" -> call-last-kbd-macro -"C-XC-?" -> backward-kill-line +"C-XC-G" abort +"C-XC-R" re-read-init-file +"C-XC-U" undo +"C-XC-X" exchange-point-and-mark +"C-X(" start-kbd-macro +"C-X)" end-kbd-macro +"C-XE" call-last-kbd-macro +"C-XC-?" backward-kill-line .sp .RE .SS VI Mode bindings @@ -1067,105 +957,103 @@ Emacs Control-X bindings .PP VI Insert Mode functions .sp -"C-D" -> vi-eof-maybe -"C-H" -> backward-delete-char -"C-I" -> complete -"C-J" -> accept-line -"C-K" -> kill-line -"C-L" -> clear-screen -"C-M" -> accept-line -"C-N" -> next-history -"C-P" -> previous-history -"C-Q" -> quoted-insert -"C-R" -> reverse-search-history -"C-S" -> forward-search-history -"C-T" -> transpose-chars -"C-U" -> unix-line-discard -"C-V" -> quoted-insert -"C-W" -> unix-word-rubout -"C-Y" -> yank -"C-[" -> vi-movement-mode -"\^ " to "~" -> self-insert -"C-?" -> backward-delete-char +"C-D" vi-eof-maybe +"C-H" backward-delete-char +"C-I" complete +"C-J" accept-line +"C-M" accept-line +"C-R" reverse-search-history +"C-S" forward-search-history +"C-T" transpose-chars +"C-U" unix-line-discard +"C-V" quoted-insert +"C-W" unix-word-rubout +"C-Y" yank +"C-[" vi-movement-mode +"C-_" undo +"\^ " to "~" self-insert +"C-?" backward-delete-char .PP VI Command Mode functions .sp -"C-D" -> vi-eof-maybe -"C-E" -> emacs-editing-mode -"C-G" -> abort -"C-H" -> backward-char -"C-J" -> accept-line -"C-K" -> kill-line -"C-L" -> clear-screen -"C-M" -> accept-line -"C-N" -> next-history -"C-P" -> previous-history -"C-Q" -> quoted-insert -"C-R" -> reverse-search-history -"C-S" -> forward-search-history -"C-T" -> transpose-chars -"C-U" -> unix-line-discard -"C-V" -> quoted-insert -"C-W" -> unix-word-rubout -"C-Y" -> yank -"C-[" -> abort -"\^ " -> forward-char -"#" -> vi-comment -"$" -> end-of-line -"%" -> vi-match -"&" -> vi-tilde-expand -"*" -> vi-complete -"+" -> down-history -"," -> vi-char-search -"-" -> previous-history -"." -> vi-redo -"/" -> vi-search -"0" -> beginning-of-line -"1" to "9" -> vi-arg-digit -";" -> vi-char-search -"=" -> vi-complete -"?" -> vi-search -"@" -> is undefined -"A" -> vi-append-eol -"B" -> vi-prev-word -"C" -> vi-change-to -"D" -> vi-delete-to -"E" -> vi-end-word -"F" -> vi-char-search -"I" -> vi-insert-beg -"N" -> vi-search-again -"P" -> vi-put -"R" -> vi-replace -"S" -> vi-subst -"T" -> vi-char-search -"U" -> revert-line -"W" -> vi-next-word -"X" -> backward-delete-char -"Y" -> vi-yank-to -"\e" -> vi-complete -"^" -> vi-first-print -"_" -> vi-yank-arg -"a" -> vi-append-mode -"b" -> vi-prev-word -"c" -> vi-change-to -"d" -> vi-delete-to -"e" -> vi-end-word -"f" -> vi-char-search -"h" -> backward-char -"i" -> vi-insertion-mode -"j" -> next-history -"k" -> prev-history -"l" -> forward-char -"n" -> vi-search-again -"r" -> vi-change-char -"s" -> vi-subst -"t" -> vi-char-search -"u" -> undo -"w" -> vi-next-word -"x" -> vi-delete -"y" -> vi-yank-to -"|" -> vi-column -"~" -> vi-change-case +"C-D" vi-eof-maybe +"C-E" emacs-editing-mode +"C-G" abort +"C-H" backward-char +"C-J" accept-line +"C-K" kill-line +"C-L" clear-screen +"C-M" accept-line +"C-N" next-history +"C-P" previous-history +"C-Q" quoted-insert +"C-R" reverse-search-history +"C-S" forward-search-history +"C-T" transpose-chars +"C-U" unix-line-discard +"C-V" quoted-insert +"C-W" unix-word-rubout +"C-Y" yank +"\^ " forward-char +"#" insert-comment +"$" end-of-line +"%" vi-match +"&" vi-tilde-expand +"*" vi-complete +"+" next-history +"," vi-char-search +"-" previous-history +"." vi-redo +"/" vi-search +"0" beginning-of-line +"1" to "9" vi-arg-digit +";" vi-char-search +"=" vi-complete +"?" vi-search +"A" vi-append-eol +"B" vi-prev-word +"C" vi-change-to +"D" vi-delete-to +"E" vi-end-word +"F" vi-char-search +"G" vi-fetch-history +"I" vi-insert-beg +"N" vi-search-again +"P" vi-put +"R" vi-replace +"S" vi-subst +"T" vi-char-search +"U" revert-line +"W" vi-next-word +"X" backward-delete-char +"Y" vi-yank-to +"\e" vi-complete +"^" vi-first-print +"_" vi-yank-arg +"`" vi-goto-mark +"a" vi-append-mode +"b" vi-prev-word +"c" vi-change-to +"d" vi-delete-to +"e" vi-end-word +"f" vi-char-search +"h" backward-char +"i" vi-insertion-mode +"j" next-history +"k" prev-history +"l" forward-char +"m" vi-set-mark +"n" vi-search-again +"p" vi-put +"r" vi-change-char +"s" vi-subst +"t" vi-char-search +"u" undo +"w" vi-next-word +"x" vi-delete +"y" vi-yank-to +"|" vi-column +"~" vi-change-case .RE .SH "SEE ALSO" .PD 0 @@ -1183,7 +1071,6 @@ VI Command Mode functions Individual \fBreadline\fP initialization file .PD .SH AUTHORS -.RS Brian Fox, Free Software Foundation (primary author) .br bfox@ai.MIT.Edu @@ -1201,10 +1088,10 @@ version of the library that you have. .PP Once you have determined that a bug actually exists, mail a -bug report to \fIbash\-maintainers\fP@\fIprep.ai.MIT.Edu\fP. +bug report to \fIbug\-readline\fP@\fIprep.ai.MIT.Edu\fP. If you have a fix, you are welcome to mail that as well! Suggestions and `philosophical' bug reports may be mailed -to \fPbug-bash\fP@\fIprep.ai.MIT.Edu\fP or posted to the Usenet +to \fPbug-readline\fP@\fIprep.ai.MIT.Edu\fP or posted to the Usenet newsgroup .BR gnu.bash.bug . .PP diff --git a/documentation/texinfo.tex b/doc/texinfo.tex similarity index 83% rename from documentation/texinfo.tex rename to doc/texinfo.tex index ce8124e..fb7cfe5 100644 --- a/documentation/texinfo.tex +++ b/doc/texinfo.tex @@ -1,6 +1,6 @@ %% TeX macros to handle texinfo files -% Copyright (C) 1985, 86, 88, 90, 91, 92, 1993 Free Software Foundation, Inc. +% Copyright (C) 1985, 86, 88, 90, 91, 92, 93, 1994 Free Software Foundation, Inc. %This texinfo.tex file is free software; you can redistribute it and/or %modify it under the terms of the GNU General Public License as @@ -22,14 +22,30 @@ %You are forbidden to forbid anyone else to use, share and improve %what you give them. Help stamp out software-hoarding! -\def\texinfoversion{2.108} + +% Send bug reports to bug-texinfo@prep.ai.mit.edu. +% Please include a *precise* test case in each bug report. + + +% Make it possible to create a .fmt file just by loading this file: +% if the underlying format is not loaded, start by loading it now. +% Added by gildea November 1993. +\expandafter\ifx\csname fmtname\endcsname\relax\input plain\fi + +% This automatically updates the version number based on RCS. +\def\deftexinfoversion$#1: #2 ${\def\texinfoversion{#2}} +\deftexinfoversion$Revision: 2.145 $ \message{Loading texinfo package [Version \texinfoversion]:} -% Print the version number if in a .fmt file. -\everyjob{\message{[Texinfo version \texinfoversion]}\message{}} +% If in a .fmt file, print the version number +% and turn on active characters that we couldn't do earlier because +% they might have appeared in the input file name. +\everyjob{\message{[Texinfo version \texinfoversion]}\message{} + \catcode`+=\active \catcode`\_=\active} % Save some parts of plain tex whose names we will redefine. +\let\ptextilde=\~ \let\ptexlbrace=\{ \let\ptexrbrace=\} \let\ptexdots=\dots @@ -44,7 +60,15 @@ \let\ptexl=\l \let\ptexL=\L -\def\tie{\penalty 10000\ } % Save plain tex definition of ~. +% Be sure we're in horizontal mode when doing a tie, since we make space +% equivalent to this in @example-like environments. Otherwise, a space +% at the beginning of a line will start with \penalty -- and +% since \penalty is valid in vertical mode, we'd end up putting the +% penalty on the vertical list instead of in the new paragraph. +{\catcode`@ = 11 + \gdef\tie{\leavevmode\penalty\@M\ } +} +\let\~ = \tie % And make it available as @~. \message{Basics,} \chardef\other=12 @@ -53,6 +77,19 @@ % starts a new line in the output. \newlinechar = `^^J +% Set up fixed words for English. +\ifx\putwordChapter\undefined{\gdef\putwordChapter{Chapter}}\fi% +\def\putwordInfo{Info}% +\ifx\putwordSee\undefined{\gdef\putwordSee{See}}\fi% +\ifx\putwordsee\undefined{\gdef\putwordsee{see}}\fi% +\ifx\putwordfile\undefined{\gdef\putwordfile{file}}\fi% +\ifx\putwordpage\undefined{\gdef\putwordpage{page}}\fi% +\ifx\putwordsection\undefined{\gdef\putwordsection{section}}\fi% +\ifx\putwordSection\undefined{\gdef\putwordSection{Section}}\fi% +\ifx\putwordTableofContents\undefined{\gdef\putwordTableofContents{Table of Contents}}\fi% +\ifx\putwordShortContents\undefined{\gdef\putwordShortContents{Short Contents}}\fi% +\ifx\putwordAppendix\undefined{\gdef\putwordAppendix{Appendix}}\fi% + % Ignore a token. % \def\gobble#1{} @@ -144,9 +181,14 @@ % Do @cropmarks to get crop marks \def\cropmarks{\let\onepageout=\croppageout } +\newinsert\margin \dimen\margin=\maxdimen + \def\pagebody#1{\vbox to\pageheight{\boxmaxdepth=\maxdepth #1}} {\catcode`\@ =11 \gdef\pagecontents#1{\ifvoid\topins\else\unvbox\topins\fi +% marginal hacks, juha@viisa.uucp (Juha Takala) +\ifvoid\margin\else % marginal info is present + \rlap{\kern\hsize\vbox to\z@{\kern1pt\box\margin \vss}}\fi \dimen@=\dp#1 \unvbox#1 \ifvoid\footins\else\vskip\skip\footins\footnoterule \unvbox\footins\fi \ifr@ggedbottom \kern-\dimen@ \vfil \fi} @@ -297,13 +339,13 @@ % Single-spacing is done by various environments (specifically, in % \nonfillstart and \quotations). -\newskip\singlespaceskip \singlespaceskip = \baselineskip +\newskip\singlespaceskip \singlespaceskip = 12.5pt \def\singlespace{% -% Why was this kern here? It messes up equalizing space above and below -% environments. --karl, 6may93 -%{\advance \baselineskip by -\singlespaceskip -%\kern \baselineskip}% -\baselineskip=\singlespaceskip + % Why was this kern here? It messes up equalizing space above and below + % environments. --karl, 6may93 + %{\advance \baselineskip by -\singlespaceskip + %\kern \baselineskip}% + \setleading \singlespaceskip } %% Simple single-character @ commands @@ -335,6 +377,15 @@ % @. is an end-of-sentence period. \def\.{.\spacefactor=3000 } +% @enddots{} is an end-of-sentence ellipsis. +\gdef\enddots{$\mathinner{\ldotp\ldotp\ldotp\ldotp}$\spacefactor=3000} + +% @! is an end-of-sentence bang. +\gdef\!{!\spacefactor=3000 } + +% @? is an end-of-sentence query. +\gdef\?{?\spacefactor=3000 } + % @w prevents a word break. Without the \leavevmode, @w at the % beginning of a paragraph, when TeX is still in vertical mode, would % produce a whole line of output instead of starting the paragraph. @@ -389,8 +440,8 @@ \obeylines \fi % - % We do @comment here in case we are called inside an environment, - % such as @example, where each end-of-line in the input causes an + % Do @comment since we are called inside an environment such as + % @example, where each end-of-line in the input causes an % end-of-line in the output. We don't want the end-of-line after % the `@group' to put extra space in the output. Since @group % should appear on a line by itself (according to the Texinfo @@ -584,15 +635,19 @@ where each line of input produces a line of output.} \let\up = \relax \let\set = \relax \let\clear = \relax + \let\item = \relax + \let\message = \relax } % Ignore @ignore ... @end ignore. % \def\ignore{\doignore{ignore}} -% Also ignore @ifinfo, @menu, and @direntry text. +% Also ignore @ifinfo, @ifhtml, @html, @menu, and @direntry text. % \def\ifinfo{\doignore{ifinfo}} +\def\ifhtml{\doignore{ifhtml}} +\def\html{\doignore{html}} \def\menu{\doignore{menu}} \def\direntry{\doignore{direntry}} @@ -679,6 +734,11 @@ where each line of input produces a line of output.} \let\tenrm = \nullfont \let\tenit = \nullfont \let\tensl = \nullfont \let\tenbf = \nullfont \let\tentt = \nullfont \let\smallcaps = \nullfont \let\tensf = \nullfont + % Similarly for index fonts (mostly for their use in + % smallexample) + \let\indrm = \nullfont \let\indit = \nullfont \let\indsl = \nullfont + \let\indbf = \nullfont \let\indtt = \nullfont \let\indsc = \nullfont + \let\indsf = \nullfont % % Don't complain when characters are missing from the fonts. \tracinglostchars = 0 @@ -712,7 +772,10 @@ where each line of input produces a line of output.} \else \setzzz{#1}#2\endsetzzz % Remove the trailing space \setxxx inserted. \fi } -\def\setzzz#1#2 \endsetzzz{\expandafter\xdef\csname SET#1\endcsname{#2}} +% Can't use \xdef to pre-expand #2 and save some time, since \temp or +% \next or other control sequences that we've defined might get us into +% an infinite loop. Consider `@set foo @cite{bar}'. +\def\setzzz#1#2 \endsetzzz{\expandafter\gdef\csname SET#1\endcsname{#2}} % @clear VAR clears (i.e., unsets) the variable VAR. % @@ -814,15 +877,15 @@ where each line of input produces a line of output.} \def\donoderef{\ifx\lastnode\relax\else \expandafter\expandafter\expandafter\setref{\lastnode}\fi -\let\lastnode=\relax} +\global\let\lastnode=\relax} \def\unnumbnoderef{\ifx\lastnode\relax\else \expandafter\expandafter\expandafter\unnumbsetref{\lastnode}\fi -\let\lastnode=\relax} +\global\let\lastnode=\relax} \def\appendixnoderef{\ifx\lastnode\relax\else \expandafter\expandafter\expandafter\appendixsetref{\lastnode}\fi -\let\lastnode=\relax} +\global\let\lastnode=\relax} \let\refill=\relax @@ -841,7 +904,7 @@ where each line of input produces a line of output.} \outer\def\bye{\pagealignmacro\tracingstats=1\ptexend} \def\inforef #1{\inforefzzz #1,,,,**} -\def\inforefzzz #1,#2,#3,#4**{See Info file \file{\ignorespaces #3{}}, +\def\inforefzzz #1,#2,#3,#4**{\putwordSee{} \putwordInfo{} \putwordfile{} \file{\ignorespaces #3{}}, node \samp{\ignorespaces#1{}}} \message{fonts,} @@ -857,28 +920,39 @@ where each line of input produces a line of output.} %% Try out Computer Modern fonts at \magstephalf \let\mainmagstep=\magstephalf +% Set the font macro #1 to the font named #2, adding on the +% specified font prefix (normally `cm'). +\def\setfont#1#2{\font#1=\fontprefix#2} + +% Use cm as the default font prefix. +% To specify the font prefix, you must define \fontprefix +% before you read in texinfo.tex. +\ifx\fontprefix\undefined +\def\fontprefix{cm} +\fi + \ifx\bigger\relax \let\mainmagstep=\magstep1 -\font\textrm=cmr12 -\font\texttt=cmtt12 +\setfont\textrm{r12} +\setfont\texttt{tt12} \else -\font\textrm=cmr10 scaled \mainmagstep -\font\texttt=cmtt10 scaled \mainmagstep +\setfont\textrm{r10 scaled \mainmagstep} +\setfont\texttt{tt10 scaled \mainmagstep} \fi % Instead of cmb10, you many want to use cmbx10. % cmbx10 is a prettier font on its own, but cmb10 % looks better when embedded in a line with cmr10. -\font\textbf=cmb10 scaled \mainmagstep -\font\textit=cmti10 scaled \mainmagstep -\font\textsl=cmsl10 scaled \mainmagstep -\font\textsf=cmss10 scaled \mainmagstep -\font\textsc=cmcsc10 scaled \mainmagstep +\setfont\textbf{b10 scaled \mainmagstep} +\setfont\textit{ti10 scaled \mainmagstep} +\setfont\textsl{sl10 scaled \mainmagstep} +\setfont\textsf{ss10 scaled \mainmagstep} +\setfont\textsc{csc10 scaled \mainmagstep} \font\texti=cmmi10 scaled \mainmagstep \font\textsy=cmsy10 scaled \mainmagstep % A few fonts for @defun, etc. -\font\defbf=cmbx10 scaled \magstep1 %was 1314 -\font\deftt=cmtt10 scaled \magstep1 +\setfont\defbf{bx10 scaled \magstep1} %was 1314 +\setfont\deftt{tt10 scaled \magstep1} \def\df{\let\tentt=\deftt \let\tenbf = \defbf \bf} % Fonts for indices and small examples. @@ -886,66 +960,66 @@ where each line of input produces a line of output.} % because texinfo normally uses the slanted fonts for that. % Do not make many font distinctions in general in the index, since they % aren't very useful. -\font\ninett=cmtt9 -\font\indrm=cmr9 -\font\indit=cmsl9 +\setfont\ninett{tt9} +\setfont\indrm{r9} +\setfont\indit{sl9} \let\indsl=\indit \let\indtt=\ninett \let\indsf=\indrm \let\indbf=\indrm -\let\indsc=\indrm +\setfont\indsc{csc10 at 9pt} \font\indi=cmmi9 \font\indsy=cmsy9 % Fonts for headings -\font\chaprm=cmbx12 scaled \magstep2 -\font\chapit=cmti12 scaled \magstep2 -\font\chapsl=cmsl12 scaled \magstep2 -\font\chaptt=cmtt12 scaled \magstep2 -\font\chapsf=cmss12 scaled \magstep2 +\setfont\chaprm{bx12 scaled \magstep2} +\setfont\chapit{ti12 scaled \magstep2} +\setfont\chapsl{sl12 scaled \magstep2} +\setfont\chaptt{tt12 scaled \magstep2} +\setfont\chapsf{ss12 scaled \magstep2} \let\chapbf=\chaprm -\font\chapsc=cmcsc10 scaled\magstep3 +\setfont\chapsc{csc10 scaled\magstep3} \font\chapi=cmmi12 scaled \magstep2 \font\chapsy=cmsy10 scaled \magstep3 -\font\secrm=cmbx12 scaled \magstep1 -\font\secit=cmti12 scaled \magstep1 -\font\secsl=cmsl12 scaled \magstep1 -\font\sectt=cmtt12 scaled \magstep1 -\font\secsf=cmss12 scaled \magstep1 -\font\secbf=cmbx12 scaled \magstep1 -\font\secsc=cmcsc10 scaled\magstep2 +\setfont\secrm{bx12 scaled \magstep1} +\setfont\secit{ti12 scaled \magstep1} +\setfont\secsl{sl12 scaled \magstep1} +\setfont\sectt{tt12 scaled \magstep1} +\setfont\secsf{ss12 scaled \magstep1} +\setfont\secbf{bx12 scaled \magstep1} +\setfont\secsc{csc10 scaled\magstep2} \font\seci=cmmi12 scaled \magstep1 \font\secsy=cmsy10 scaled \magstep2 -% \font\ssecrm=cmbx10 scaled \magstep1 % This size an font looked bad. -% \font\ssecit=cmti10 scaled \magstep1 % The letters were too crowded. -% \font\ssecsl=cmsl10 scaled \magstep1 -% \font\ssectt=cmtt10 scaled \magstep1 -% \font\ssecsf=cmss10 scaled \magstep1 +% \setfont\ssecrm{bx10 scaled \magstep1} % This size an font looked bad. +% \setfont\ssecit{cmti10 scaled \magstep1} % The letters were too crowded. +% \setfont\ssecsl{sl10 scaled \magstep1} +% \setfont\ssectt{tt10 scaled \magstep1} +% \setfont\ssecsf{ss10 scaled \magstep1} -%\font\ssecrm=cmb10 scaled 1315 % Note the use of cmb rather than cmbx. -%\font\ssecit=cmti10 scaled 1315 % Also, the size is a little larger than -%\font\ssecsl=cmsl10 scaled 1315 % being scaled magstep1. -%\font\ssectt=cmtt10 scaled 1315 -%\font\ssecsf=cmss10 scaled 1315 +%\setfont\ssecrm{b10 scaled 1315} % Note the use of cmb rather than cmbx. +%\setfont\ssecit{ti10 scaled 1315} % Also, the size is a little larger than +%\setfont\ssecsl{sl10 scaled 1315} % being scaled magstep1. +%\setfont\ssectt{tt10 scaled 1315} +%\setfont\ssecsf{ss10 scaled 1315} %\let\ssecbf=\ssecrm -\font\ssecrm=cmbx12 scaled \magstephalf -\font\ssecit=cmti12 scaled \magstephalf -\font\ssecsl=cmsl12 scaled \magstephalf -\font\ssectt=cmtt12 scaled \magstephalf -\font\ssecsf=cmss12 scaled \magstephalf -\font\ssecbf=cmbx12 scaled \magstephalf -\font\ssecsc=cmcsc10 scaled \magstep1 +\setfont\ssecrm{bx12 scaled \magstephalf} +\setfont\ssecit{ti12 scaled \magstephalf} +\setfont\ssecsl{sl12 scaled \magstephalf} +\setfont\ssectt{tt12 scaled \magstephalf} +\setfont\ssecsf{ss12 scaled \magstephalf} +\setfont\ssecbf{bx12 scaled \magstephalf} +\setfont\ssecsc{csc10 scaled \magstep1} \font\sseci=cmmi12 scaled \magstephalf \font\ssecsy=cmsy10 scaled \magstep1 % The smallcaps and symbol fonts should actually be scaled \magstep1.5, % but that is not a standard magnification. % Fonts for title page: -\font\titlerm = cmbx12 scaled \magstep3 +\setfont\titlerm{bx12 scaled \magstep3} \let\authorrm = \secrm % In order for the font changes to affect most math symbols and letters, @@ -1001,9 +1075,9 @@ where each line of input produces a line of output.} \newcount\fontdepth \fontdepth=0 % Fonts for short table of contents. -\font\shortcontrm=cmr12 -\font\shortcontbf=cmbx12 -\font\shortcontsl=cmsl12 +\setfont\shortcontrm{r12} +\setfont\shortcontbf{bx12} +\setfont\shortcontsl{sl12} %% Add scribe-like font environments, plus @l for inline lisp (usually sans %% serif) and @ii for TeX italic @@ -1074,10 +1148,17 @@ where each line of input produces a line of output.} % and arrange explicitly to hyphenate an a dash. % -- rms. { -\catcode `\-=\active -\catcode `\_=\active -\global\def\code{\begingroup \catcode `\-=\active \let-\codedash \let_\codeunder \codex} +\catcode`\-=\active +\catcode`\_=\active +\global\def\code{\begingroup \catcode`\-=\active \let-\codedash \catcode`\_=\active \let_\codeunder \codex} +% The following is used by \doprintindex to insure that long function names +% wrap around. It is necessary for - and _ to be active before the index is +% read from the file, as \entry parses the arguments long before \code is +% ever called. -- mycroft +\global\def\indexbreaks{\catcode`\-=\active \let-\realdash \catcode`\_=\active \let_\realunder} } +\def\realdash{-} +\def\realunder{_} \def\codedash{-\discretionary{}{}{}} \def\codeunder{\normalunderscore\discretionary{}{}{}} \def\codex #1{\tclose{#1}\endgroup} @@ -1140,7 +1221,7 @@ where each line of input produces a line of output.} \def\titlezzz##1{\leftline{\titlefont{##1}} % print a rule at the page bottom also. \finishedtitlepagefalse - \vskip4pt \hrule height 4pt \vskip4pt}% + \vskip4pt \hrule height 4pt width \hsize \vskip4pt}% % No rule at page bottom unless we print one at the top with @title. \finishedtitlepagetrue % @@ -1180,7 +1261,7 @@ where each line of input produces a line of output.} } \def\finishtitlepage{% - \vskip4pt \hrule height 2pt + \vskip4pt \hrule height 2pt width \hsize \vskip\titlepagebottomglue \finishedtitlepagetrue } @@ -1354,14 +1435,18 @@ July\or August\or September\or October\or November\or December\fi % They also define \itemindex % to index the item name in whatever manner is desired (perhaps none). +\newif\ifitemxneedsnegativevskip + +\def\itemxpar{\par\ifitemxneedsnegativevskip\vskip-\parskip\nobreak\fi} + \def\internalBitem{\smallbreak \parsearg\itemzzz} -\def\internalBitemx{\par \parsearg\itemzzz} +\def\internalBitemx{\itemxpar \parsearg\itemzzz} \def\internalBxitem "#1"{\def\xitemsubtopix{#1} \smallbreak \parsearg\xitemzzz} -\def\internalBxitemx "#1"{\def\xitemsubtopix{#1} \par \parsearg\xitemzzz} +\def\internalBxitemx "#1"{\def\xitemsubtopix{#1} \itemxpar \parsearg\xitemzzz} \def\internalBkitem{\smallbreak \parsearg\kitemzzz} -\def\internalBkitemx{\par \parsearg\kitemzzz} +\def\internalBkitemx{\itemxpar \parsearg\kitemzzz} \def\kitemzzz #1{\dosubind {kw}{\code{#1}}{for {\bf \lastfunction}}% \itemzzz {#1}} @@ -1377,9 +1462,9 @@ July\or August\or September\or October\or November\or December\fi \nobreak % This prevents a break before @itemx. % % Be sure we are not still in the middle of a paragraph. - {\parskip = 0in - \par - }% + %{\parskip = 0in + %\par + %}% % % If the item text does not fit in the space we have, put it on a line % by itself, and do not allow a page break either before or after that @@ -1387,7 +1472,15 @@ July\or August\or September\or October\or November\or December\fi % command is, e.g., @kindex, the whatsit would get put into the % horizontal list on a line by itself, resulting in extra blank space. \ifdim \wd0>\itemmax - \setbox0=\hbox{\hskip \leftskip \hskip -\tableindent \unhbox0}\box0 + % + % Make this a paragraph so we get the \parskip glue and wrapping, + % but leave it ragged-right. + \begingroup + \advance\leftskip by-\tableindent + \advance\hsize by\tableindent + \advance\rightskip by0pt plus1fil + \leavevmode\unhbox0\par + \endgroup % % We're going to be starting a paragraph, but we don't want the % \parskip glue -- logically it's part of the @item we just started. @@ -1397,15 +1490,18 @@ July\or August\or September\or October\or November\or December\fi % we can't prevent a possible page break at the following % \baselineskip glue. \nobreak + \endgroup + \itemxneedsnegativevskipfalse \else % The item text fits into the space. Start a paragraph, so that the % following text (if any) will end up on the same line. Since that % text will be indented by \tableindent, we make the item text be in % a zero-width box. \noindent - \rlap{\hskip -\tableindent\box0}% + \rlap{\hskip -\tableindent\box0}\ignorespaces% + \endgroup% + \itemxneedsnegativevskiptrue% \fi - \endgroup } \def\item{\errmessage{@item while not in a table}} @@ -1611,6 +1707,159 @@ July\or August\or September\or October\or November\or December\fi \vadjust{\penalty 1200}}% \flushcr} +% @multitable macros +% Amy Hendrickson, 8/18/94 +% +% @multitable ... @endmultitable will make as many columns as desired. +% Contents of each column will wrap at width given in preamble. Width +% can be specified either with sample text given in a template line, +% or in percent of \hsize, the current width of text on page. + +% Table can continue over pages but will only break between lines. + +% To make preamble: +% +% Either define widths of columns in terms of percent of \hsize: +% @multitable @percentofhsize .2 .3 .5 +% @item ... +% +% Numbers following @percentofhsize are the percent of the total +% current hsize to be used for each column. You may use as many +% columns as desired. + +% Or use a template: +% @multitable {Column 1 template} {Column 2 template} {Column 3 template} +% @item ... +% using the widest term desired in each column. + + +% Each new table line starts with @item, each subsequent new column +% starts with @tab. Empty columns may be produced by supplying @tab's +% with nothing between them for as many times as empty columns are needed, +% ie, @tab@tab@tab will produce two empty columns. + +% @item, @tab, @multicolumn or @endmulticolumn do not need to be on their +% own lines, but it will not hurt if they are. + +% Sample multitable: + +% @multitable {Column 1 template} {Column 2 template} {Column 3 template} +% @item first col stuff @tab second col stuff @tab third col +% @item +% first col stuff +% @tab +% second col stuff +% @tab +% third col +% @item first col stuff @tab second col stuff +% @tab Many paragraphs of text may be used in any column. +% +% They will wrap at the width determined by the template. +% @item@tab@tab This will be in third column. +% @endmultitable + +% Default dimensions may be reset by user. +% @intableparskip will set vertical space between paragraphs in table. +% @intableparindent will set paragraph indent in table. +% @spacebetweencols will set horizontal space to be left between columns. +% @spacebetweenlines will set vertical space to be left between lines. + +%%%% +% Dimensions + +\newdimen\intableparskip +\newdimen\intableparindent +\newdimen\spacebetweencols +\newdimen\spacebetweenlines +\intableparskip=0pt +\intableparindent=6pt +\spacebetweencols=12pt +\spacebetweenlines=12pt + +%%%% +% Macros used to set up halign preamble: +\let\endsetuptable\relax +\def\xendsetuptable{\endsetuptable} +\let\percentofhsize\relax +\def\xpercentofhsize{\percentofhsize} +\newif\ifsetpercent + +\newcount\colcount +\def\setuptable#1{\def\firstarg{#1}% +\ifx\firstarg\xendsetuptable\let\go\relax% +\else + \ifx\firstarg\xpercentofhsize\global\setpercenttrue% + \else + \ifsetpercent + \if#1.\else% + \global\advance\colcount by1 % + \expandafter\xdef\csname col\the\colcount\endcsname{.#1\hsize}% + \fi + \else + \global\advance\colcount by1 + \setbox0=\hbox{#1}% + \expandafter\xdef\csname col\the\colcount\endcsname{\the\wd0}% + \fi% + \fi% + \let\go\setuptable% +\fi\go} +%%%% +% multitable syntax +\def\tab{&} + +%%%% +% @multitable ... @endmultitable definitions: + +\def\multitable#1\item{\bgroup +\let\item\cr +\tolerance=9500 +\hbadness=9500 +\parskip=\intableparskip +\parindent=\intableparindent +\overfullrule=0pt +\global\colcount=0\relax% +\def\Emultitable{\global\setpercentfalse\global\everycr{}\cr\egroup\egroup}% + % To parse everything between @multitable and @item : +\def\one{#1}\expandafter\setuptable\one\endsetuptable + % Need to reset this to 0 after \setuptable. +\global\colcount=0\relax% + % + % This preamble sets up a generic column definition, which will + % be used as many times as user calls for columns. + % \vtop will set a single line and will also let text wrap and + % continue for many paragraphs if desired. +\halign\bgroup&\global\advance\colcount by 1\relax% +\vtop{\hsize=\expandafter\csname col\the\colcount\endcsname + % In order to keep entries from bumping into each other + % we will add a \leftskip of \spacebetweencols to all columns after + % the first one. + % If a template has been used, we will add \spacebetweencols + % to the width of each template entry. + % If user has set preamble in terms of percent of \hsize + % we will use that dimension as the width of the column, and + % the \leftskip will keep entries from bumping into each other. + % Table will start at left margin and final column will justify at + % right margin. +\ifnum\colcount=1 +\else + \ifsetpercent + \else + % If user has set preamble in terms of percent of \hsize + % we will advance \hsize by \spacebetweencols + \advance\hsize by \spacebetweencols + \fi + % In either case we will make \leftskip=\spacebetweencols: +\leftskip=\spacebetweencols +\fi +\noindent##}\cr% + % \everycr will reset column counter, \colcount, at the end of + % each line. Every column entry will cause \colcount to advance by one. + % The table preamble + % looks at the current \colcount to find the correct column width. +\global\everycr{\noalign{\nointerlineskip\vskip\spacebetweenlines +\filbreak%% keeps underfull box messages off when table breaks over pages. +\global\colcount=0\relax}}} + \message{indexing,} % Index generation facilities @@ -1685,6 +1934,32 @@ July\or August\or September\or October\or November\or December\fi \def\singlecodeindexer #1{\doind{\indexname}{\code{#1}}} \def\indexdummies{% +% Take care of the plain tex accent commands. +\def\"{\realbackslash "}% +\def\`{\realbackslash `}% +\def\'{\realbackslash '}% +\def\^{\realbackslash ^}% +\def\~{\realbackslash ~}% +\def\={\realbackslash =}% +\def\b{\realbackslash b}% +\def\c{\realbackslash c}% +\def\d{\realbackslash d}% +\def\u{\realbackslash u}% +\def\v{\realbackslash v}% +\def\H{\realbackslash H}% +% Take care of the plain tex special European modified letters. +\def\oe{\realbackslash oe}% +\def\ae{\realbackslash ae}% +\def\aa{\realbackslash aa}% +\def\OE{\realbackslash OE}% +\def\AE{\realbackslash AE}% +\def\AA{\realbackslash AA}% +\def\o{\realbackslash o}% +\def\O{\realbackslash O}% +\def\l{\realbackslash l}% +\def\L{\realbackslash L}% +\def\ss{\realbackslash ss}% +% Take care of texinfo commands likely to appear in an index entry. \def\_{{\realbackslash _}}% \def\w{\realbackslash w }% \def\bf{\realbackslash bf }% @@ -1722,6 +1997,31 @@ July\or August\or September\or October\or November\or December\fi \def\indexdummydots{...} \def\indexnofonts{% +% Just ignore accents. +\let\"=\indexdummyfont +\let\`=\indexdummyfont +\let\'=\indexdummyfont +\let\^=\indexdummyfont +\let\~=\indexdummyfont +\let\==\indexdummyfont +\let\b=\indexdummyfont +\let\c=\indexdummyfont +\let\d=\indexdummyfont +\let\u=\indexdummyfont +\let\v=\indexdummyfont +\let\H=\indexdummyfont +% Take care of the plain tex special European modified letters. +\def\oe{oe}% +\def\ae{ae}% +\def\aa{aa}% +\def\OE{OE}% +\def\AE{AE}% +\def\AA{AA}% +\def\o{o}% +\def\O{O}% +\def\l{l}% +\def\L{L}% +\def\ss{ss}% \let\w=\indexdummyfont \let\t=\indexdummyfont \let\r=\indexdummyfont @@ -1754,7 +2054,14 @@ July\or August\or September\or October\or November\or December\fi \let\indexbackslash=0 %overridden during \printindex. +\let\SETmarginindex=\relax %initialize! +% workhorse for all \fooindexes +% #1 is name of index, #2 is stuff to put there \def\doind #1#2{% +% Put the index entry in the margin if desired. +\ifx\SETmarginindex\relax\else% +\insert\margin{\hbox{\vrule height8pt depth3pt width0pt #2}}% +\fi% {\count10=\lastpenalty % {\indexdummies % Must do this here, since \bf, etc expand at this stage \escapechar=`\\% @@ -1838,8 +2145,9 @@ July\or August\or September\or October\or November\or December\fi \tex \dobreak \chapheadingskip {10000} \catcode`\%=\other\catcode`\&=\other\catcode`\#=\other - \catcode`\$=\other\catcode`\_=\other + \catcode`\$=\other \catcode`\~=\other + \indexbreaks % % The following don't help, since the chars were translated % when the raw index was written, and their fonts were discarded @@ -1932,23 +2240,32 @@ July\or August\or September\or October\or November\or December\fi % % Insert the text of the index entry. TeX will do line-breaking on it. #1% - % - % If we must, put the page number on a line of its own, and fill out - % this line with blank space. (The \hfil is overwhelmed with the - % fill leaders glue in \indexdotfill if the page number does fit.) - \hfil\penalty50 - \null\nobreak\indexdotfill % Have leaders before the page number. - % - % The `\ ' here is removed by the implicit \unskip that TeX does as - % part of (the primitive) \par. Without it, a spurious underfull - % \hbox ensues. - \ #2% The page number ends the paragraph. + % The following is kluged to not output a line of dots in the index if + % there are no page numbers. The next person who breaks this will be + % cursed by a Unix daemon. + \def\tempa{{\rm }}% + \def\tempb{#2}% + \edef\tempc{\tempa}% + \edef\tempd{\tempb}% + \ifx\tempc\tempd\ \else% + % + % If we must, put the page number on a line of its own, and fill out + % this line with blank space. (The \hfil is overwhelmed with the + % fill leaders glue in \indexdotfill if the page number does fit.) + \hfil\penalty50 + \null\nobreak\indexdotfill % Have leaders before the page number. + % + % The `\ ' here is removed by the implicit \unskip that TeX does as + % part of (the primitive) \par. Without it, a spurious underfull + % \hbox ensues. + \ #2% The page number ends the paragraph. + \fi% \par \endgroup} % Like \dotfill except takes at least 1 em. \def\indexdotfill{\cleaders - \hbox{$\mathsurround=0pt \mkern1.5mu . \mkern1.5mu$}\hskip 1em plus 1fill} + \hbox{$\mathsurround=0pt \mkern1.5mu ${\it .}$ \mkern1.5mu$}\hskip 1em plus 1fill} \def\primary #1{\line{#1\hfil}} @@ -2180,13 +2497,13 @@ July\or August\or September\or October\or November\or December\fi \def\chapteryyy #1{\numhead0{#1}} % normally numhead0 calls chapterzzz \def\chapterzzz #1{\seccheck{chapter}% \secno=0 \subsecno=0 \subsubsecno=0 -\global\advance \chapno by 1 \message{Chapter \the\chapno}% +\global\advance \chapno by 1 \message{\putwordChapter \the\chapno}% \chapmacro {#1}{\the\chapno}% \gdef\thissection{#1}% \gdef\thischaptername{#1}% % We don't substitute the actual chapter name into \thischapter % because we don't want its macros evaluated now. -\xdef\thischapter{Chapter \the\chapno: \noexpand\thischaptername}% +\xdef\thischapter{\putwordChapter{} \the\chapno: \noexpand\thischaptername}% {\chapternofonts% \edef\temp{{\realbackslash chapentry {#1}{\the\chapno}{\noexpand\folio}}}% \escapechar=`\\% @@ -2202,13 +2519,13 @@ July\or August\or September\or October\or November\or December\fi \def\appendixzzz #1{\seccheck{appendix}% \secno=0 \subsecno=0 \subsubsecno=0 \global\advance \appendixno by 1 \message{Appendix \appendixletter}% -\chapmacro {#1}{Appendix \appendixletter}% +\chapmacro {#1}{\putwordAppendix{} \appendixletter}% \gdef\thissection{#1}% \gdef\thischaptername{#1}% -\xdef\thischapter{Appendix \appendixletter: \noexpand\thischaptername}% +\xdef\thischapter{\putwordAppendix{} \appendixletter: \noexpand\thischaptername}% {\chapternofonts% \edef\temp{{\realbackslash chapentry - {#1}{Appendix \appendixletter}{\noexpand\folio}}}% + {#1}{\putwordAppendix{} \appendixletter}{\noexpand\folio}}}% \escapechar=`\\% \write \contentsfile \temp % \appendixnoderef % @@ -2567,6 +2884,7 @@ July\or August\or September\or October\or November\or December\fi \unnumbchapmacro{#1}\def\thischapter{}% \begingroup % Set up to handle contents files properly. \catcode`\\=0 \catcode`\{=1 \catcode`\}=2 \catcode`\@=11 + \catcode`\^=7 % to see ^^e4 as \"a etc. juha@piuha.ydi.vtt.fi \raggedbottom % Worry more about breakpoints than the bottom. \advance\hsize by -\contentsrightmargin % Don't use the full line length. } @@ -2574,7 +2892,7 @@ July\or August\or September\or October\or November\or December\fi % Normal (long) toc. \outer\def\contents{% - \startcontents{Table of Contents}% + \startcontents{\putwordTableofContents}% \input \jobname.toc \endgroup \vfill \eject @@ -2582,7 +2900,7 @@ July\or August\or September\or October\or November\or December\fi % And just the chapters. \outer\def\summarycontents{% - \startcontents{Short Contents}% + \startcontents{\putwordShortContents}% % \let\chapentry = \shortchapentry \let\unnumbchapentry = \shortunnumberedentry @@ -2621,7 +2939,7 @@ July\or August\or September\or October\or November\or December\fi % We could simplify the code here by writing out an \appendixentry % command in the toc file for appendices, instead of using \chapentry % for both, but it doesn't seem worth it. -\setbox0 = \hbox{\shortcontrm Appendix } +\setbox0 = \hbox{\shortcontrm \putwordAppendix } \newdimen\shortappendixwidth \shortappendixwidth = \wd0 \def\shortchaplabel#1{% @@ -2775,6 +3093,7 @@ July\or August\or September\or October\or November\or December\fi \catcode`\>=12 \escapechar=`\\ % +\let\~=\ptextilde \let\{=\ptexlbrace \let\}=\ptexrbrace \let\.=\ptexdot @@ -2809,7 +3128,7 @@ July\or August\or September\or October\or November\or December\fi % Define \obeyedspace to be our active space, whatever it is. This is % for use in \parsearg. -{\sepspaces % +{\sepspaces% \global\let\obeyedspace= } % This space is always present above and below environments. @@ -2949,9 +3268,9 @@ July\or August\or September\or October\or November\or December\fi \let\Esmallexample = \nonfillfinish % % Smaller interline space and fonts for small examples. - \baselineskip 10pt + \setleading{10pt}% \indexfonts \tt - \rawbackslash % output the \ character from the current font + \rawbackslash % make \ output the \ character from the current font (tt) \gobble } @@ -2987,23 +3306,26 @@ July\or August\or September\or October\or November\or December\fi \advance\leftskip by 0pt plus 1fill \gobble} -% @quotation does normal linebreaking and narrows the margins. +% @quotation does normal linebreaking (hence we can't use \nonfillstart) +% and narrows the margins. % \def\quotation{% -\begingroup\inENV %This group ends at the end of the @quotation body -{\parskip=0pt % because we will skip by \parskip too, later -\aboveenvbreak}% -\singlespace -\parindent=0pt -\let\Equotation = \nonfillfinish -% @cartouche defines \nonarrowing to inhibit narrowing -% at next level down. -\ifx\nonarrowing\relax -\advance \leftskip by \lispnarrowing -\advance \rightskip by \lispnarrowing -\exdentamount=\lispnarrowing -\let\nonarrowing=\relax -\fi} + \begingroup\inENV %This group ends at the end of the @quotation body + {\parskip=0pt \aboveenvbreak}% because \aboveenvbreak inserts \parskip + \singlespace + \parindent=0pt + % We have retained a nonzero parskip for the environment, since we're + % doing normal filling. So to avoid extra space below the environment... + \def\Equotation{\parskip = 0pt \nonfillfinish}% + % + % @cartouche defines \nonarrowing to inhibit narrowing at next level down. + \ifx\nonarrowing\relax + \advance\leftskip by \lispnarrowing + \advance\rightskip by \lispnarrowing + \exdentamount = \lispnarrowing + \let\nonarrowing = \relax + \fi +} \message{defuns,} % Define formatter for defuns @@ -3035,6 +3357,9 @@ July\or August\or September\or October\or November\or December\fi \gdef\functionparens{\boldbrax\let&=\amprm\parencount=0 } \gdef\boldbrax{\let(=\opnr\let)=\clnr\let[=\lbrb\let]=\rbrb} +% This is used to turn on special parens +% but make & act ordinary (given that it's active). +\gdef\boldbraxnoamp{\let(=\opnr\let)=\clnr\let[=\lbrb\let]=\rbrb\let&=\ampnr} % Definitions of (, ) and & used in args for functions. % This is the definition of ( outside of all parentheses. @@ -3104,7 +3429,7 @@ July\or August\or September\or October\or November\or December\fi \advance\leftskip by \defbodyindent \advance \rightskip by \defbodyindent \exdentamount=\defbodyindent \begingroup % -\catcode 61=\active % +\catcode 61=\active % 61 is `=' \obeylines\activeparens\spacesplit#3} \def\defmethparsebody #1#2#3#4 {\begingroup\inENV % @@ -3147,55 +3472,54 @@ July\or August\or September\or October\or November\or December\fi \catcode 61=\active % \obeylines\spacesplit#3} -\def\defvrparsebody #1#2#3#4 {\begingroup\inENV % -\medbreak % -% Define the end token that this defining construct specifies -% so that it will exit this group. -\def#1{\endgraf\endgroup\medbreak}% -\def#2##1 {\begingroup\obeylines\spacesplit{#3{##1}}}% -\parindent=0in -\advance\leftskip by \defbodyindent \advance \rightskip by \defbodyindent -\exdentamount=\defbodyindent -\begingroup\obeylines\spacesplit{#3{#4}}} - -% This seems to work right in all cases. -\let\deftpparsebody=\defvrparsebody -% This fails to work. When given `@deftp {Data Type} foo_t', -% it thinks the type name is just `f'. -%%% This is the same as all the others except for the last line. We need -%%% to parse the arguments differently for @deftp, since the ``attributes'' -%%% there are optional. -%%% -%%\def\deftpparsebody #1#2#3#4 {\begingroup\inENV % -%%\medbreak % -%%% Define the end token that this defining construct specifies -%%% so that it will exit this group. -%%\def#1{\endgraf\endgroup\medbreak}% -%%\def#2##1 {\begingroup\obeylines\spacesplit{#3{##1}}}% -%%\parindent=0in -%%\advance\leftskip by \defbodyindent \advance \rightskip by \defbodyindent -%%\exdentamount=\defbodyindent -%%\begingroup\obeylines\parsetpheaderline{#3{#4}}} - -%%{\obeylines % -%% % Parse the type name and any attributes (field names, etc.). -%% % #1 is the beginning of the macro call that will produce the output, -%% % i.e., \deftpheader{CLASS}; this is passed from \deftpparsebody. -%% % #2 is the type name, e.g., `struct termios'. -%% % #3 is the (possibly empty) attribute list. -%% % -%% \gdef\parsetpheaderline#1#2#3^^M{% -%% \endgroup % Started in \deftpparsebody. -%% % -%% % If the attribute list is in fact empty, there will be no space after -%% % #2; so we can't put a space in our TeX parameter list. But if it -%% % isn't empty, then #3 will begin with an unwanted space. -%% \def\theargs{\ignorespaces #3}% -%% % -%% % Call the macro to produce the output. -%% #1{#2}\theargs % -%% }% -%%} +% This is used for \def{tp,vr}parsebody. It could probably be used for +% some of the others, too, with some judicious conditionals. +% +\def\parsebodycommon#1#2#3{% + \begingroup\inENV % + \medbreak % + % Define the end token that this defining construct specifies + % so that it will exit this group. + \def#1{\endgraf\endgroup\medbreak}% + \def#2##1 {\begingroup\obeylines\spacesplit{#3{##1}}}% + \parindent=0in + \advance\leftskip by \defbodyindent \advance \rightskip by \defbodyindent + \exdentamount=\defbodyindent + \begingroup\obeylines +} + +\def\defvrparsebody#1#2#3#4 {% + \parsebodycommon{#1}{#2}{#3}% + \spacesplit{#3{#4}}% +} + +% This loses on `@deftp {Data Type} {struct termios}' -- it thinks the +% type is just `struct', because we lose the braces in `{struct +% termios}' when \spacesplit reads its undelimited argument. Sigh. +% \let\deftpparsebody=\defvrparsebody +% +% So, to get around this, we put \empty in with the type name. That +% way, TeX won't find exactly `{...}' as an undelimited argument, and +% won't strip off the braces. +% +\def\deftpparsebody #1#2#3#4 {% + \parsebodycommon{#1}{#2}{#3}% + \spacesplit{\parsetpheaderline{#3{#4}}}\empty +} + +% Fine, but then we have to eventually remove the \empty *and* the +% braces (if any). That's what this does, putting the result in \tptemp. +% +\def\removeemptybraces\empty#1\relax{\def\tptemp{#1}}% + +% After \spacesplit has done its work, this is called -- #1 is the final +% thing to call, #2 the type name (which starts with \empty), and #3 +% (which might be empty) the arguments. +% +\def\parsetpheaderline#1#2#3{% + \removeemptybraces#2\relax + #1{\tptemp}{#3}% +}% \def\defopvarparsebody #1#2#3#4#5 {\begingroup\inENV % \medbreak % @@ -3244,8 +3568,9 @@ July\or August\or September\or October\or November\or December\fi \def\deftypefunargs #1{% % Expand, preventing hyphenation at `-' chars. % Note that groups don't affect changes in \hyphenchar. -\functionparens -\code{#1}% +% Use \boldbraxnoamp, not \functionparens, so that & is not special. +\boldbraxnoamp +\tclose{#1}% avoid \code because of side effects on active chars \interlinepenalty=10000 \advance\rightskip by 0pt plus 1fil \endgraf\penalty 10000\vskip -\parskip\penalty 10000% @@ -3281,7 +3606,7 @@ July\or August\or September\or October\or November\or December\fi % #1 is the data type, #2 the name, #3 the args. \def\deftypefunheaderx #1#2 #3\relax{% \doind {fn}{\code{#2}}% Make entry in function index -\begingroup\defname {\code{#1} #2}{Function}% +\begingroup\defname {\defheaderxcond#1\relax$$$#2}{Function}% \deftypefunargs {#3}\endgroup % \catcode 61=\other % Turn off change made in \defparsebody } @@ -3290,12 +3615,19 @@ July\or August\or September\or October\or November\or December\fi \def\deftypefn{\defmethparsebody\Edeftypefn\deftypefnx\deftypefnheader} +% \defheaderxcond#1\relax$$$ +% puts #1 in @code, followed by a space, but does nothing if #1 is null. +\def\defheaderxcond#1#2$$${\ifx#1\relax\else\code{#1#2} \fi} + % #1 is the classification. #2 is the data type. #3 is the name and args. \def\deftypefnheader #1#2#3{\deftypefnheaderx{#1}{#2}#3 \relax} % #1 is the classification, #2 the data type, #3 the name, #4 the args. \def\deftypefnheaderx #1#2#3 #4\relax{% \doind {fn}{\code{#3}}% Make entry in function index -\begingroup\defname {\code{#2} #3}{#1}% +\begingroup +\normalparens % notably, turn off `&' magic, which prevents +% at least some C++ text from working +\defname {\defheaderxcond#2\relax$$$#3}{#1}% \deftypefunargs {#4}\endgroup % \catcode 61=\other % Turn off change made in \defparsebody } @@ -3423,7 +3755,7 @@ July\or August\or September\or October\or November\or December\fi % #1 is the data type. #2 is the name. \def\deftypevarheader #1#2{% \doind {vr}{\code{#2}}% Make entry in variables index -\begingroup\defname {\code{#1} #2}{Variable}% +\begingroup\defname {\defheaderxcond#1\relax$$$#2}{Variable}% \interlinepenalty=10000 \endgraf\penalty 10000\vskip -\parskip\penalty 10000 \endgroup} @@ -3433,7 +3765,7 @@ July\or August\or September\or October\or November\or December\fi \def\deftypevr{\defvrparsebody\Edeftypevr\deftypevrx\deftypevrheader} \def\deftypevrheader #1#2#3{\doind {vr}{\code{#3}}% -\begingroup\defname {\code{#2} #3}{#1} +\begingroup\defname {\defheaderxcond#2\relax$$$#3}{#1} \interlinepenalty=10000 \endgraf\penalty 10000\vskip -\parskip\penalty 10000 \endgroup} @@ -3474,17 +3806,17 @@ July\or August\or September\or October\or November\or December\fi % \setref{foo} defines a cross-reference point named foo. \def\setref#1{% -%\dosetq{#1-title}{Ytitle}% +\dosetq{#1-title}{Ytitle}% \dosetq{#1-pg}{Ypagenumber}% \dosetq{#1-snt}{Ysectionnumberandtype}} \def\unnumbsetref#1{% -%\dosetq{#1-title}{Ytitle}% +\dosetq{#1-title}{Ytitle}% \dosetq{#1-pg}{Ypagenumber}% \dosetq{#1-snt}{Ynothing}} \def\appendixsetref#1{% -%\dosetq{#1-title}{Ytitle}% +\dosetq{#1-title}{Ytitle}% \dosetq{#1-pg}{Ypagenumber}% \dosetq{#1-snt}{Yappendixletterandtype}} @@ -3494,43 +3826,63 @@ July\or August\or September\or October\or November\or December\fi % file, #5 the name of the printed manual. All but the node name can be % omitted. % -\def\pxref#1{see \xrefX[#1,,,,,,,]} -\def\xref#1{See \xrefX[#1,,,,,,,]} +\def\pxref#1{\putwordsee{} \xrefX[#1,,,,,,,]} +\def\xref#1{\putwordSee{} \xrefX[#1,,,,,,,]} \def\ref#1{\xrefX[#1,,,,,,,]} -\def\xrefX[#1,#2,#3,#4,#5,#6]{\begingroup% -\def\printedmanual{\ignorespaces #5}% -\def\printednodename{\ignorespaces #3}% -% -\setbox1=\hbox{\printedmanual}% -\setbox0=\hbox{\printednodename}% -\ifdim \wd0=0pt% -\def\printednodename{\ignorespaces #1}% -%%% Uncommment the following line to make the actual chapter or section title -%%% appear inside the square brackets. -%\def\printednodename{#1-title}% -\fi% -% -% -% If we use \unhbox0 and \unhbox1 to print the node names, TeX does -% not insert empty discretionaries after hyphens, which means that it -% will not find a line break at a hyphen in a node names. Since some -% manuals are best written with fairly long node names, containing -% hyphens, this is a loss. Therefore, we simply give the text of -% the node name again, so it is as if TeX is seeing it for the first -% time. -\ifdim \wd1>0pt -section ``\printednodename'' in \cite{\printedmanual}% -\else% -\turnoffactive% -\refx{#1-snt}{} [\printednodename], page\tie\refx{#1-pg}{}% -\fi +\def\xrefX[#1,#2,#3,#4,#5,#6]{\begingroup + \def\printedmanual{\ignorespaces #5}% + \def\printednodename{\ignorespaces #3}% + \setbox1=\hbox{\printedmanual}% + \setbox0=\hbox{\printednodename}% + \ifdim \wd0 = 0pt + % No printed node name was explicitly given. + \ifx\SETxref-automatic-section-title\relax % + % Use the actual chapter/section title appear inside + % the square brackets. Use the real section title if we have it. + \ifdim \wd1>0pt% + % It is in another manual, so we don't have it. + \def\printednodename{\ignorespaces #1}% + \else + \ifhavexrefs + % We know the real title if we have the xref values. + \def\printednodename{\refx{#1-title}}% + \else + % Otherwise just copy the Info node name. + \def\printednodename{\ignorespaces #1}% + \fi% + \fi + \def\printednodename{#1-title}% + \else + % Use the node name inside the square brackets. + \def\printednodename{\ignorespaces #1}% + \fi + \fi + % + % If we use \unhbox0 and \unhbox1 to print the node names, TeX does not + % insert empty discretionaries after hyphens, which means that it will + % not find a line break at a hyphen in a node names. Since some manuals + % are best written with fairly long node names, containing hyphens, this + % is a loss. Therefore, we give the text of the node name again, so it + % is as if TeX is seeing it for the first time. + \ifdim \wd1 > 0pt + \putwordsection{} ``\printednodename'' in \cite{\printedmanual}% + \else + % _ (for example) has to be the character _ for the purposes of the + % control sequence corresponding to the node, but it has to expand + % into the usual \leavevmode...\vrule stuff for purposes of + % printing. So we \turnoffactive for the \refx-snt, back on for the + % printing, back off for the \refx-pg. + {\turnoffactive \refx{#1-snt}{}}% + \space [\printednodename],\space + \turnoffactive \putwordpage\tie\refx{#1-pg}{}% + \fi \endgroup} % \dosetq is the interface for calls from other macros % Use \turnoffactive so that punctuation chars such as underscore % work in node names. -\def\dosetq #1#2{{\let\folio=0 \turnoffactive% +\def\dosetq #1#2{{\let\folio=0 \turnoffactive \auxhat% \edef\next{\write\auxfile{\internalsetq {#1}{#2}}}% \next}} @@ -3544,26 +3896,26 @@ section ``\printednodename'' in \cite{\printedmanual}% \def\Ypagenumber{\folio} -\def\Ytitle{\thischapter} +\def\Ytitle{\thissection} \def\Ynothing{} \def\Ysectionnumberandtype{% -\ifnum\secno=0 Chapter\xreftie\the\chapno % -\else \ifnum \subsecno=0 Section\xreftie\the\chapno.\the\secno % +\ifnum\secno=0 \putwordChapter\xreftie\the\chapno % +\else \ifnum \subsecno=0 \putwordSection\xreftie\the\chapno.\the\secno % \else \ifnum \subsubsecno=0 % -Section\xreftie\the\chapno.\the\secno.\the\subsecno % +\putwordSection\xreftie\the\chapno.\the\secno.\the\subsecno % \else % -Section\xreftie\the\chapno.\the\secno.\the\subsecno.\the\subsubsecno % +\putwordSection\xreftie\the\chapno.\the\secno.\the\subsecno.\the\subsubsecno % \fi \fi \fi } \def\Yappendixletterandtype{% -\ifnum\secno=0 Appendix\xreftie'char\the\appendixno{}% -\else \ifnum \subsecno=0 Section\xreftie'char\the\appendixno.\the\secno % +\ifnum\secno=0 \putwordAppendix\xreftie'char\the\appendixno{}% +\else \ifnum \subsecno=0 \putwordSection\xreftie'char\the\appendixno.\the\secno % \else \ifnum \subsubsecno=0 % -Section\xreftie'char\the\appendixno.\the\secno.\the\subsecno % +\putwordSection\xreftie'char\the\appendixno.\the\secno.\the\subsecno % \else % -Section\xreftie'char\the\appendixno.\the\secno.\the\subsecno.\the\subsubsecno % +\putwordSection\xreftie'char\the\appendixno.\the\secno.\the\subsecno.\the\subsubsecno % \fi \fi \fi } \gdef\xreftie{'tie} @@ -3651,6 +4003,15 @@ Section\xreftie'char\the\appendixno.\the\secno.\the\subsecno.\the\subsubsecno % \catcode `\&=\other % `\+ does not work, so use 43. \catcode 43=\other +% Make the characters 128-255 be printing characters +{% + \count 1=128 + \def\loop{% + \catcode\count 1=\other + \advance\count 1 by 1 + \ifnum \count 1<256 \loop \fi + }% +}% % the aux file uses ' as the escape. % Turn off \ as an escape so we do not lose on % entries which were dumped with control sequences in their names. @@ -3660,6 +4021,7 @@ Section\xreftie'char\the\appendixno.\the\secno.\the\subsecno.\the\subsubsecno % \catcode `\{=1 \catcode `\}=2 \catcode `\%=\other \catcode `\'=0 +\catcode`\^=7 % to make ^^e4 etc usable in xref tags \catcode `\\=\other \openin 1 \jobname.aux \ifeof 1 \else \closein 1 \input \jobname.aux \global\havexrefstrue @@ -3846,6 +4208,8 @@ Section\xreftie'char\the\appendixno.\the\secno.\the\subsecno.\the\subsubsecno % \global\tolerance=700 \global\hfuzz=1pt \global\contentsrightmargin=0pt +\global\deftypemargin=0pt +\global\defbodyindent=.5cm \global\pagewidth=\hsize \global\pageheight=\vsize @@ -3875,6 +4239,32 @@ Section\xreftie'char\the\appendixno.\the\secno.\the\subsecno.\the\subsubsecno % \global\pageheight=\vsize } +% Allow control of the text dimensions. Parameters in order: textheight; +% textwidth; \voffset; \hoffset (!); binding offset. All require a dimension; +% header is additional; added length extends the bottom of the page. + +\def\changepagesizes#1#2#3#4#5{ + \global\vsize= #1 + \advance\vsize by \topskip + \global\voffset= #3 + \global\hsize= #2 + \global\outerhsize=\hsize + \global\advance\outerhsize by 0.5in + \global\outervsize=\vsize + \global\advance\outervsize by 0.6in + \global\pagewidth=\hsize + \global\pageheight=\vsize + \global\normaloffset= #4 + \global\bindingoffset= #5} + +% This layout is compatible with Latex on A4 paper. + +\def\afourlatex{\changepagesizes{22cm}{15cm}{7mm}{4.6mm}{5mm}} + +% Use @afourwide to print on European A4 paper in wide format. +\def\afourwide{\afourpaper +\changepagesizes{9.5in}{6.5in}{\hoffset}{\normaloffset}{\bindingoffset}} + % Define macros to output various characters with catcode for normal text. \catcode`\"=\other \catcode`\~=\other @@ -3916,6 +4306,7 @@ Section\xreftie'char\the\appendixno.\the\secno.\the\subsecno.\the\subsubsecno % \def~{{\tt \char '176}} \chardef\hat=`\^ \catcode`\^=\active +\def\auxhat{\def^{'hat}} \def^{{\tt \hat}} \catcode`\_=\active @@ -3943,21 +4334,19 @@ Section\xreftie'char\the\appendixno.\the\secno.\the\subsecno.\the\subsubsecno % %\catcode 27=\active %\def^^[{$\diamondsuit$} -% Used sometimes to turn off (effectively) the active characters -% even after parsing them. -\def\turnoffactive{\let"=\normaldoublequote -\let~=\normaltilde -\let^=\normalcaret -\let_=\normalunderscore -\let|=\normalverticalbar -\let<=\normalless -\let>=\normalgreater -\let+=\normalplus} - % Set up an active definition for =, but don't enable it most of the time. {\catcode`\==\active \global\def={{\tt \char 61}}} +\catcode`+=\active +\catcode`\_=\active + +% If a .fmt file is being used, characters that might appear in a file +% name cannot be active until we have parsed the command line. +% So turn them off again, and have \everyjob (or @setfilename) turn them on. +% \otherifyactive is called near the end of this file. +\def\otherifyactive{\catcode`+=\other \catcode`\_=\other} + \catcode`\@=0 % \rawbackslashxx output one backslash character in current font @@ -3978,6 +4367,32 @@ Section\xreftie'char\the\appendixno.\the\secno.\the\subsecno.\the\subsubsecno % % \catcode 17=0 % Define control-q \catcode`\\=\active +% Used sometimes to turn off (effectively) the active characters +% even after parsing them. +@def@turnoffactive{@let"=@normaldoublequote +@let\=@realbackslash +@let~=@normaltilde +@let^=@normalcaret +@let_=@normalunderscore +@let|=@normalverticalbar +@let<=@normalless +@let>=@normalgreater +@let+=@normalplus} + +@def@normalturnoffactive{@let"=@normaldoublequote +@let\=@normalbackslash +@let~=@normaltilde +@let^=@normalcaret +@let_=@normalunderscore +@let|=@normalverticalbar +@let<=@normalless +@let>=@normalgreater +@let+=@normalplus} + +% Make _ and + \other characters, temporarily. +% This is canceled by @fixbackslash. +@otherifyactive + % If a .fmt file is being used, we don't want the `\input texinfo' to show up. % That is what \eatinput is for; after that, the `\' should revert to printing % a backslash. @@ -3988,8 +4403,11 @@ Section\xreftie'char\the\appendixno.\the\secno.\the\subsecno.\the\subsubsecno % % On the other hand, perhaps the file did not have a `\input texinfo'. Then % the first `\{ in the file would cause an error. This macro tries to fix % that, assuming it is called before the first `\' could plausibly occur. +% Also back turn on active characters that might appear in the input +% file name, in case not using a pre-dumped format. % -@gdef@fixbackslash{@ifx\@eatinput @let\ = @normalbackslash @fi} +@gdef@fixbackslash{@ifx\@eatinput @let\ = @normalbackslash @fi + @catcode`+=@active @catcode`@_=@active} %% These look ok in all fonts, so just make them not special. The @rm below %% makes sure that the current font starts out as the newly loaded cmr10 diff --git a/documentation/FAQ b/documentation/FAQ deleted file mode 100644 index c44bc47..0000000 --- a/documentation/FAQ +++ /dev/null @@ -1,795 +0,0 @@ -This is the Bash FAQ, version 1.2, for Bash version 1.14.6. - -This document contains a set of frequently-asked questions concerning -Bash, the GNU Bourne-Again Shell. Bash is a freely-available command -interpreter with advanced features for both interactive use and shell -programming. - -Another good source of basic information about shells is the collection -of FAQ articles periodically posted to comp.unix.shell. - -Questions and comments concerning this document should be set to -chet@po.cwru.edu. - -Contents: -1) What is it? -2) What's the latest version? -3) Where can I get it? -4) What's the `Posix 1003.2 standard'? -5) On what machines will bash run? -6) How does bash differ from sh, the Bourne shell? -7) How does bash differ from the Korn shell? -8) What is the bash `posix mode'? -9) How can I build bash with gcc? -10) Why does bash run a different version of `command' than - `which command' says it will? -11) How can I make my csh aliases work when I convert to bash? -12) Now that I've converted from ksh to bash, are there equivalents to - ksh features like autoloaded functions and the `whence' command? -13) Why is the bash builtin `test' slightly different from /bin/test? -14) Why does bash sometimes say `Broken pipe'? -15) How can I get bash to read and display eight-bit characters? -16) Why can't I use command line editing in my `cmdtool'? -17) How do I write a function `x' to replace builtin command `x', but - still invoke the command from within the function? -18) When I have terminal escape sequences in my prompt, why does bash - wrap lines at the wrong column? -19) I built bash on Solaris 2. Why do globbing expansions and filename - completion chop off the first few characters of each filename? -20) Why doesn't bash treat brace expansions exactly like csh? -21) Why does bash dump core after I interrupt username completion? -22) I'm running SVR4.2. Why is the line erased every time I type `@'? -23) How can I find the value of a shell variable whose name is the value - of another shell variable? -24) If I pipe the output of a command into `read variable', why doesn't - the output show up in $variable when the read command finishes? -25) I just changed my shell to bash, and now I can't FTP into my machine. - Why not? -26) I have a bunch of shell scripts that use backslash-escaped characters - in arguments to `echo'. Bash doesn't interpret these characters. Why - not, and how can I make it understand them? -27) Why doesn't bash have csh variable modifiers? -28) Why does bash report syntax errors when my C News scripts use a - redirection before a subshell command? -29) How do I report bugs in bash, and where should I look for fixes and - advice? -30) What kind of bash documentation is there? -31) What's coming in future versions? -32) What's on the bash `wish list'? -33) When will the next release appear? - -1) What is it? - -Bash is a Unix command interpreter (shell). It is an implementation of -the Posix 1003.2 shell standard, and resembles the Korn and System V -shells. - -Bash contains a number of enhancements over those shells, both -for interactive use and shell programming. Features geared -toward interactive use include command line editing, command -history, job control, aliases, and prompt expansion. Programming -features include additional variable expansions, shell -arithmetic, and a number of variables and options to control -shell behavior. - -Bash was originally written by Brian Fox of the Free Software -Foundation. The current developer and maintainer is Chet Ramey -of Case Western Reserve University. - -2) What's the latest version? - -The latest version is 1.14.6, first made available on December 19, 1995. - -3) Where can I get it? - -Bash is the GNU project's shell, and so is available from the -master GNU archive site, prep.ai.mit.edu, and its mirrors. The -latest version is also available for FTP from slc2.ins.cwru.edu, -the maintainer's machine. The following URLs tell how to get -version 1.14.6: - -ftp://prep.ai.mit.edu/pub/gnu/bash-1.14.6.tar.gz -ftp://slc2.ins.cwru.edu/pub/dist/bash-1.14.6.tar.gz - -4) What's the `Posix 1003.2 standard'? - -POSIX is a name originally coined by Richard Stallman for a -family of open system standards based on UNIX. There are a -number of aspects of UNIX under consideration for -standardization, from the basic system services at the system -call and C library level to applications and tools to system -administration and management. Each area of standardization is -assigned to a working group in the 1003 series. - -The POSIX Shell and Utilities standard has been developed by IEEE -Working Group 1003.2 (POSIX.2). It concentrates on the command -interpreter interface and utility programs commonly executed from -the command line or by other programs. An initial version of the -standard has been approved and published by the IEEE, and work is -currently underway to update it. - -Bash is concerned with the aspects of the shell's behavior -defined by POSIX.2. The shell command language has of course -been standardized, including the basic flow control and program -execution constructs, I/O redirection and pipelining, argument -handling, variable expansion, and quoting. - -The `special' builtins, which must be implemented as part of the -shell to provide the desired functionality, are specified as -being part of the shell; examples of these are `eval' and -`export'. Other utilities appear in the sections of POSIX.2 not -devoted to the shell which are commonly (and in some cases must -be) implemented as builtin commands, such as `read' and `test'. -POSIX.2 also specifies aspects of the shell's interactive -behavior as part of the UPE, including job control and command -line editing. Only vi-style line editing commands have been -standardized; emacs editing commands were left out due to -objections. - -5) On what machines will bash run? - -Bash has been ported to nearly every version of UNIX. All you -should have to do to build it on a machine for which a port -exists is to type `make'. The build process will attempt to -discover the version of UNIX you have and tailor itself -accordingly, using a combination of saved definitions in the file -`machines.h' and a file `sysdefs.h' created by inspecting the -environment for various things. - -More information appears in the file `INSTALL' in the distribution. - -6) How does bash differ from sh, the Bourne shell? - -This is a non-comprehensive list of features that differentiate bash -from the SVR4 shell. The bash manual page explains these completely. - -Things bash has that sh does not: - long invocation options - `!' reserved word to invert pipeline return value - the select compound command - the $(...) form of command substitution - the ${#param} parameter value length operator - expansions to perform substring removal (${p%[%]w}, ${p#[#]w}) - variables: BASH, BASH_VERSION, UID, EUID, REPLY, PPID, PWD, - OLDPWD, SHLVL, RANDOM, SECONDS, LINENO, HISTCMD, - HOSTTYPE, OSTYPE, ENV, MAIL_WARNING, PS3, PS4, - HISTSIZE, HISTFILE, HISTFILESIZE, PROMPT_COMMAND, - FCEDIT, FIGNORE, IGNOREEOF, INPUTRC, HISTCONTROL, - command_oriented_history, allow_null_glob_expansion, - glob_dot_filenames, histchars, nolinks, auto_resume, - HOSTFILE, noclobber, TMOUT, no_exit_on_failed_exec, - cdable_vars - redirections: <>, &>, >| - prompt string special char translation and variable expansion - auto-export of modified values of variables in initial environment - command search finds functions before builtins - bash return builtin will exit a file sourced with `.' - builtins: cd -, exec -, echo -e/-E, export -n/-f/-p/name=value, - pwd -P, read -r, readonly -f, trap -l, ulimit -n/-p/-u, - set -b/-m/-o option/-p/-l/-d/-C/-H/-P, unset -f/-v, - umask -S, type -all/-path/-type, suspend -f, kill -s - bash reads ~/.bashrc for interactive shells, $ENV for non-interactive - bash restricted shell mode is more extensive - bash allows functions and variables with the same name - brace expansion - tilde expansion - arithmetic expansion and `let' builtin - process substitution - aliases and alias/unalias builtins - local variables in functions and `local' builtin - readline and command-line editing - history and history/fc builtins - csh-like history expansion - other new bash builtins: bind, command, builtin, declare/typeset, - dirs, enable, fc, help, history, logout, - popd, pushd - exported functions - filename generation when using output redirection (command >a*) - -Things sh has that bash does not: - uses variable SHACCT to do shell accounting - includes `stop' builtin (bash can use alias stop='kill -s STOP') - `newgrp' builtin - turns on job control if called as `jsh' - ulimit attempts to set both soft & hard limits if -S/-H not given - -New things in the SVR4.2 sh: - internationalization: $LANG, $LC_CTYPE, $LC_MESSAGES, setlocale, etc. - $TIMEOUT (like bash $TMOUT) - new builtins: mldmode, priv - `read' builtin has -r - cannot trap SIGALRM or SIGCHLD - kill -s is present - -Implementation differences: - redirection to/from compound commands causes sh to create a subshell - bash does not allow unbalanced quotes; sh silently inserts them at EOF - bash does not mess with signal 11 - sh sets (euid, egid) to (uid, gid) if -p not supplied and uid < 100 - bash splits only the results of expansions on IFS - sh does not allow MAILCHECK to be unset (?) - -7) How does bash differ from the Korn shell? - -Things bash has or uses that ksh does not: - long invocation options - `!' reserved word - posix mode and posix conformance - command hashing - tilde expansion for assignment statements that look like $PATH - process substitution with named pipes if /dev/fd is not available - variables: BASH, BASH_VERSION, UID, EUID, SHLVL, HISTCMD, HOSTTYPE, - OSTYPE, MAIL_WARNING, HISTFILESIZE, OPTERR, - PROMPT_COMMAND, IGNOREEOF, FIGNORE, INPUTRC, HISTCONTROL, - notify, command_oriented_history, glob_dot_filenames, - allow_null_glob_expansion, histchars, nolinks, HOSTFILE, - noclobber, auto_resume, no_exit_on_failed_exec, cdable_vars - prompt expansion with backslash escapes and command substitution - redirection: &> (stdout and stderr) - more extensive and extensible editing and completion - builtins: bind, builtin, command, declare, dirs, echo -e/-E, enable, - exec -, fc -s, export -n/-f/-p, hash, help, history, - jobs -x, kill -s, local, logout, popd, pushd, - readonly -n/-f/-p, set -o braceexpand/-o histexpand/ - -o interactive-comments/-o notify/-o physical/-o posix/ - -l/-d/-C/-b/-H/-P, suspend, trap -l, type, ulimit -u, - umask -S - $[...] synonym for $((...)) - `!' csh-style history expansion - -Things ksh has or uses that bash does not: - new version of test: [[...]] - ((...)) equivalent to let "..." - time keyword to let pipelines be timed - tracked aliases - $(&p, <&p) - weirdly-scoped functions - typeset +f to list all function names without definitions - text of command history kept in a file, not memory - builtins: alias -x, cd old new, fc -e -, newgrp, print, - read -p/-s/u/var?prompt, set -A/-o gmacs/-o keyword/ - -o bgnice/-o markdirs/-o nolog/-o trackall/-o viraw/-s, - typeset -H/-L/-R/-A/-ft/-fu/-fx/-l/-u/-t, whence - -Implementation differences: - ksh runs last command of a pipeline in parent shell context - ksh ulimit sets hard and soft limits by default - bash has brace expansion by default - bash has fixed startup file for all interactive shells; ksh reads $ENV - bash has exported functions - bash command search finds functions before builtins - -8) What is the bash `posix mode'? - -Although bash is an implementation of the Posix.2 shell -specification, there are areas where the bash default behavior -differs from that spec. The bash `posix mode' changes the bash -behavior in these areas so that it obeys the spec more closely. - -Posix mode is entered by starting bash with the -posix option or -executing `set -o posix' after bash is running. - -The specific aspects of bash which change when posix mode is -active are listed in the file CWRU/POSIX.NOTES in the bash -distribution. - -9) How can I build bash with gcc? - -Type - make CC=gcc CPPNAME='$(CC) -E' - -10) Why does bash run a different version of `command' than - `which command' says it will? - -`which' is actually a csh script that assumes you're running csh. -It reads the csh startup files from your home directory and uses -those to determine which `command' will be invoked. Since bash -doesn't use any of those startup files, there's a good chance -that your bash environment differs from your csh environment. - -11) How can I make my csh aliases work when I convert to bash? - -Bash uses a different syntax to support aliases than csh does. -The details can be found in the documentation. We have provided -a shell script which does most of the work of conversion for you; -this script can be found in ./examples/alias-conv.sh. Here is -how you use it: - -Start csh in the normal way for you. (e.g., `csh') - -Pipe the output of `alias' through `alias-conv.sh', saving the -results into `bash_aliases': - - alias | alias-conv.sh >bash_aliases - -Edit `bash_aliases', carefully reading through any created -functions. You will need to change the names of csh specific -variables (like $cwd) to the bash equivalents (like $PWD). You -will also need to remove recursive references to commands which -are defined as functions. For example, the csh alias: - - alias cd 'cd \!*;echo $cwd' - -is converted to the bash function: - - cd () - { - cd $*; - echo $cwd - } - -This function contains a self-pointing reference to `cd', which -should be changed to use the `builtin' version. It also uses -the csh variable `$cwd' which has an equivalent in bash. -Precede the recursive reference with the word `builtin', and -change the name of the variable: - - cd () { builtin cd $*; echo $PWD; } - -Merge the edited file into your ~/.bashrc. - -12) Now that I've converted from ksh to bash, are there equivalents to - ksh features like autoloaded functions and the `whence' command? - -There are features in ksh-88 that do not have direct bash equivalents. -Most, however, can be emulated with very little trouble. - -ksh-88 feature Bash equivalent --------------- --------------- -[[...]] can usually use [...]; minor differences -compiled-in aliases set up aliases in .bashrc; some ksh aliases are - bash builtins (hash, history, type) -$(&2; read var - -13) Why is the bash builtin `test' slightly different from /bin/test? - -The specific example used here is [ ! x -o x ], which is false. - -Bash's builtin `test' implements the Posix.2 spec, which can be -summarized as follows (the wording is due to David Korn): - -Here is the set of rules for processing test arguments. - - 0 Args: False - 1 Arg: True iff argument is not null. - 2 Args: If first arg is !, True iff second argument is null. - If first argument is unary, then true if unary test is true - Otherwise error. - 3 Args: If second argument is a binary operator, do binary test of $1 $3 - If first argument is !, negate two argument test of $2 $3 - Otherwise error. - 4 Args: If first argument is !, negate three argument test of $2 $3 $4. - Otherwise unspecified - 5 or more Args: unspecified. (Historical shells would use their - current algorithm). - -The operators -a and -o are considered binary operators for the purpose -of the 3 Arg case. - -As you can see, the test becomes (not (x or x)), which is false. - -14) Why does bash sometimes say `Broken pipe'? - -If a sequence of commands appear in a pipeline, and one of the -reading commands finishes before the writer has finished, the -writer receives a SIGPIPE signal. Many other shells special-case -SIGPIPE as an exit status in the pipeline and do not report it. -For example, in: - - ps -aux | head - -`head' can finish before `ps' writes all of its output, and ps -will try to write on a pipe without a reader. In that case, bash -will print `Broken pipe' to stderr when ps is killed by a -SIGPIPE. - -15) How can I get bash to read and display eight-bit characters? - -This is a process requiring several steps. - -First, you must ensure that the `physical' data path is a full eight -bits. For xterms, for example, the `vt100' resources `eightBitInput' -and `eightBitOutput' should be set to `true'. - -Once you have set up an eight-bit path, you must tell the kernel and -tty driver to leave the eigth bit of characters alone when processing -keyboard input. Use `stty' to do this: - - stty cs8 -istrip -parenb - -For old BSD-style systems, you can use - - stty pass8 - -You may also need - - stty even odd - -Finally, you need to tell readline that you will be inputting and -displaying eight-bit characters. You use readline variables to do -this. These variables can be set in your .inputrc or using the bash -`bind' builtin. Here's an example using `bind': - - bash$ bind 'set convert-meta off' - bash$ bind 'set meta-flag on' - bash$ bind 'set output-meta on' - -The `set' commands between the single quotes may also be placed -in ~/.inputrc. - -16) Why can't I use command line editing in my `cmdtool'? - -The problem is `cmdtool' and bash fighting over the input. When -scrolling is enabled in a cmdtool window, cmdtool puts the tty in -`raw mode' to permit command-line editing using the mouse for -applications that cannot do it themselves. As a result, bash and -cmdtool each try to read keyboard input immediately, with neither -getting enough of it to be useful. - -This mode also causes cmdtool to not implement many of the -terminal functions and control sequences appearing in the -`sun-cmd' termcap entry. For a more complete explanation, see -that file examples/suncmd.termcap in the bash distribution. - -`xterm' is a better choice, and gets along with bash much more -smoothly. - -17) How do I write a function `x' to replace builtin command `x', but - still invoke the command from within the function? - -This is what the `command' and `builtin' builtins are for. The -`command' builtin executes the command supplied as its first -argument, skipping over any function defined with that name. The -`builtin' builtin executes the builtin command given as its first -argument directly. - -For example, to write a function to replace `cd' that writes the -hostname and current directory to an xterm title bar, use -something like the following: - - cd() - { - builtin cd "$@" && xtitle $HOST: $PWD - } - -This could also be written using `command' instead of `builtin'; -the version above is marginally more efficient. - -18) When I have terminal escape sequences in my prompt, why does bash - wrap lines at the wrong column? - -Bash does not know that the terminal escape sequences do not take -up space on the screen. The redisplay code assumes, unless told -otherwise, that each character in the prompt is a `printable' -character that takes up one character position on the screen. - -You can use the bash prompt expansion facility (see the PROMPTING -section in the manual page) to tell readline that sequences of -characters in the prompt strings take up no screen space. - -Use the \[ escape to begin a sequence of non-printing characters, -and the \] escape to signal the end of such a sequence. - -19) I built bash on Solaris 2. Why do globbing expansions and filename - completion chop off the first few characters of each filename? - -This is the consequence of building bash on SunOS 5 and linking -with the libraries in /usr/ucblib, but using the definitions -and strutures from files in /usr/include. - -The actual conflict is between the dirent structure in -/usr/include/dirent.h and the struct returned by the version of -`readdir' in libucb.a (a 4.3-BSD style `struct direct'). - -Make sure you've got /usr/ccs/bin ahead of /usr/ucb in your $PATH -when building bash. This will ensure that you use /usr/ccs/bin/cc -or acc instead of /usr/ucb/cc and that you link with libc before -libucb. - -If you have installed the Sun C compiler, you may also need to -put /usr/ccs/bin and /opt/SUNWspro/bin into your $PATH before -/usr/ucb. - -20) Why doesn't bash treat brace expansions exactly like csh? - -The only difference between bash and csh brace expansion is that -bash requires a brace expression to contain at least on unquoted -comma if it is to be expanded. Any brace-surrounded word not -containing an unquoted comma is left unchanged by the brace -expansion code. This affords the greatest degree of sh -compatibility. - -Bash, ksh, zsh, and pd-ksh all implement brace expansion this way. - -21) Why does bash dump core after I interrupt username completion on a - machine running NIS? - -This is a famous and long-standing bug in the SunOS YP (sorry, NIS) -client library, which is part of libc. - -The YP library code keeps static state -- a pointer into the data -returned from the server. When YP initializes itself (setpwent), -it looks at this pointer and calls free on it if it's non-null. -So far, so good. - -If one of the YP functions is interrupted during getpwent (the -exact function is interpretwithsave()), and returns NULL, the -pointer is freed without being reset to NULL, and the function -returns. The next time getpwent is called, it sees that this -pointer is non-null, calls free, and the bash free() blows up -because it's being asked to free freed memory. - -The traditional Unix mallocs allow memory to be freed multiple -times; that's probably why this has never been fixed. You can -probably stop it by adding an #undef USE_GNU_MALLOC to the -appropriate machine description in machines.h. - -22) I'm running SVR4.2. Why is the line erased every time I type `@'? - -The `@' character is the default `line kill' character in most -versions of System V, including SVR4.2. You can change this -character to whatever you want using `stty'. For example, to -change the line kill character to control-u, type - - stty kill ^U - -where the `^' and `U' can be two separate characters. - -23) How can I find the value of a shell variable whose name is the value - of another shell variable? - -Use the `eval' builtin. The important thing to remember is that -`eval' expands the arguments you give it again, so you need to -quote the parts of the arguments that you want `eval' to act on. - -For example, this expression prints the value of the last positional -parameter: - - eval echo \$\{$#\} - -The expansion of the quoted portions of this expression will be -deferred until `eval' runs, while the `$#' will be expanded -before `eval' is executed. - -24) If I pipe the output of a command into `read variable', why doesn't - the output show up in $variable when the read command finishes? - -This has to do with the parent-child relationship between Unix -processes. - -Each element of a pipeline runs in a separate process, a child of -the shell running the pipeline. A subprocess cannot affect its -parent's environment. When the `read' command sets the variable -to the input, that variable is set only in the subshell, not the -parent shell. When the subshell exits, the value of the variable -is lost. - -Many pipelines that end with `read variable' can be converted -into command substitutions, which will capture the output into a -variable: - - grep ^gnu /usr/lib/news/active | wc -l | read ngroup - -can be converted into - - ngroup=$(grep ^gnu /usr/lib/news/active | wc -l) - -This does not, unfortunately, work to split the text among -multiple variables, as read does when given multiple variable -arguments. - -25) I just changed my shell to bash, and now I can't FTP into my machine. - Why not? - -You must add the full pathname to bash to the file /etc/shells. -Many versions of ftpd use this file to prohibit `special' users -such as `uucp' and `news' from using FTP. - -26) I have a bunch of shell scripts that use backslash-escaped characters - in arguments to `echo'. Bash doesn't interpret these characters. Why - not, and how can I make it understand them? - -This is the behavior of echo on most Unix System V machines. - -The bash builtin `echo' is modelled after the 9th Edition -Research Unix version of `echo'. It does not interpret -backslash-escaped characters in its argument strings by default, -but requires the use of the -e option to enable the -interpretation. The System V echo provides no way to disable the -special characters; the bash echo has a -E option to disable -them. - -There is a compile-time option that will make bash behave like -the System V echo and interpret things like \t by default. -Change config.h so that DEFAULT_ECHO_TO_USG is defined, remove -builtins/libbuiltins.a and builtins/echo.o, and rebuild. - -27) Why doesn't bash have csh variable modifiers? - -Posix has specified a more powerful, albeit somewhat more confusing, -mechanism cribbed from ksh, and bash implements it. - -${parameter%word} - Remove smallest suffix pattern. The WORD is expanded to produce - a pattern. It then expands to the value of PARAMETER, with the - smallest portion of the suffix matched by the pattern deleted. - - x=file.c - echo ${x%.c}.o - -->file.o - -${parameter%%word} - - Remove largest suffix pattern. The WORD is expanded to produce - a pattern. It then expands to the value of PARAMETER, with the - largest portion of the suffix matched by the pattern deleted. - - x=posix/src/std - echo ${x%%/*} - -->posix - -${parameter#word} - Remove smallest prefix pattern. The WORD is expanded to produce - a pattern. It then expands to the value of PARAMETER, with the - smallest portion of the prefix matched by the pattern deleted. - - x=$HOME/src/cmd - echo ${x#$HOME} - -->/src/cmd - -${parameter##word} - Remove largest prefix pattern. The WORD is expanded to produce - a pattern. It then expands to the value of PARAMETER, with the - largest portion of the prefix matched by the pattern deleted. - - x=/one/two/three - echo ${x##*/} - -->three - - -Given - a=/a/b/c/d - b=b.xxx - - csh bash result - --- ---- ------ - $a:h ${a%/*} /a/b/c - $a:t ${a##*/} d - $b:r ${b%.*} b - $b:e ${b##*.} xxx - - -28) Why does bash report syntax errors when my C News scripts use a - redirection before a subshell command? - -The actual command in question is something like - - < file ( command ) - -According to the grammar given in the Posix.2 standard, this construct -is, in fact, a syntax error. Redirections may only precede `simple -commands'. A subshell construct such as the above is one of the shell's -`compound commands'. A redirection may only follow a compound command. - -The file CWRU/sh-redir-hack in the 1.14.6 distribution is an (unofficial) -patch to parse.y that will modify the grammar to support this construct. -Note that if you apply this, you must recompile with -DREDIRECTION_HACK. -This introduces a large number of reduce/reduce conflicts into the shell -grammar. - -29) How do I report bugs in bash, and where should I look for fixes and - advice? - -Use the `bashbug' script to report bugs. It is built and -installed at the same time as bash. It provides a standard -template for reporting a problem and automatically includes -information about your configuration and build environment. - -`bashbug' sends its reports to bug-bash@prep.ai.mit.edu, which -is a large mailing list gatewayed to the usenet newsgroup gnu.bash.bug. - -Bug fixes, answers to questions, and announcements of new releases -are all posted to gnu.bash.bug. Discussions concerning bash features -and problems also take place there. - -To reach the bash maintainers directly, send mail to -bash-maintainers@prep.ai.mit.edu. - -30) What kind of bash documentation is there? - -First, look in the documentation directory in the bash distribution. -It should contain the following files: - -bash.1 an extensive, thorough Unix-style manual page -builtins.1 a manual page covering just bash builtin commands -features.texi a Gnu-style info file overview -FAQ this file -article.ms text of an article written for The Linux Journal -readline.3 a man page describing readline - -Postscript files created from the above source are also present in -the distribution. - -There is additional documentation available for anonymous FTP from host -slc2.ins.cwru.edu in the `pub/bash' directory. - -Cameron Newham is in the midst of writing a book on bash, to be -published by O'Reilly and Associates. Look for it sometime this -year. - -31) What's coming in future versions? - -There will be no new features in future releases of version 1.14. - -The next major release, bash-2.0, will contain extensive changes and new -features. Here's a short list: - -one-dimensional arrays with a new compound assignment statement, - appropriate expansion constructs and modifications to some - of the builtins (read, declare, etc.) to use them -new expansions to do ANSI-C string expansion, substring extraction, - pattern replacement, and indirect variable expansion -new builtins: `disown' and `shopt' -new variables: HISTIGNORE, SHELLOPTS, PIPESTATUS, DIRSTACK -special handling of many unused or redundant variables removed -dynamic loading of new builtin commands; many loadable examples provided -new prompt expansions: \e, \n, \H, \T -new readline variables: enable-keypad, mark-directories, input-meta -new readline commands to manipulate the mark and operate on the region -new readline emacs mode commands and bindings for ksh-88 compatibility -updated and extended builtins -new DEBUG trap -expanded (and now documented) restricted shell mode - -implementation stuff: -autoconf-based configuration -nearly all of the bugs reported since version 1.14 have been fixed -most builtins converted to use builtin `getopt' for consistency -most builtins use -p option to display output in a reusable form - (for consistency) -grammar tighter and smaller (66 reduce-reduce conflicts gone) -lots of code now smaller and faster -test suite greatly expanded - -32) What's on the bash `wish list'? - -internationalization with a variable expansion to translate a string - according to a particular message catalog -Programmable completion a la zsh -menu completion a la tcsh -the ksh egrep-style extended pattern matching operators -associative arrays (not really all that hard) -breaking some of the shell functionality into embeddable libraries -a bash debugger - -Much of this will not be in bash-2.0. - -33) When will the next release appear? - -Version 1.14.6 will probably be the last release for version 1.14. - -The next version will appear sometime in 1996. Never make predictions. - - -This document is copyright Chester Ramey, 1995. - -Permission is hereby granted, without written agreement and -without license or royalty fees, to use, copy, and distribute -this document for any purpose, provided that the above copyright -notice appears in all copies of this document and that the -contents of this document remain unaltered. diff --git a/documentation/Makefile b/documentation/Makefile deleted file mode 100644 index fb437eb..0000000 --- a/documentation/Makefile +++ /dev/null @@ -1,103 +0,0 @@ -# This Makefile is for the Bash/documentation directory -*- text -*-. -# -RM = rm -f - -INSTALL_DATA = ../support/install.sh -c -m 644 - -# unused -TEXINDEX = texindex -TEX = tex - -MAKEINFO = makeinfo -TEXI2DVI = ../support/texi2dvi -QUIETPS = #set this to -q to shut up dvips -DVIPS = dvips -D 300 $(QUIETPS) -o $@ # tricky -TEXINPUTS = ./../lib/readline/doc - -# Change to groff -Tascii if you don't have nroff -NROFF = nroff - -# This should be a program that converts troff to postscript -GROFF = groff - -HSUSER = ./../lib/readline/doc/hsuser.texinfo -RLUSER = ./../lib/readline/doc/rluser.texinfo - -.SUFFIXES: .1 .3 .ms .ps .txt .dvi - -.1.ps: - $(RM) $@ - ${GROFF} -man $< > $@ - -.1.txt: - $(RM) $@ - ${NROFF} -man $< > $@ - -.ms.ps: - $(RM) $@ - ${GROFF} -ms $< > $@ - -.ms.txt: - $(RM) $@ - ${NROFF} -ms $< > $@ - -.3.ps: - $(RM) $@ - ${GROFF} -man $< > $@ - -.3.txt: - $(RM) $@ - ${NROFF} -man $< > $@ - -all: ps info dvi text - -ps: bash.ps readline.ps article.ps -dvi: features.dvi features.ps -info: features.info -text: bash.txt builtins.txt readline.txt article.txt - -features.dvi: features.texi $(HSUSER) $(RLUSER) - TEXINPUTS=.:$(TEXINPUTS):$$TEXINPUTS $(TEXI2DVI) features.texi - -features.ps: features.dvi - $(RM) $@ - $(DVIPS) features.dvi - -features.info: features.texi $(HSUSER) $(RLUSER) - $(MAKEINFO) --no-split -I$(TEXINPUTS) features.texi - -bash.txt: bash.1 -bash.ps: bash.1 -builtins.txt: builtins.1 bash.1 -readline.txt: readline.3 -readline.ps: readline.3 -article.ps: article.ms - -hsuser.texinfo: ../lib/readline/doc/hsuser.texinfo - ln -s ../lib/readline/doc/hsuser.texinfo . - -rluser.texinfo: ../lib/readline/doc/rluser.texinfo - ln -s ../lib/readline/doc/rluser.texinfo . - -clean: - $(RM) *.aux *.cp *.fn *.ky *.log *.pg *.toc *.tp *.vr *.cps *.pgs \ - *.fns *.kys *.tps *.vrs *.o core rluser.texinfo hsuser.texinfo - -distclean mostlyclean: clean - -realclean maintainer-clean: clean - rm -f *.dvi *.info *.ps *.txt - -installdirs: - -[ -d $(mandir) ] || mkdir $(mandir) - -[ -d $(man3dir) ] || mkdir $(man3dir) - -[ -d $(infodir) ] || mkdir $(infodir) - -install: all installdirs - $(INSTALL_DATA) bash.1 $(mandir) - $(INSTALL_DATA) readline.3 $(man3dir) - $(INSTALL_DATA) features.info $(infodir)/bash.info - -uninstall: - $(RM) $(mandir)/bash.1 - $(RM) $(man3dir)/readline.3 $(infodir)/bash.info diff --git a/documentation/article.ps b/documentation/article.ps deleted file mode 100644 index 3cf5f39..0000000 --- a/documentation/article.ps +++ /dev/null @@ -1,1368 +0,0 @@ -%!PS-Adobe-3.0 -%%Creator: groff version 1.08 -%%DocumentNeededResources: font Times-Bold -%%+ font Times-Italic -%%+ font Times-Roman -%%+ font Courier -%%DocumentSuppliedResources: procset grops 1.08 0 -%%Pages: 11 -%%PageOrder: Ascend -%%Orientation: Portrait -%%EndComments -%%BeginProlog -%%BeginResource: procset grops 1.08 0 -/setpacking where{ -pop -currentpacking -true setpacking -}if -/grops 120 dict dup begin -/SC 32 def -/A/show load def -/B{0 SC 3 -1 roll widthshow}bind def -/C{0 exch ashow}bind def -/D{0 exch 0 SC 5 2 roll awidthshow}bind def -/E{0 rmoveto show}bind def -/F{0 rmoveto 0 SC 3 -1 roll widthshow}bind def -/G{0 rmoveto 0 exch ashow}bind def -/H{0 rmoveto 0 exch 0 SC 5 2 roll awidthshow}bind def -/I{0 exch rmoveto show}bind def -/J{0 exch rmoveto 0 SC 3 -1 roll widthshow}bind def -/K{0 exch rmoveto 0 exch ashow}bind def -/L{0 exch rmoveto 0 exch 0 SC 5 2 roll awidthshow}bind def -/M{rmoveto show}bind def -/N{rmoveto 0 SC 3 -1 roll widthshow}bind def -/O{rmoveto 0 exch ashow}bind def -/P{rmoveto 0 exch 0 SC 5 2 roll awidthshow}bind def -/Q{moveto show}bind def -/R{moveto 0 SC 3 -1 roll widthshow}bind def -/S{moveto 0 exch ashow}bind def -/T{moveto 0 exch 0 SC 5 2 roll awidthshow}bind def -/SF{ -findfont exch -[exch dup 0 exch 0 exch neg 0 0]makefont -dup setfont -[exch/setfont cvx]cvx bind def -}bind def -/MF{ -findfont -[5 2 roll -0 3 1 roll -neg 0 0]makefont -dup setfont -[exch/setfont cvx]cvx bind def -}bind def -/level0 0 def -/RES 0 def -/PL 0 def -/LS 0 def -/PLG{ -gsave newpath clippath pathbbox grestore -exch pop add exch pop -}bind def -/BP{ -/level0 save def -1 setlinecap -1 setlinejoin -72 RES div dup scale -LS{ -90 rotate -}{ -0 PL translate -}ifelse -1 -1 scale -}bind def -/EP{ -level0 restore -showpage -}bind def -/DA{ -newpath arcn stroke -}bind def -/SN{ -transform -.25 sub exch .25 sub exch -round .25 add exch round .25 add exch -itransform -}bind def -/DL{ -SN -moveto -SN -lineto stroke -}bind def -/DC{ -newpath 0 360 arc closepath -}bind def -/TM matrix def -/DE{ -TM currentmatrix pop -translate scale newpath 0 0 .5 0 360 arc closepath -TM setmatrix -}bind def -/RC/rcurveto load def -/RL/rlineto load def -/ST/stroke load def -/MT/moveto load def -/CL/closepath load def -/FL{ -currentgray exch setgray fill setgray -}bind def -/BL/fill load def -/LW/setlinewidth load def -/RE{ -findfont -dup maxlength 1 index/FontName known not{1 add}if dict begin -{ -1 index/FID ne{def}{pop pop}ifelse -}forall -/Encoding exch def -dup/FontName exch def -currentdict end definefont pop -}bind def -/DEFS 0 def -/EBEGIN{ -moveto -DEFS begin -}bind def -/EEND/end load def -/CNT 0 def -/level1 0 def -/PBEGIN{ -/level1 save def -translate -div 3 1 roll div exch scale -neg exch neg exch translate -0 setgray -0 setlinecap -1 setlinewidth -0 setlinejoin -10 setmiterlimit -[]0 setdash -/setstrokeadjust where{ -pop -false setstrokeadjust -}if -/setoverprint where{ -pop -false setoverprint -}if -newpath -/CNT countdictstack def -userdict begin -/showpage{}def -}bind def -/PEND{ -clear -countdictstack CNT sub{end}repeat -level1 restore -}bind def -end def -/setpacking where{ -pop -setpacking -}if -%%EndResource -%%IncludeResource: font Times-Bold -%%IncludeResource: font Times-Italic -%%IncludeResource: font Times-Roman -%%IncludeResource: font Courier -grops begin/DEFS 1 dict def DEFS begin/u{.001 mul}bind def end/RES 72 def/PL -792 def/LS false def/ENC0[/asciicircum/asciitilde/Scaron/Zcaron/scaron/zcaron -/Ydieresis/trademark/quotesingle/.notdef/.notdef/.notdef/.notdef/.notdef -/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef -/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/space -/exclam/quotedbl/numbersign/dollar/percent/ampersand/quoteright/parenleft -/parenright/asterisk/plus/comma/hyphen/period/slash/zero/one/two/three/four -/five/six/seven/eight/nine/colon/semicolon/less/equal/greater/question/at/A/B/C -/D/E/F/G/H/I/J/K/L/M/N/O/P/Q/R/S/T/U/V/W/X/Y/Z/bracketleft/backslash -/bracketright/circumflex/underscore/quoteleft/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q -/r/s/t/u/v/w/x/y/z/braceleft/bar/braceright/tilde/.notdef/quotesinglbase -/guillemotleft/guillemotright/bullet/florin/fraction/perthousand/dagger -/daggerdbl/endash/emdash/ff/fi/fl/ffi/ffl/dotlessi/dotlessj/grave/hungarumlaut -/dotaccent/breve/caron/ring/ogonek/quotedblleft/quotedblright/oe/lslash -/quotedblbase/OE/Lslash/.notdef/exclamdown/cent/sterling/currency/yen/brokenbar -/section/dieresis/copyright/ordfeminine/guilsinglleft/logicalnot/minus -/registered/macron/degree/plusminus/twosuperior/threesuperior/acute/mu -/paragraph/periodcentered/cedilla/onesuperior/ordmasculine/guilsinglright -/onequarter/onehalf/threequarters/questiondown/Agrave/Aacute/Acircumflex/Atilde -/Adieresis/Aring/AE/Ccedilla/Egrave/Eacute/Ecircumflex/Edieresis/Igrave/Iacute -/Icircumflex/Idieresis/Eth/Ntilde/Ograve/Oacute/Ocircumflex/Otilde/Odieresis -/multiply/Oslash/Ugrave/Uacute/Ucircumflex/Udieresis/Yacute/Thorn/germandbls -/agrave/aacute/acircumflex/atilde/adieresis/aring/ae/ccedilla/egrave/eacute -/ecircumflex/edieresis/igrave/iacute/icircumflex/idieresis/eth/ntilde/ograve -/oacute/ocircumflex/otilde/odieresis/divide/oslash/ugrave/uacute/ucircumflex -/udieresis/yacute/thorn/ydieresis]def/Courier@0 ENC0/Courier RE/Times-Roman@0 -ENC0/Times-Roman RE/Times-Italic@0 ENC0/Times-Italic RE/Times-Bold@0 ENC0 -/Times-Bold RE -%%EndProlog -%%Page: 1 1 -%%BeginPageSetup -BP -%%EndPageSetup -/F0 12/Times-Bold@0 SF(Bash \255 The GNU shell*)227.904 120 Q/F1 10 -/Times-Italic@0 SF(Chet Rame)263.85 144 Q(y)-.3 E(Case W)221.72 156 Q -(estern Reserve Univer)-.92 E(sity)-.1 E -.15(ch)250.425 168 S(et@po.cwru.edu) -.15 E/F2 10/Times-Bold@0 SF 2.5(1. Intr)72 234 R(oduction)-.18 E(Bash)97 249.6 -Q/F3 10/Times-Roman@0 SF .904(is the shell, or command language interpreter) -3.404 F 3.404(,t)-.4 G .904(hat will appear in the GNU operating system.) -316.032 249.6 R .91(The name is an acron)72 261.6 R .91(ym for the `)-.15 F -(`Bourne-Ag)-.74 E .91(ain SHell')-.05 F .911(', a pun on Ste)-.74 F 1.211 -.15 -(ve B)-.25 H .911(ourne, the author of the direct).15 F .212 -(ancestor of the current)72 273.6 R/F4 9/Times-Roman@0 SF(UNIX)2.712 E F3 2.712 -<8773>C(hell)199.131 273.6 Q F1(/bin/sh)2.712 E F3 2.712(,w)C .212 -(hich appeared in the Se)256.505 273.6 R -.15(ve)-.25 G .211 -(nth Edition Bell Labs Research v).15 F(er)-.15 E(-)-.2 E(sion of)72 285.6 Q F4 -(UNIX)2.5 E F3(.)A .387(Bash is an)97 301.2 R F2(sh)2.887 E F3 .387 -(\255compatible shell that incorporates useful features from the K)B .388 -(orn shell \()-.35 F F2(ksh)A F3 2.888(\)a)C .388(nd the C)469.334 301.2 R .023 -(shell \()72 313.2 R F2(csh)A F3 .023(\), described later in this article.)B -.022(It is ultimately intended to be a conformant implementation of the)5.022 F -3.568(IEEE POSIX Shell and Utilities speci\214cation \(IEEE W)72 325.2 R 3.568 -(orking Group 1003.2\).)-.8 F 3.569(It of)8.569 F 3.569(fers functional)-.25 F -(impro)72 337.2 Q -.15(ve)-.15 G(ments o).15 E -.15(ve)-.15 G 2.5(rs).15 G 2.5 -(hf)155.28 337.2 S(or both interacti)166.11 337.2 Q .3 -.15(ve a)-.25 H -(nd programming use.).15 E .697(While the GNU operating system will most lik)97 -352.8 R .697(ely include a v)-.1 F .697(ersion of the Berk)-.15 F(ele)-.1 E -3.197(ys)-.15 G .696(hell csh, Bash)446.778 352.8 R .015(will be the def)72 -364.8 R .015(ault shell.)-.1 F(Lik)5.015 E 2.515(eo)-.1 G .015(ther GNU softw) -199.1 364.8 R .016(are, Bash is quite portable.)-.1 F .016 -(It currently runs on nearly e)5.016 F -.15(ve)-.25 G(ry).15 E -.15(ve)72 376.8 -S .367(rsion of).15 F F4(UNIX)2.867 E F3 .367(and a fe)2.867 F 2.867(wo)-.25 G -.367(ther operating systems \255 an independently-supported port e)187.933 -376.8 R .366(xists for OS/2, and)-.15 F .706 -(there are rumors of ports to DOS and W)72 388.8 R(indo)-.4 E .706(ws NT)-.25 F -5.706(.P)-.74 G .706(orts to)295.97 388.8 R F4(UNIX)3.206 E F3(-lik)A 3.206(es) --.1 G .706(ystems such as QNX and Minix)372.979 388.8 R -(are part of the distrib)72 400.8 Q(ution.)-.2 E .405 -(The original author of Bash w)97 416.4 R .405(as Brian F)-.1 F .405 -(ox, an emplo)-.15 F .405(yee of the Free Softw)-.1 F .405(are F)-.1 F 2.905 -(oundation. The)-.15 F(cur)2.905 E(-)-.2 E(rent de)72 428.4 Q -.15(ve)-.25 G -(loper and maintainer is Chet Rame).15 E 1.3 -.65(y, a v)-.15 H(olunteer who w) -.45 E(orks at Case W)-.1 E(estern Reserv)-.8 E 2.5(eU)-.15 G(ni)458.91 428.4 Q --.15(ve)-.25 G(rsity).15 E(.)-.65 E F2 2.5(2. What')72 452.4 R 2.5(sP)-.37 G -(OSIX, anyway?)123.85 452.4 Q F1(POSIX)97 468 Q F3 .239 -(is a name originally coined by Richard Stallman for a f)4.405 F .239 -(amily of open system standards based)-.1 F(on)72 480 Q F4(UNIX)3.24 E F3 5.74 -(.T)C .74(here are a number of aspects of)122.081 480 R F4(UNIX)3.24 E F3 .74 -(under consideration for standardization, from the basic)3.24 F .192 -(system services at the system call and C library le)72 492 R -.15(ve)-.25 G -2.692(lt).15 G 2.692(oa)290.156 492 S .192 -(pplications and tools to system administration and)302.288 492 R 2.5 -(management. Each)72 504 R(area of standardization is assigned to a w)2.5 E -(orking group in the 1003 series.)-.1 E 2.814 -(The POSIX Shell and Utilities standard has been de)97 519.6 R -.15(ve)-.25 G -2.814(loped by IEEE W).15 F 2.813(orking Group 1003.2)-.8 F .254 -(\(POSIX.2\).\210 It concentrates on the command interpreter interf)72 531.6 R -.253(ace and utility programs commonly e)-.1 F -.15(xe)-.15 G(cuted).15 E 1.112 -(from the command line or by other programs.)72 543.6 R 1.112(An initial v) -6.112 F 1.113(ersion of the standard has been appro)-.15 F -.15(ve)-.15 G 3.613 -(da).15 G(nd)494 543.6 Q .365(published by the IEEE, and w)72 555.6 R .365 -(ork is currently underw)-.1 F .365(ay to update it.)-.1 F .365 -(There are four primary areas of w)5.365 F(ork)-.1 E(in the 1003.2 standard:)72 -567.6 Q 21.5<8341>72 583.2 S .835(spects of the shell')104.22 583.2 R 3.335(ss) --.55 G .835(yntax and command language.)192 583.2 R 3.335(An)5.835 G .835 -(umber of special b)338.095 583.2 R .835(uiltins such as)-.2 F F2(cd)3.335 E F3 -(and)3.335 E F2(exec)97 595.2 Q F3 .545(are being speci\214ed as part of the s\ -hell, since their functionality usually cannot be implemented)3.046 F -(by a separate e)97 607.2 Q -.15(xe)-.15 G(cutable;).15 E 21.5<8341>72 622.8 S -.73(set of utilities to be called by shell scripts and applications.)107.45 -622.8 R .731(Examples are programs lik)5.731 F(e)-.1 E F1 2.397(sed, tr)3.231 F -(,)-1.11 E F3(and)97 634.8 Q F1(awk.)2.853 E F3 .352 -(Utilities commonly implemented as shell b)4.519 F .352 -(uiltins are described in this section, such as)-.2 F F2(test)2.852 E F3(and)97 -646.8 Q F2(kill)3.422 E F3 5.922(.A)C 3.422(ne)144.404 646.8 S .922 -(xpansion of this section')157.116 646.8 R 3.423(ss)-.55 G .923 -(cope, termed the User Portability Extension, or UPE, has)268.586 646.8 R -(standardized interacti)97 658.8 Q .3 -.15(ve p)-.25 H(rograms such as).15 E F1 -(vi)2.5 E F3(and)4.166 E F1(mailx;)2.5 E .32 LW 76 668.8 72 668.8 DL 80 668.8 -76 668.8 DL 84 668.8 80 668.8 DL 88 668.8 84 668.8 DL 92 668.8 88 668.8 DL 96 -668.8 92 668.8 DL 100 668.8 96 668.8 DL 104 668.8 100 668.8 DL 108 668.8 104 -668.8 DL 112 668.8 108 668.8 DL 116 668.8 112 668.8 DL 120 668.8 116 668.8 DL -124 668.8 120 668.8 DL 128 668.8 124 668.8 DL 132 668.8 128 668.8 DL 136 668.8 -132 668.8 DL 140 668.8 136 668.8 DL 144 668.8 140 668.8 DL/F5 8/Times-Roman@0 -SF(*An earlier v)72 678.8 Q -(ersion of this article appeared in The Linux Journal.)-.12 E<87>72 688.8 Q/F6 -7/Times-Roman@0 SF(UNIX)2 E F5(is a trademark of Bell Laboratories.)2 E -(\210IEEE,)72 698.8 Q/F7 8/Times-Italic@0 SF .042(IEEE Standar)2.042 F 2.042 -(df)-.296 G .042(or Information T)150.046 698.8 R(ec)-.736 E(hnolo)-.12 E .042 -(gy -- P)-.08 F .042(ortable Oper)-.64 F .042 -(ating System Interface \(POSIX\) P)-.12 F .042(art 2: Shell and Utili-)-.64 F -(ties)72 708.8 Q F5 2(,1)C(992.)91.112 708.8 Q EP -%%Page: 2 2 -%%BeginPageSetup -BP -%%EndPageSetup -/F0 10/Times-Roman@0 SF 2.5(-2-)279.67 48 S 21.5<8341>72 84 S .288 -(group of functional interf)107.008 84 R .287(aces to services pro)-.1 F .287 -(vided by the shell, such as the traditional)-.15 F/F1 10/Courier@0 SF -(system\(\))2.787 E F0 3.289(Cl)97 96 S .789(ibrary function.)109.739 96 R .789 -(There are functions to perform shell w)5.789 F .789(ord e)-.1 F .79 -(xpansions, perform \214lename e)-.15 F(xpan-)-.15 E .324(sion \()97 108 R/F2 -10/Times-Italic@0 SF(globbing)A F0 .324(\), obtain v)B .323 -(alues of POSIX.2 system con\214guration v)-.25 F .323(ariables, retrie)-.25 F -.623 -.15(ve v)-.25 H .323(alues of en)-.1 F(viron-)-.4 E(ment v)97 120 Q -(ariables \()-.25 E F1(getenv\(\))A F0(\), and other services;).833 E 21.5 -<8341>72 135.6 S(suite of `)106.72 135.6 Q(`de)-.74 E -.15(ve)-.25 G(lopment') -.15 E 2.5('u)-.74 G(tilities such as)209.54 135.6 Q F2(c89)2.5 E F0 -(\(the POSIX.2 v)4.166 E(ersion of)-.15 E F2(cc)2.5 E F0(\), and)A F2(yacc.)2.5 -E F0 .483(Bash is concerned with the aspects of the shell')97 151.2 R 2.983(sb) --.55 G(eha)301.597 151.2 Q .484(vior de\214ned by POSIX.2.)-.2 F .484 -(The shell command)5.484 F 1.439 -(language has of course been standardized, including the basic \215o)72 163.2 R -3.938(wc)-.25 G 1.438(ontrol and program e)359.688 163.2 R -.15(xe)-.15 G 1.438 -(cution con-).15 F 1.145(structs, I/O redirection and pipelining, ar)72 175.2 R -1.145(gument handling, v)-.18 F 1.145(ariable e)-.25 F 1.146 -(xpansion, and quoting.)-.15 F(The)6.146 E F2(special)3.646 E F0 -.2(bu)72 -187.2 S .676(iltins, which must be implemented as part of the shell to pro).2 F -.676(vide the desired functionality)-.15 F 3.176(,a)-.65 G .676(re speci\214ed) -457.504 187.2 R .7(as being part of the shell; e)72 199.2 R .7 -(xamples of these are)-.15 F/F3 10/Times-Bold@0 SF -2.3 -.15(ev a)3.201 H(l).15 -E F0(and)3.201 E F3(export)3.201 E F0 5.701(.O)C .701 -(ther utilities appear in the sections of)352.034 199.2 R .256(POSIX.2 not de) -72 211.2 R -.2(vo)-.25 G .256(ted to the shell which are commonly \(and in som\ -e cases must be\) implemented as b).2 F(uiltin)-.2 E .213(commands, such as)72 -223.2 R F3 -.18(re)2.713 G(ad).18 E F0(and)2.713 E F3(test)2.713 E F0 5.213(.P) -C .213(OSIX.2 also speci\214es aspects of the shell')220.018 223.2 R 2.713(si) --.55 G(nteracti)398.159 223.2 Q .513 -.15(ve b)-.25 H(eha).15 E .214 -(vior as part)-.2 F .598 -(of the UPE, including job control and command line editing.)72 235.2 R .598 -(Interestingly enough, only)5.598 F F2(vi)3.098 E F0 .598(-style line edit-)B -(ing commands ha)72 247.2 Q .3 -.15(ve b)-.2 H(een standardized;).15 E F2 -(emacs)2.5 E F0(editing commands were left out due to objections.)2.5 E 1.128 -(While POSIX.2 includes much of what the shell has traditionally pro)97 262.8 R -1.129(vided, some important things)-.15 F(ha)72 274.8 Q .58 -.15(ve b)-.2 H .28 -(een omitted as being `).15 F(`be)-.74 E .28(yond its scope.)-.15 F 4.26 -.74 -('' T)-.7 H .28(here is, for instance, no mention of a dif).74 F .28 -(ference between)-.25 F(a)72 286.8 Q F2(lo)3.354 E(gin)-.1 E F0 .854 -(shell and an)5.02 F 3.354(yo)-.15 G .854(ther interacti)167.956 286.8 R 1.154 --.15(ve s)-.25 H .854(hell \(since POSIX.2 does not specify a login program\).) -.15 F .855(No \214x)5.855 F(ed)-.15 E -(startup \214les are de\214ned, either \255 the standard does not mention)72 -298.8 Q F2(.pr)2.5 E(o\214le)-.45 E F0(.)1.666 E F3 2.5(3. Basic)72 322.8 R -(Bash featur)2.5 E(es)-.18 E F0 1.448(Since the Bourne shell pro)97 338.4 R -1.448(vides Bash with most of its philosophical underpinnings, Bash inherits) --.15 F .64(most of its features and functionality from sh.)72 350.4 R .641 -(Bash implements all of the traditional sh \215o)5.641 F 3.141(wc)-.25 G .641 -(ontrol con-)459.199 350.4 R .8(structs \()72 362.4 R F2(for)A F0(,)A F2(if)3.3 -E F0(,)A F2(while)3.3 E F0 3.3(,e)C 3.3(tc.\). All)165.48 362.4 R .799 -(of the Bourne shell b)3.3 F .799 -(uiltins, including those not speci\214ed in the POSIX.2)-.2 F .536 -(standard, appear in Bash.)72 374.4 R(Shell)5.536 E F2(functions)3.036 E F0 -3.036(,i)C .536(ntroduced in the SVR2 v)248.536 374.4 R .537 -(ersion of the Bourne shell, are similar)-.15 F .779(to shell scripts, b)72 -386.4 R .779(ut are de\214ned using a special syntax and are e)-.2 F -.15(xe) --.15 G .779(cuted in the same process as the calling).15 F 2.841(shell. Bash)72 -398.4 R .341(has shell functions which beha)2.841 F .641 -.15(ve i)-.2 H 2.841 -(naf).15 G .341(ashion upw)278.759 398.4 R .342 -(ard-compatible with sh functions.)-.1 F .342(There are)5.342 F 1.447 -(certain shell v)72 410.4 R 1.446(ariables that Bash interprets in the same w) --.25 F 1.446(ay as sh, such as)-.1 F F3(PS1)3.946 E F0(,)A F3(IFS)3.946 E F0 -3.946(,a)C(nd)435.018 410.4 Q F3 -.74(PA)3.946 G(TH)-.21 E F0 6.446(.B)C(ash) -490.67 410.4 Q 1.423(implements essentially the same grammar)72 422.4 R 3.924 -(,p)-.4 G 1.424(arameter and v)256.476 422.4 R 1.424(ariable e)-.25 F 1.424 -(xpansion semantics, redirection, and)-.15 F 1.06(quoting as the Bourne shell.) -72 434.4 R 1.06(Where dif)6.06 F 1.06 -(ferences appear between the POSIX.2 standard and traditional sh)-.25 F(beha)72 -446.4 Q(vior)-.2 E 2.5(,B)-.4 G(ash follo)118.06 446.4 Q(ws POSIX.)-.25 E 1.608 -(The K)97 462 R 1.608(orn Shell \()-.35 F F3(ksh)A F0 4.108(\)i)C 4.108(sad) -194.192 462 S 1.608(escendent of the Bourne shell written at A)215.738 462 R -1.609(T&T Bell Laboratories by)-1.11 F(Da)72 474 Q 1.059(vid K)-.2 F 3.559 -(orn\207. It)-.35 F(pro)3.559 E 1.059 -(vides a number of useful features that POSIX and Bash ha)-.15 F 1.359 -.15 -(ve a)-.2 H 3.558(dopted. Man).15 F 3.558(yo)-.15 G 3.558(ft)484.892 474 S(he) -494.56 474 Q(interacti)72 486 Q 1.312 -.15(ve f)-.25 H 1.012 -(acilities in POSIX.2 ha).05 F 1.312 -.15(ve t)-.2 H 1.012 -(heir roots in the ksh: for e).15 F 1.013 -(xample, the POSIX and ksh job control)-.15 F -.1(fa)72 498 S .513 -(cilities are nearly identical. Bash includes features from the K).1 F .513 -(orn Shell for both interacti)-.35 F .813 -.15(ve u)-.25 H .513(se and shell) -.15 F 3.905(programming. F)72 510 R 1.405(or programming, Bash pro)-.15 F 1.405 -(vides v)-.15 F 1.405(ariables such as)-.25 F F3(RANDOM)3.905 E F0(and)3.905 E -F3(REPL)3.905 E(Y)-.92 E F0 3.905(,t)C(he)460.665 510 Q F3(typeset)3.905 E F0 --.2(bu)72 522 S .398(iltin, the ability to remo).2 F .698 -.15(ve s)-.15 H .398 -(ubstrings from v).15 F .398(ariables based on patterns, and shell arithmetic.) --.25 F F3(RANDOM)5.397 E F0 -.15(ex)72 534 S .489 -(pands to a random number each time it is referenced; assigning a v).15 F .49 -(alue to)-.25 F F3(RANDOM)2.99 E F0 .49(seeds the random)2.99 F .055 -(number generator)72 546 R(.)-.55 E F3(REPL)5.055 E(Y)-.92 E F0 .054 -(is the def)2.554 F .054(ault v)-.1 F .054(ariable used by the)-.25 F F3 -.18 -(re)2.554 G(ad).18 E F0 -.2(bu)2.554 G .054(iltin when no v).2 F .054 -(ariable names are sup-)-.25 F .742(plied as ar)72 558 R 3.243(guments. The) --.18 F F3(typeset)3.243 E F0 -.2(bu)3.243 G .743(iltin is used to de\214ne v).2 -F .743(ariables and gi)-.25 F 1.043 -.15(ve t)-.25 H .743(hem attrib).15 F .743 -(utes such as)-.2 F F3 -.18(re)3.243 G(ad-).18 E(only)72 570 Q F0 5.512(.B)C -.512(ash arithmetic allo)105.022 570 R .512(ws the e)-.25 F -.25(va)-.25 G .511 -(luation of an e).25 F .511(xpression and the substitution of the result.)-.15 -F .511(Shell v)5.511 F(ari-)-.25 E .222 -(ables may be used as operands, and the result of an e)72 582 R .222 -(xpression may be assigned to a v)-.15 F 2.722(ariable. Nearly)-.25 F .222 -(all of)2.722 F(the operators from the C language are a)72 594 Q -.25(va)-.2 G -(ilable, with the same precedence rules:).25 E F1 6($e)97 612 S -(cho $\(\(3 + 5 * 32\)\))115 612 Q(163)97 624 Q F0 -.15(Fo)72 645.6 S 3.24(ri) -.15 G(nteracti)91.76 645.6 Q 1.04 -.15(ve u)-.25 H .74 -(se, Bash implements ksh-style aliases and b).15 F .74(uiltins such as)-.2 F F3 -(fc)3.24 E F0 .74(\(discussed belo)3.24 F .74(w\) and)-.25 F F3(jobs)3.24 E F0 -(.)A .291(Bash aliases allo)72 657.6 R 2.791(was)-.25 G .291 -(tring to be substituted for a command name.)160.124 657.6 R(The)5.291 E 2.791 -(yc)-.15 G .291(an be used to create a mnemonic)371.733 657.6 R .568(for a)72 -669.6 R/F4 9/Times-Roman@0 SF(UNIX)3.068 E F0 .568(command name \()3.068 F F1 -.568(alias del=rm)B F0 .568(\), to e)B .567(xpand a single w)-.15 F .567 -(ord to a comple)-.1 F 3.067(xc)-.15 G .567(ommand \()432.603 669.6 R F1(alias) -A .255(news='xterm -g 80x45 -title trn -e trn -e -S1 -N &')72 681.6 R F0 .255 -(\), or to ensure that a command)B(is in)72 693.6 Q -.2(vo)-.4 G -.1(ke).2 G -2.5(dw).1 G(ith a basic set of options \()122.41 693.6 Q F1 -(alias ls="/bin/ls -F")A F0(\).)A .32 LW 76 703.6 72 703.6 DL 80 703.6 76 703.6 -DL 84 703.6 80 703.6 DL 88 703.6 84 703.6 DL 92 703.6 88 703.6 DL 96 703.6 92 -703.6 DL 100 703.6 96 703.6 DL 104 703.6 100 703.6 DL 108 703.6 104 703.6 DL -112 703.6 108 703.6 DL 116 703.6 112 703.6 DL 120 703.6 116 703.6 DL 124 703.6 -120 703.6 DL 128 703.6 124 703.6 DL 132 703.6 128 703.6 DL 136 703.6 132 703.6 -DL 140 703.6 136 703.6 DL 144 703.6 140 703.6 DL/F5 8/Times-Roman@0 SF -(\207Morris Bolsk)72 713.6 Q 2(ya)-.12 G(nd Da)127.88 713.6 Q(vid K)-.16 E -(orn,)-.28 E/F6 8/Times-Italic@0 SF(The K)2 E(ornShell Command and Pr)-.32 E --.08(og)-.36 G -.12(ra).08 G(mming Langua).12 E -.08(ge)-.08 G F5 2(,P).08 G -(rentice Hall, 1989.)363.064 713.6 Q EP -%%Page: 3 3 -%%BeginPageSetup -BP -%%EndPageSetup -/F0 10/Times-Roman@0 SF 2.5(-3-)279.67 48 S .293(The C shell \()97 84 R/F1 10 -/Times-Bold@0 SF(csh)A F0 .293(\)\207, originally written by Bill Jo)B 2.792 -(yw)-.1 G .292(hile at Berk)304.534 84 R(ele)-.1 E 1.592 -.65(y, i)-.15 H 2.792 -(sw).65 G .292(idely used and quite popular)389.512 84 R 1.252 -(for its interacti)72 96 R 1.552 -.15(ve f)-.25 H 3.752(acilities. Bash).05 F -1.253(includes a csh-compatible history e)3.752 F 1.253(xpansion mechanism \(`) --.15 F 1.253(`! history')-.74 F('\),)-.74 E .019(brace e)72 108 R .018 -(xpansion, access to a stack of directories via the)-.15 F F1(pushd)2.518 E F0 -(,)A F1(popd)2.518 E F0 2.518(,a)C(nd)357.31 108 Q F1(dirs)2.518 E F0 -.2(bu) -2.518 G .018(iltins, and tilde e).2 F(xpansion,)-.15 E 1.293 -(to generate users' home directories.)72 120 R -.35(Ti)6.294 G 1.294(lde e).35 -F 1.294(xpansion has also been adopted by both the K)-.15 F 1.294 -(orn Shell and)-.35 F(POSIX.2.)72 132 Q .148 -(There were certain areas in which POSIX.2 felt standardization w)97 147.6 R -.149(as necessary)-.1 F 2.649(,b)-.65 G .149(ut no e)420.643 147.6 R .149 -(xisting imple-)-.15 F 1.598(mentation pro)72 159.6 R 1.598 -(vided the proper beha)-.15 F(vior)-.2 E 6.598(.T)-.55 G 1.598(he w)251.56 -159.6 R 1.597(orking group in)-.1 F -.15(ve)-.4 G 1.597 -(nted and standardized functionality in).15 F .674 -(these areas, which Bash implements.)72 171.6 R(The)5.674 E F1(command)3.174 E -F0 -.2(bu)3.174 G .674(iltin w).2 F .674(as in)-.1 F -.15(ve)-.4 G .674 -(nted so that shell functions could be).15 F .996(written to replace b)72 183.6 -R .996(uiltins; it mak)-.2 F .996(es the capabilities of the b)-.1 F .995 -(uiltin a)-.2 F -.25(va)-.2 G .995(ilable to the function.).25 F .995 -(The reserv)5.995 F(ed)-.15 E -.1(wo)72 195.6 S 1.566(rd `).1 F(`!')-.74 E -4.066('w)-.74 G 1.566(as added to ne)122.872 195.6 R -.05(ga)-.15 G 1.567 -(te the return v).05 F 1.567(alue of a command or pipeline; it w)-.25 F 1.567 -(as nearly impossible to)-.1 F -.15(ex)72 207.6 S .089(press `).15 F .089 -(`if not x')-.74 F 2.589('c)-.74 G .089(leanly using the sh language.)152.366 -207.6 R .089(There e)5.089 F .088 -(xist multiple incompatible implementations of the)-.15 F F1(test)72 219.6 Q F0 --.2(bu)3.163 G .663(iltin, which tests \214les for type and other attrib).2 F -.664(utes and performs arithmetic and string comparisons.)-.2 F .5 -(POSIX considered none of these correct, so the standard beha)72 231.6 R .5 -(vior w)-.2 F .5(as speci\214ed in terms of the number of)-.1 F(ar)72 243.6 Q -.412(guments to the command.)-.18 F .412(POSIX.2 dictates e)5.412 F .412 -(xactly what will happen when four or fe)-.15 F .412(wer ar)-.25 F .412 -(guments are)-.18 F(gi)72 255.6 Q -.15(ve)-.25 G 5.01(nt).15 G(o)101.61 255.6 Q -F1(test)5.01 E F0 5.01(,a)C 2.51(nd lea)138.56 255.6 R -.15(ve)-.2 G 5.01(st) -.15 G 2.51(he beha)186 255.6 R 2.51(vior unde\214ned when more ar)-.2 F 2.51 -(guments are supplied.)-.18 F 2.51(Bash uses the)7.51 F -(POSIX.2 algorithm, which w)72 267.6 Q(as concei)-.1 E -.15(ve)-.25 G 2.5(db) -.15 G 2.5(yD)247.31 267.6 S -.2(av)262.03 267.6 S(id K).2 E(orn.)-.35 E F1 2.5 -(3.1. F)72 291.6 R(eatur)-.25 E(es not in the Bour)-.18 E(ne Shell)-.15 E F0 -.718(There are a number of minor dif)97 307.2 R .719 -(ferences between Bash and the v)-.25 F .719 -(ersion of sh present on most other)-.15 F -.15(ve)72 319.2 S .874(rsions of) -.15 F/F2 9/Times-Roman@0 SF(UNIX)3.374 E F0 5.873(.T)C .873 -(he majority of these are due to the POSIX standard, b)157.232 319.2 R .873 -(ut some are the result of Bash)-.2 F .188 -(adopting features from other shells.)72 331.2 R -.15(Fo)5.188 G 2.689(ri).15 G -.189(nstance, Bash includes the ne)239.069 331.2 R 2.689(w`)-.25 G(`!')369.554 -331.2 Q 2.689('r)-.74 G(eserv)388.153 331.2 Q .189(ed w)-.15 F .189(ord, the) --.1 F F1(command)2.689 E F0 -.2(bu)72 343.2 S .116(iltin, the ability of the).2 -F F1 -.18(re)2.616 G(ad).18 E F0 -.2(bu)2.615 G .115 -(iltin to correctly return a line ending with a backslash, symbolic ar).2 F -(guments)-.18 E .798(to the)72 355.2 R F1(umask)3.298 E F0 -.2(bu)3.298 G .798 -(iltin, v).2 F .798(ariable substring remo)-.25 F -.25(va)-.15 G .798(l, a w) -.25 F .799(ay to get the length of a v)-.1 F .799(ariable, and the ne)-.25 F -3.299(wa)-.25 G(lgo-)487.89 355.2 Q(rithm for the)72 367.2 Q F1(test)2.5 E F0 --.2(bu)2.5 G(iltin from the POSIX.2 standard, none of which appear in sh.).2 E -.998(Bash also implements the `)97 382.8 R(`$\(...\)')-.74 E 3.498('c)-.74 G -.998(ommand substitution syntax, which supersedes the sh `...` con-)244.93 -382.8 R 2.654(struct. The)72 394.8 R -.74(``)2.654 G($\(...\)').74 E 2.654('c) --.74 G .154(onstruct e)158.172 394.8 R .154 -(xpands to the output of the command contained within the parentheses, with) --.15 F .467(trailing ne)72 406.8 R .467(wlines remo)-.25 F -.15(ve)-.15 G 2.967 -(d. The).15 F .467(sh syntax is accepted for backw)2.967 F .467 -(ards compatibility)-.1 F 2.966(,b)-.65 G .466(ut the `)415.026 406.8 R -(`$\(...\)')-.74 E 2.966('f)-.74 G .466(orm is)478.254 406.8 R(preferred becau\ -se its quoting rules are much simpler and it is easier to nest.)72 418.8 Q .772 -(The Bourne shell does not pro)97 434.4 R .772(vide such features as brace e) --.15 F .772(xpansion, the ability to de\214ne a v)-.15 F(ariable)-.25 E .283 -(and a function with the same name, local v)72 446.4 R .282 -(ariables in shell functions, the ability to enable and disable indi-)-.25 F -.547(vidual b)72 458.4 R .547(uiltins or write a function to replace a b)-.2 F -.547(uiltin, or a means to e)-.2 F .547(xport a shell function to a child pro-) --.15 F(cess.)72 470.4 Q .32 -(Bash has closed a long-standing shell security hole by not using the)97 486 R -F1($IFS)2.82 E F0 -.25(va)2.82 G .32(riable to split each w).25 F(ord)-.1 E -1.254(read by the shell, b)72 498 R 1.254(ut splitting only the results of e) --.2 F 1.255(xpansion \(ksh and the 4.4 BSD sh ha)-.15 F 1.555 -.15(ve \214)-.2 -H -.15(xe).15 G 3.755(dt).15 G 1.255(his as)480.245 498 R 2.752(well\). Useful) -72 510 R(beha)2.751 E .251(vior such as a means to abort e)-.2 F -.15(xe)-.15 G -.251(cution of a script read with the `).15 F(`.)-.74 E 1.731 -.74('' c)-.7 H -.251(ommand using the).74 F F1 -.18(re)72 522 S(tur).18 E(n)-.15 E F0 -.2(bu) -2.742 G .242(iltin or automatically e).2 F .242(xporting v)-.15 F .243 -(ariables in the shell')-.25 F 2.743(se)-.55 G -.4(nv)336.842 522 S .243 -(ironment to children is also not present).4 F .969(in the Bourne shell.)72 534 -R .968(Bash pro)5.968 F .968(vides a much more po)-.15 F .968(werful en)-.25 F -.968(vironment for both interacti)-.4 F 1.268 -.15(ve u)-.25 H .968 -(se and pro-).15 F(gramming.)72 546 Q F1 2.5(4. Bash-speci\214c)72 570 R -.25 -(Fe)2.5 G(atur).25 E(es)-.18 E F0 .491(This section details a fe)97 585.6 R -2.991(wo)-.25 G 2.991(ft)208.355 585.6 S .491(he features which mak)217.456 -585.6 R 2.991(eB)-.1 G .491(ash unique.)323.18 585.6 R .492(Most of them pro) -5.491 F .492(vide impro)-.15 F -.15(ve)-.15 G(d).15 E(interacti)72 597.6 Q -1.182 -.15(ve u)-.25 H .882(se, b).15 F .882(ut a fe)-.2 F 3.382(wp)-.25 G .882 -(rogramming impro)183.31 597.6 R -.15(ve)-.15 G .882 -(ments are present as well.).15 F .882(Full descriptions of these fea-)5.882 F -(tures can be found in the Bash documentation.)72 609.6 Q F1 2.5(4.1. Startup) -72 633.6 R(Files)2.5 E F0 .161(Bash e)97 649.2 R -.15(xe)-.15 G .161 -(cutes startup \214les dif).15 F .161(ferently than other shells.)-.25 F .162 -(The Bash beha)5.161 F .162(vior is a compromise between)-.2 F .116 -(the csh principle of startup \214les with \214x)72 661.2 R .116(ed names e) --.15 F -.15(xe)-.15 G .116(cuted for each shell and the sh `).15 F -(`minimalist')-.74 E 2.615('b)-.74 G(eha)472.26 661.2 Q(vior)-.2 E(.)-.55 E -2.844(An interacti)72 673.2 R 3.144 -.15(ve i)-.25 H 2.844 -(nstance of Bash started as a login shell reads and e).15 F -.15(xe)-.15 G -(cutes).15 E/F3 10/Times-Italic@0 SF(~/.bash_pr)5.345 E(o\214le)-.45 E F0 2.845 -(\(the \214le)7.011 F .954(.bash_pro\214le in the user')72 685.2 R 3.454(sh) --.55 G .953(ome directory\), if it e)186.086 685.2 R 3.453(xists. An)-.15 F -(interacti)3.453 E 1.253 -.15(ve n)-.25 H .953(on-login shell reads and e).15 F --.15(xe)-.15 G(cutes).15 E .32 LW 76 695.2 72 695.2 DL 80 695.2 76 695.2 DL 84 -695.2 80 695.2 DL 88 695.2 84 695.2 DL 92 695.2 88 695.2 DL 96 695.2 92 695.2 -DL 100 695.2 96 695.2 DL 104 695.2 100 695.2 DL 108 695.2 104 695.2 DL 112 -695.2 108 695.2 DL 116 695.2 112 695.2 DL 120 695.2 116 695.2 DL 124 695.2 120 -695.2 DL 128 695.2 124 695.2 DL 132 695.2 128 695.2 DL 136 695.2 132 695.2 DL -140 695.2 136 695.2 DL 144 695.2 140 695.2 DL/F4 8/Times-Roman@0 SF .764 -(\207Bill Jo)72 705.2 R 1.804 -.52(y, A)-.08 H 2.764(nI).52 G .764 -(ntroduction to the C Shell,)121.252 705.2 R/F5 8/Times-Italic@0 SF .763 -(UNIX User')2.764 F 2.763(sS)-.32 G .763(upplementary Documents)260.942 705.2 R -F4 2.763(,U)C(ni)354.228 705.2 Q -.12(ve)-.2 G .763 -(rsity of California at Berk).12 F(ele)-.08 E -.52(y,)-.12 G(1986.)72 715.2 Q -EP -%%Page: 4 4 -%%BeginPageSetup -BP -%%EndPageSetup -/F0 10/Times-Roman@0 SF 2.5(-4-)279.67 48 S/F1 10/Times-Italic@0 SF(~/.bashr)72 -84 Q(c)-.37 E F0 5.537(.A)1.666 G(non-interacti)127.42 84 Q .837 -.15(ve s)-.25 -H .537(hell \(one be).15 F .538(gun to e)-.15 F -.15(xe)-.15 G .538 -(cute a shell script, for e).15 F .538(xample\) reads no \214x)-.15 F .538 -(ed startup)-.15 F .342(\214le, b)72 96 R .342(ut uses the v)-.2 F .342 -(alue of the v)-.25 F(ariable)-.25 E/F2 10/Times-Bold@0 SF($ENV)2.842 E F0 -2.841(,i)C 2.841(fs)260.187 96 S .341(et, as the name of a startup \214le.) -270.248 96 R .341(The ksh practice of read-)5.341 F(ing)72 108 Q F2($ENV)3.114 -E F0 .614(for e)3.114 F -.15(ve)-.25 G .614(ry shell, with the accompan).15 F -.615(ying dif)-.15 F .615(\214culty of de\214ning the proper v)-.25 F .615 -(ariables and functions)-.25 F .721(for interacti)72 120 R 1.021 -.15(ve a)-.25 -H .721(nd non-interacti).15 F 1.021 -.15(ve s)-.25 H .721(hells or ha).15 F -.721(ving the \214le read only for interacti)-.2 F 1.02 -.15(ve s)-.25 H .72 -(hells, w).15 F .72(as considered)-.1 F .158(too comple)72 132 R 2.658(x. Ease) --.15 F .158(of use w)2.658 F .158(on out here.)-.1 F(Interestingly)5.158 E -2.658(,t)-.65 G .158(he ne)295.822 132 R .159 -(xt release of ksh will change to reading)-.15 F F2($ENV)2.659 E F0 -(only for interacti)72 144 Q .3 -.15(ve s)-.25 H(hells.).15 E F2 2.5(4.2. New) -72 168 R(Builtin Commands)2.5 E F0 1.02(There are a fe)97 183.6 R 3.52(wb)-.25 -G 1.02(uiltins which are ne)170.59 183.6 R 3.52(wo)-.25 G 3.52(rh)267.74 183.6 -S -2.25 -.2(av e)279.59 183.6 T 1.02(been e)3.72 F 1.02(xtended in Bash.)-.15 F -(The)6.02 E F2(enable)3.52 E F0 -.2(bu)3.52 G 1.02(iltin allo).2 F(ws)-.25 E --.2(bu)72 195.6 S .736(iltin commands to be turned on and of).2 F 3.236(fa)-.25 -G(rbitrarily)250.198 195.6 Q 5.736(.T)-.65 G 3.237(ou)298.644 195.6 S .737 -(se the v)311.881 195.6 R .737(ersion of)-.15 F F1(ec)3.237 E(ho)-.15 E F0 .737 -(found in a user')4.903 F 3.237(ss)-.55 G(earch)482.35 195.6 Q .625 -(path rather than the Bash b)72 207.6 R(uiltin,)-.2 E/F3 10/Courier@0 SF .625 -(enable -n echo)3.125 F F0(suf)3.125 E 3.125(\214ces. The)-.25 F F2(help)3.124 -E F0 -.2(bu)3.124 G .624(iltin pro).2 F .624(vides quick synopses)-.15 F .703 -(of the shell f)72 219.6 R .704 -(acilities without requiring access to a manual page.)-.1 F F2(Builtin)5.704 E -F0 .704(is similar to)3.204 F F2(command)3.204 E F0 .704(in that it)3.204 F -.342(bypasses shell functions and directly e)72 231.6 R -.15(xe)-.15 G .342 -(cutes b).15 F .342(uiltin commands.)-.2 F .342 -(Access to a csh-style stack of directories)5.342 F .072(is pro)72 243.6 R .073 -(vided via the)-.15 F F2(pushd)2.573 E F0(,)A F2(popd)2.573 E F0 2.573(,a)C(nd) -211.197 243.6 Q F2(dirs)2.573 E F0 -.2(bu)2.573 G(iltins.).2 E F2(Pushd)5.073 E -F0(and)2.573 E F2(popd)2.573 E F0 .073(insert and remo)2.573 F .373 -.15(ve d) --.15 H .073(irectories from the).15 F 2.858(stack, respecti)72 255.6 R -.15(ve) --.25 G(ly).15 E 5.358(,a)-.65 G(nd)159.976 255.6 Q F2(dirs)5.358 E F0 2.858 -(lists the stack contents.)5.358 F 2.858(On systems that allo)7.858 F 5.358 -<778c>-.25 G 2.857(ne-grained control of)413.866 255.6 R 1.339(resources, the) -72 267.6 R F2(ulimit)3.839 E F0 -.2(bu)3.839 G 1.339 -(iltin can be used to tune these settings.).2 F F2(Ulimit)6.34 E F0(allo)3.84 E -1.34(ws a user to control, among)-.25 F 1.086 -(other things, whether core dumps are to be generated, ho)72 279.6 R 3.586(wm) --.25 G 1.086(uch memory the shell or a child process is)327.002 279.6 R(allo)72 -291.6 Q .496(wed to allocate, and ho)-.25 F 2.996(wl)-.25 G(ar)193.96 291.6 Q -.496(ge a \214le created by a child process can gro)-.18 F 4.296 -.65(w. T)-.25 -H(he).65 E F2(suspend)2.996 E F0 .497(command will)2.997 F .744 -(stop the shell process when job control is acti)72 303.6 R -.15(ve)-.25 G -3.243(;m).15 G .743(ost other shells do not allo)282.443 303.6 R 3.243(wt)-.25 -G(hemselv)404.431 303.6 Q .743(es to be stopped)-.15 F(lik)72 315.6 Q 2.717(et) --.1 G(hat.)92.397 315.6 Q F2 -.74(Ty)5.217 G(pe,).74 E F0 .217 -(the Bash answer to)2.717 F F2(which)2.717 E F0(and)2.717 E F2(whence,)2.717 E -F0(sho)2.717 E .218(ws what will happen when a w)-.25 F .218(ord is typed as a) --.1 F(command:)72 327.6 Q F3 6($t)97 345.6 S(ype export)115 345.6 Q -(export is a shell builtin)97 357.6 Q 6($t)97 369.6 S(ype -t export)115 369.6 Q -(builtin)97 381.6 Q 6($t)97 393.6 S(ype bash)115 393.6 Q(bash is /bin/bash)97 -405.6 Q 6($t)97 417.6 S(ype cd)115 417.6 Q(cd is a function)97 429.6 Q(cd \(\)) -97 441.6 Q({)97 453.6 Q(builtin cd ${1+"$@"} && xtitle $HOST: $PWD)121 465.6 Q -(})97 477.6 Q F0 -1.11(Va)72 499.2 S .682(rious modes tell what a command w) -1.11 F .681(ord is \(reserv)-.1 F .681(ed w)-.15 F .681 -(ord, alias, function, b)-.1 F .681(uiltin, or \214le\) or which v)-.2 F(er) --.15 E(-)-.2 E 1.15(sion of a command will be e)72 511.2 R -.15(xe)-.15 G 1.15 -(cuted based on a user').15 F 3.65(ss)-.55 G 1.15(earch path.)305.7 511.2 R -1.15(Some of this functionality has been)6.15 F -(adopted by POSIX.2 and folded into the)72 523.2 Q F2(command)2.5 E F0(utility) -2.5 E(.)-.65 E F2 2.5(4.3. Editing)72 547.2 R(and Completion)2.5 E F0 .584 -(One area in which Bash shines is command line editing.)97 562.8 R .584 -(Bash uses the)5.584 F F1 -.37(re)3.084 G(adline).37 E F0 .583 -(library to read and)4.749 F .942(edit lines when interacti)72 574.8 R -.15(ve) --.25 G 5.942(.R).15 G .942(eadline is a po)194.798 574.8 R .942 -(werful and \215e)-.25 F .942(xible input f)-.15 F .943 -(acility that a user can con\214gure to)-.1 F(indi)72 586.8 Q .732 -(vidual tastes.)-.25 F .732(It allo)5.732 F .732 -(ws lines to be edited using either emacs or vi commands, where those commands) --.25 F .2(are appropriate.)72 598.8 R .2 -(The full capability of emacs is not present \255 there is no w)5.2 F .2 -(ay to e)-.1 F -.15(xe)-.15 G .2(cute a named command).15 F 1.15 -(with M-x, for instance \255 b)72 610.8 R 1.15(ut the e)-.2 F 1.149 -(xisting commands are more than adequate.)-.15 F 1.149 -(The vi mode is compliant)6.149 F -(with the command line editing standardized by POSIX.2.)72 622.8 Q 1.69 -(Readline is fully customizable.)97 638.4 R 1.691 -(In addition to the basic commands and k)6.69 F 1.991 -.15(ey b)-.1 H 1.691 -(indings, the library).15 F(allo)72 650.4 Q .83 -(ws users to de\214ne additional k)-.25 F 1.13 -.15(ey b)-.1 H .83 -(indings using a startup \214le.).15 F(The)5.83 E F1(inputr)3.329 E(c)-.37 E F0 -.829(\214le, which def)4.995 F .829(aults to the)-.1 F(\214le)72 662.4 Q F1 -(~/.inputr)4.287 E(c)-.37 E F0 4.287(,i)1.666 G 4.287(sr)137.43 662.4 S 1.788(\ -ead each time readline initializes, permitting users to maintain a consistent \ -interf)148.937 662.4 R(ace)-.1 E .547(across a set of programs.)72 674.4 R .546 -(Readline includes an e)5.546 F .546(xtensible interf)-.15 F .546 -(ace, so each program using the library can)-.1 F .23(add its o)72 686.4 R .23 -(wn bindable commands and program-speci\214c k)-.25 F .531 -.15(ey b)-.1 H -2.731(indings. Bash).15 F .231(uses this f)2.731 F .231 -(acility to add bindings)-.1 F(that perform history e)72 698.4 Q -(xpansion or shell w)-.15 E(ord e)-.1 E(xpansions on the current input line.) --.15 E .707(Readline interprets a number of v)97 714 R .706 -(ariables which further tune its beha)-.25 F(vior)-.2 E 5.706(.V)-.55 G .706 -(ariables e)408.432 714 R .706(xist to control)-.15 F .157 -(whether or not eight-bit characters are directly read as input or con)72 726 R --.15(ve)-.4 G .158(rted to meta-pre\214x).15 F .158(ed k)-.15 F .458 -.15(ey s) --.1 H .158(equences \(a).15 F EP -%%Page: 5 5 -%%BeginPageSetup -BP -%%EndPageSetup -/F0 10/Times-Roman@0 SF 2.5(-5-)279.67 48 S(meta-pre\214x)72 84 Q 1.575(ed k) --.15 F 1.875 -.15(ey s)-.1 H 1.575 -(equence consists of the character with the eighth bit zeroed, preceded by the) -.15 F/F1 10/Times-Italic@0 SF(meta-)4.074 E(pr)72 96 Q(e\214x)-.37 E F0 -(character)4.45 E 2.784(,u)-.4 G .284 -(sually escape, which selects an alternate k)145.374 96 R -.15(ey)-.1 G .285 -(map\), to decide whether to output characters).15 F .485 -(with the eighth bit set directly or as a meta-pre\214x)72 108 R .485(ed k)-.15 -F .784 -.15(ey s)-.1 H .484(equence, whether or not to wrap to a ne).15 F 2.984 -(ws)-.25 G(creen)482.35 108 Q .157 -(line when a line being edited is longer than the screen width, the k)72 120 R --.15(ey)-.1 G .158(map to which subsequent k).15 F .458 -.15(ey b)-.1 H -(indings).15 E .531(should apply)72 132 R 3.031(,o)-.65 G 3.031(re)133.802 132 -S -.15(ve)144.353 132 S 3.031(nw).15 G .531(hat happens when readline w)168.894 -132 R .531(ants to ring the terminal')-.1 F 3.03(sb)-.55 G 3.03(ell. All)399.37 -132 R .53(of these v)3.03 F(ariables)-.25 E(can be set in the inputrc \214le.) -72 144 Q .284(The startup \214le understands a set of C preprocessor)97 159.6 R -(-lik)-.2 E 2.785(ec)-.1 G .285(onditional constructs which allo)329.49 159.6 R -2.785(wv)-.25 G(ariables)472.9 159.6 Q .12(or k)72 171.6 R .42 -.15(ey b)-.1 H -.119(indings to be assigned based on the application using readline, the termi\ -nal currently being used, or).15 F .338(the editing mode.)72 183.6 R .338 -(Users can add program-speci\214c bindings to mak)5.338 F 2.838(et)-.1 G .338 -(heir li)353.02 183.6 R -.15(ve)-.25 G 2.838(se).15 G 2.838(asier: I)397.176 -183.6 R(ha)2.838 E .639 -.15(ve b)-.2 H .339(indings that).15 F -(let me edit the v)72 195.6 Q(alue of)-.25 E/F2 10/Times-Bold@0 SF($P)2.5 E --.95(AT)-.74 G(H).95 E F0(and double-quote the current or pre)2.5 E(vious w) --.25 E(ord:)-.1 E/F3 10/Courier@0 SF 6(#M)97 213.6 S -(acros that are convenient for shell interaction)115 213.6 Q($if Bash)97 225.6 -Q 6(#e)97 237.6 S(dit the path)115 237.6 Q -("\\C-xp": "PATH=${PATH}\\e\\C-e\\C-a\\ef\\C-f")97 249.6 Q 6(#p)97 261.6 S -(repare to type a quoted word -- insert open and close double)115 261.6 Q 6(#q) -97 273.6 S(uotes and move to just after the open quote)115 273.6 Q -("\\C-x\\"": "\\"\\"\\C-b")97 285.6 Q 6(#Q)97 297.6 S -(uote the current or previous word)115 297.6 Q("\\C-xq": "\\eb\\"\\ef\\"")97 -309.6 Q($endif)97 321.6 Q F0 .322(There is a readline command to re-read the \ -\214le, so users can edit the \214le, change some bindings, and be)72 343.2 R -(gin)-.15 E(to use them almost immediately)72 355.2 Q(.)-.65 E .851 -(Bash implements the)97 370.8 R F2(bind)3.351 E F0 -.2(bu)3.351 G .851 -(iltin for more dyamic control of readline than the startup \214le permits.).2 -F F2(Bind)72 382.8 Q F0 .167(is used in se)2.667 F -.15(ve)-.25 G .167(ral w) -.15 F 2.667(ays. In)-.1 F F1(list)2.667 E F0 .167 -(mode, it can display the current k)4.333 F .466 -.15(ey b)-.1 H .166 -(indings, list all the readline edit-).15 F .149(ing directi)72 394.8 R -.15 -(ve)-.25 G 2.649(sa).15 G -.25(va)132.798 394.8 S .149 -(ilable for binding, list which k).25 F -.15(ey)-.1 G 2.649(si).15 G -1.9 -.4 -(nv o)282.352 394.8 T .349 -.1(ke a g).4 H -2.15 -.25(iv e).1 H 2.65(nd).25 G -(irecti)345.3 394.8 Q -.15(ve)-.25 G 2.65(,o).15 G 2.65(ro)385.04 394.8 S .15 -(utput the current set of k)396.02 394.8 R -.15(ey)-.1 G .526(bindings in a fo\ -rmat that can be incorporated directly into an inputrc \214le.)72 406.8 R(In) -5.526 E F1(batc)3.026 E(h)-.15 E F0 .526(mode, it reads a series)4.692 F .71 -(of k)72 418.8 R 1.01 -.15(ey b)-.1 H .71 -(indings directly from a \214le and passes them to readline.).15 F .71 -(In its most common usage,)5.71 F F2(bind)3.21 E F0(tak)3.21 E .71(es a)-.1 F -.534(single string and passes it directly to readline, which interprets the li\ -ne as if it had just been read from the)72 430.8 R(inputrc \214le.)72 442.8 Q -(Both k)5 E .3 -.15(ey b)-.1 H(indings and v).15 E -(ariable assignments may appear in the string gi)-.25 E -.15(ve)-.25 G 2.5(nt) -.15 G(o)427.74 442.8 Q F2(bind)2.5 E F0(.)A .401(The readline library also pro) -97 458.4 R .402(vides an interf)-.15 F .402(ace for)-.1 F F1(wor)2.902 E 2.902 -(dc)-.37 G(ompletion)328.546 458.4 Q F0 5.402(.W)C .402(hen the)385.888 458.4 R -F1(completion)2.902 E F0(character)4.568 E 1.261(\(usually T)72 470.4 R 1.261 -(AB\) is typed, readline looks at the w)-.93 F 1.26 -(ord currently being entered and computes the set of \214le-)-.1 F .523 -(names of which the current w)72 482.4 R .523(ord is a v)-.1 F .523 -(alid pre\214x.)-.25 F .524 -(If there is only one possible completion, the rest of the)5.523 F .358 -(characters are inserted directly)72 494.4 R 2.858(,o)-.65 G .358(therwise the\ - common pre\214x of the set of \214lenames is added to the current)205.232 -494.4 R -.1(wo)72 506.4 S 3.199(rd. A).1 F .699(second T)3.199 F .699(AB chara\ -cter entered immediately after a non-unique completion causes readline to list) --.93 F 1.814(the possible completions; there is an option to ha)72 518.4 R -2.113 -.15(ve t)-.2 H 1.813(he list displayed immediately).15 F 6.813(.R)-.65 G -1.813(eadline pro)436.517 518.4 R(vides)-.15 E .482 -(hooks so that applications can pro)72 530.4 R .482 -(vide speci\214c types of completion before the def)-.15 F .483 -(ault \214lename completion)-.1 F .132(is attempted.)72 542.4 R .132 -(This is quite \215e)5.132 F .132(xible, though it is not completely user)-.15 -F 2.632(-programmable. Bash,)-.2 F .132(for e)2.632 F .132(xample, can)-.15 F -.37(complete \214lenames, command names \(including aliases, b)72 554.4 R .37 -(uiltins, shell reserv)-.2 F .37(ed w)-.15 F .37(ords, shell functions, and)-.1 -F -.15(exe)72 566.4 S .424(cutables found in the \214le system\), shell v).15 F -.424(ariables, usernames, and hostnames.)-.25 F .423 -(It uses a set of heuristics)5.424 F(that, while not perfect, is generally qui\ -te good at determining what type of completion to attempt.)72 578.4 Q F2 2.5 -(4.4. History)72 602.4 R F0 .144(Access to the list of commands pre)97 618 R -.144(viously entered \(the)-.25 F F1 .144(command history)2.644 F F0 2.644(\)i) -C 2.644(sp)398.014 618 S(ro)409.548 618 Q .144(vided jointly by Bash)-.15 F -.078(and the readline library)72 630 R 5.077(.B)-.65 G .077(ash pro)178.861 630 -R .077(vides v)-.15 F .077(ariables \()-.25 F F2($HISTFILE)A F0(,)A F2 -($HISTSIZE)2.577 E F0 2.577(,a)C(nd)391.916 630 Q F2($HISTCONTR)2.577 E(OL)-.3 -E F0 2.577(\)a)C(nd)494 630 Q(the)72 642 Q F2(history)2.89 E F0(and)2.89 E F2 -(fc)2.89 E F0 -.2(bu)2.89 G .39(iltins to manipulate the history list.).2 F -.391(The v)5.391 F .391(alue of)-.25 F F2($HISTFILE)2.891 E F0 .391 -(specifes the \214le where)2.891 F .49(Bash writes the command history on e)72 -654 R .489(xit and reads it on startup.)-.15 F F2($HISTSIZE)5.489 E F0 .489 -(is used to limit the number)2.989 F .642(of commands sa)72 666 R -.15(ve)-.2 G -3.142(di).15 G 3.142(nt)158.286 666 S .642(he history)169.208 666 R(.)-.65 E F2 -($HISTCONTR)5.642 E(OL)-.3 E F0(pro)3.142 E .642 -(vides a crude form of control o)-.15 F -.15(ve)-.15 G 3.142(rw).15 G .642 -(hich com-)463.088 666 R .32(mands are sa)72 678 R -.15(ve)-.2 G 2.819(do).15 G -2.819(nt)146.199 678 S .319(he history list: a v)156.798 678 R .319(alue of) --.25 F F1(ignor)2.819 E(espace)-.37 E F0 .319(means to not sa)4.485 F .619 -.15 -(ve c)-.2 H .319(ommands which be).15 F .319(gin with)-.15 F 2.866(as)72 690 S -.366(pace; a v)83.196 690 R .366(alue of)-.25 F F1(ignor)2.866 E(edups)-.37 E -F0 .367(means to not sa)4.533 F .667 -.15(ve c)-.2 H .367 -(ommands identical to the last command sa).15 F -.15(ve)-.2 G(d.).15 E F2 -($HIST)5.367 E(-)-.92 E(CONTR)72 702 Q(OL)-.3 E F0 -.1(wa)3.778 G 3.778(sn).1 G -(amed)150.266 702 Q F2($history_contr)3.778 E(ol)-.18 E F0 1.278(in earlier v) -3.778 F 1.278(ersions of Bash; the old name is still accepted for)-.15 F(backw) -72 714 Q .575(ards compatibility)-.1 F 5.575(.T)-.65 G(he)184.61 714 Q F2 -(history)3.075 E F0 .575 -(command can read or write \214les containing the history list and dis-)3.075 F -.167(play the current list contents.)72 726 R(The)5.167 E F2(fc)2.667 E F0 -.2 -(bu)2.667 G .167(iltin, adopted from POSIX.2 and the K).2 F .167 -(orn Shell, allo)-.35 F .167(ws display and)-.25 F EP -%%Page: 6 6 -%%BeginPageSetup -BP -%%EndPageSetup -/F0 10/Times-Roman@0 SF 2.5(-6-)279.67 48 S(re-e)72 84 Q -.15(xe)-.15 G .58 -(cution, with optional editing, of commands from the history list.).15 F .58 -(The readline library of)5.58 F .58(fers a set of)-.25 F 1.255(commands to sea\ -rch the history list for a portion of the current input line or a string typed\ - by the user)72 96 R(.)-.55 E(Finally)72 108 Q 3.499(,t)-.65 G(he)108.469 108 Q -/F1 10/Times-Italic@0 SF(history)3.499 E F0(library)5.165 E 3.499(,g)-.65 G 1 -(enerally incorporated directly into the readline library)191.362 108 R 3.5(,i) --.65 G 1(mplements a f)420.44 108 R(acility)-.1 E .613(for history recall, e)72 -120 R .613(xpansion, and re-e)-.15 F -.15(xe)-.15 G .613(cution of pre).15 F -.613(vious commands v)-.25 F .613(ery similar to csh \(`)-.15 F .612 -(`bang history')-.74 F(',)-.74 E(so called because the e)72 132 Q -(xclamation point introduces a history substitution\):)-.15 E/F2 10/Courier@0 -SF 6($e)97 150 S(cho a b c d e)115 150 Q 6(abcde)97 162 S 6($!)97 174 S 6 -(!fghi)115 174 S(echo a b c d e f g h i)97 186 Q 6(abcdefghi)97 198 S 6($!)97 -210 S(-2)115 210 Q(echo a b c d e)97 222 Q 6(abcde)97 234 S 6($e)97 246 S -(cho !-2:1-4)115 246 Q(echo a b c d)97 258 Q 6(abcd)97 270 S F0 1.456 -(The command history is only sa)72 291.6 R -.15(ve)-.2 G 3.957(dw).15 G 1.457 -(hen the shell is interacti)232.599 291.6 R -.15(ve)-.25 G 3.957(,s).15 G 3.957 -(oi)352.804 291.6 S 3.957(ti)364.541 291.6 S 3.957(sn)374.058 291.6 S 1.457 -(ot a)386.905 291.6 R -.25(va)-.2 G 1.457(ilable for use by shell).25 F -(scripts.)72 303.6 Q/F3 10/Times-Bold@0 SF 2.5(4.5. New)72 327.6 R(Shell V)2.5 -E(ariables)-.92 E F0 .59(There are a number of con)97 343.2 R -.15(ve)-.4 G -.589(nience v).15 F .589(ariables that Bash interprets to mak)-.25 F 3.089(el) --.1 G .589(ife easier)403.093 343.2 R 5.589(.T)-.55 G .589(hese include)453.701 -343.2 R F3(FIGNORE)72 355.2 Q F0 3.973(,w)C 1.473 -(hich is a set of \214lename suf)132.363 355.2 R<8c78>-.25 E 1.474 -(es identifying \214les to e)-.15 F 1.474(xclude when completing \214lenames;) --.15 F F3(HOSTTYPE)72 367.2 Q F0 2.932(,w)C .432 -(hich is automatically set to a string describing the type of hardw)139.112 -367.2 R .431(are on which Bash is cur)-.1 F(-)-.2 E .335(rently e)72 379.2 R --.15(xe)-.15 G(cuting;).15 E F3(command_oriented_history)2.835 E F0 2.835(,w)C -.335(hich directs Bash to sa)272.685 379.2 R .635 -.15(ve a)-.2 H .336 -(ll lines of a multiple-line com-).15 F 1.071(mand such as a)72 391.2 R F1 -(while)3.571 E F0(or)3.571 E F1(for)3.571 E F0 1.071 -(loop in a single history entry)3.571 F 3.57(,a)-.65 G(llo)321.92 391.2 Q 1.07 -(wing easy re-editing; and)-.25 F F3(IGNOREEOF)3.57 E F0(,)A .747(whose v)72 -403.2 R .747(alue indicates the number of consecuti)-.25 F 1.047 -.15(ve E)-.25 -H .747(OF characters that an interacti).15 F 1.048 -.15(ve s)-.25 H .748 -(hell will read before).15 F -.15(ex)72 415.2 S 1.432(iting \255 an easy w).15 -F 1.432(ay to k)-.1 F 1.432(eep yourself from being logged out accidentally)-.1 -F 6.432(.T)-.65 G(he)399.926 415.2 Q F3(auto_r)3.932 E(esume)-.18 E F0 -.25(va) -3.932 G(riable).25 E .571(alters the w)72 427.2 R .571 -(ay the shell treats simple command names: if job control is acti)-.1 F -.15 -(ve)-.25 G 3.071(,a).15 G .571(nd this v)396.954 427.2 R .571 -(ariable is set, sin-)-.25 F(gle-w)72 439.2 Q .239(ord simple commands without\ - redirections cause the shell to \214rst look for and restart a suspended job) --.1 F(with that name before starting a ne)72 451.2 Q 2.5(wp)-.25 G(rocess.) -225.33 451.2 Q F3 2.5(4.6. Brace)72 475.2 R(Expansion)2.5 E F0 .653 -(Since sh of)97 490.8 R .653(fers no con)-.25 F -.15(ve)-.4 G .653(nient w).15 -F .653(ay to generate arbitrary strings that share a common pre\214x or suf)-.1 -F<8c78>-.25 E 2.124(\(\214lename e)72 502.8 R 2.124 -(xpansion requires that the \214lenames e)-.15 F 2.123(xist\), Bash implements) --.15 F F1(br)4.623 E 2.123(ace e)-.15 F(xpansion)-.2 E F0 4.623(,ac)C -(apability)469 502.8 Q(pick)72 514.8 Q .773(ed up from csh.)-.1 F .774(Brace e) -5.773 F .774(xpansion is similar to \214lename e)-.15 F .774(xpansion, b)-.15 F -.774(ut the strings generated need not)-.2 F 1.107(correspond to e)72 526.8 R -1.107(xisting \214les.)-.15 F 3.607(Ab)6.107 G 1.107(race e)207.655 526.8 R -1.107(xpression consists of an optional)-.15 F F1(pr)3.606 E(eamble)-.37 E F0 -3.606(,f)1.666 G(ollo)419.286 526.8 Q 1.106(wed by a pair of)-.25 F 2.809 -(braces enclosing a series of comma-separated strings, and an optional)72 538.8 -R F1(postamble)5.31 E F0 7.81(.T)1.666 G 2.81(he preamble is)440.06 538.8 R(pr\ -epended to each string within the braces, and the postamble is then appended t\ -o each resulting string:)72 550.8 Q F2 6($e)97 568.8 S(cho a{d,c,b}e)115 568.8 -Q(ade ace abe)97 580.8 Q F0 .306(As this e)72 602.4 R .306 -(xample demonstrates, the results of brace e)-.15 F .305 -(xpansion are not sorted, as the)-.15 F 2.805(ya)-.15 G .305 -(re by \214lename e)416.315 602.4 R(xpan-)-.15 E(sion.)72 614.4 Q F3 2.5 -(4.7. Pr)72 638.4 R(ocess Substitution)-.18 E F0 .457 -(On systems that can support it, Bash pro)97 654 R .457(vides a f)-.15 F .457 -(acility kno)-.1 F .458(wn as)-.25 F F1(pr)2.958 E .458(ocess substitution)-.45 -F F0 5.458(.P)C .458(rocess sub-)458.832 654 R .347(stitution is similar to co\ -mmand substitution in that its speci\214cation includes a command to e)72 666 R --.15(xe)-.15 G .346(cute, b).15 F .346(ut the)-.2 F .181 -(shell does not collect the command')72 678 R 2.681(so)-.55 G .181 -(utput and insert it into the command line.)228.076 678 R(Rather)5.181 E 2.681 -(,B)-.4 G .182(ash opens a pipe)437.635 678 R 1.763 -(to the command, which is run in the background.)72 690 R 1.763 -(The shell uses named pipes \(FIFOs\) or the)6.763 F F1(/de)4.263 E(v/fd)-.15 E -F0 .961(method of naming open \214les to e)72 702 R .962 -(xpand the process substitution to a \214lename which connects to the pipe)-.15 -F .104(when opened.)72 714 R .103(This \214lename becomes the result of the e) -5.104 F 2.603(xpansion. Process)-.15 F .103(substitution can be used to com-) -2.603 F(pare the outputs of tw)72 726 Q 2.5(od)-.1 G(if)171.61 726 Q(ferent v) --.25 E(ersions of an application as part of a re)-.15 E(gression test:)-.15 E -EP -%%Page: 7 7 -%%BeginPageSetup -BP -%%EndPageSetup -/F0 10/Times-Roman@0 SF 2.5(-7-)279.67 48 S/F1 10/Courier@0 SF 6($c)97 84 S -(mp <\(old_prog\) <\(new_prog\))115 84 Q/F2 10/Times-Bold@0 SF 2.5(4.8. Pr)72 -114 R(ompt Customization)-.18 E F0 2.229(One of the more popular interacti)97 -129.6 R 2.529 -.15(ve f)-.25 H 2.229(eatures that Bash pro).15 F 2.23 -(vides is the ability to customize the)-.15 F 3.234(prompt. Both)72 141.6 R F2 -($PS1)3.234 E F0(and)3.234 E F2($PS2,)3.234 E F0 .734 -(the primary and secondary prompts, are e)3.234 F .733 -(xpanded before being displayed.)-.15 F -.15(Pa)72 153.6 S .804(rameter and v) -.15 F .804(ariable e)-.25 F .805 -(xpansion is performed when the prompt string is e)-.15 F .805(xpanded, so an) --.15 F 3.305(ys)-.15 G .805(hell v)453.735 153.6 R(ariable)-.25 E .729 -(can be put into the prompt \(e.g.,)72 165.6 R F2($SHL)3.228 E(VL)-.92 E F0 -3.228(,w)C .728(hich indicates ho)258.568 165.6 R 3.228(wd)-.25 G .728 -(eeply the current shell is nested\).)342.992 165.6 R(Bash)5.728 E 1.895 -(specially interprets characters in the prompt string preceded by a backslash.) -72 177.6 R 1.895(Some of these backslash)6.895 F .874 -(escapes are replaced with the current time, the date, the current w)72 189.6 R -.874(orking directory)-.1 F 3.373(,t)-.65 G .873(he username, and the)416.961 -189.6 R .78(command number or history number of the command being entered.)72 -201.6 R .781(There is e)5.781 F -.15(ve)-.25 G 3.281(nab).15 G .781 -(ackslash escape to)429.128 201.6 R .007 -(cause the shell to change its prompt when running as root after an)72 213.6 R -/F3 10/Times-Italic@0 SF(su)2.507 E F0 5.007(.B)C .007 -(efore printing each primary prompt,)360.392 213.6 R .305(Bash e)72 225.6 R -.305(xpands the v)-.15 F(ariable)-.25 E F2($PR)2.805 E(OMPT_COMMAND)-.3 E F0 -.305(and, if it has a v)2.805 F .306(alue, e)-.25 F -.15(xe)-.15 G .306 -(cutes the e).15 F .306(xpanded v)-.15 F .306(alue as)-.25 F 3.735(ac)72 237.6 -S 1.235(ommand, allo)84.615 237.6 R 1.234 -(wing additional prompt customization.)-.25 F -.15(Fo)6.234 G 3.734(re).15 G -1.234(xample, this assignment causes the current)327.3 237.6 R(user)72 249.6 Q -2.917(,t)-.4 G .417 -(he current host, the time, the last component of the current w)96.457 249.6 R -.417(orking directory)-.1 F 2.917(,t)-.65 G .418(he le)417.188 249.6 R -.15(ve) --.25 G 2.918(lo).15 G 2.918(fs)456.504 249.6 S .418(hell nest-)466.642 249.6 R -(ing, and the history number of the current command to be embedded into the pr\ -imary prompt:)72 261.6 Q F1 6($P)97 279.6 S -(S1='\\u@\\h [\\t] \\W\($SHLVL:\\!\)\\$ ')115 279.6 Q -(chet@odin [21:03:44] documentation\(2:636\)$ cd ..)97 291.6 Q -(chet@odin [21:03:54] src\(2:637\)$)97 303.6 Q F0 .146 -(The string being assigned is surrounded by single quotes so that if it is e)72 -325.2 R .146(xported, the v)-.15 F .146(alue of)-.25 F F2($SHL)2.646 E(VL)-.92 -E F0(will)2.646 E(be updated by a child shell:)72 337.2 Q F1 -(chet@odin [21:17:35] src\(2:638\)$ export PS1)97 355.2 Q -(chet@odin [21:17:40] src\(2:639\)$ bash)97 367.2 Q -(chet@odin [21:17:46] src\(3:696\)$)97 379.2 Q F0 -(The \\$ escape is displayed as `)72 400.8 Q(`)-.74 E F2($)A F0 1.48 -.74('' w) -D(hen running as a normal user).74 E 2.5(,b)-.4 G(ut as `)342.08 400.8 Q(`)-.74 -E F2(#)A F0 1.48 -.74('' w)D(hen running as root.).74 E F2 2.5(4.9. File)72 -424.8 R(System V)2.5 E(iews)-.37 E F0 .029(Since Berk)97 440.4 R(ele)-.1 E -2.529(yi)-.15 G .029 -(ntroduced symbolic links in 4.2 BSD, one of their most anno)162.908 440.4 R -.03(ying properties has been)-.1 F 1.701(the `)72 452.4 R(`w)-.74 E(arping')-.1 -E 4.201('t)-.74 G 4.201(oac)139.912 452.4 S 1.701(ompletely dif)162.194 452.4 R -1.701(ferent area of the \214le system when using)-.25 F F2(cd)4.2 E F0 4.2(,a) -C 1.7(nd the resultant non-)416.41 452.4 R(intuiti)72 464.4 Q .658 -.15(ve b) --.25 H(eha).15 E .359(vior of `)-.2 F(`)-.74 E F2 .359(cd ..)B F0 -.74('')C -5.359(.T).74 G(he)200.304 464.4 Q/F4 9/Times-Roman@0 SF(UNIX)2.859 E F0 -.1(ke) -2.859 G .359(rnel treats symbolic links).1 F F3(physically)2.859 E F0 5.359(.W) -1.666 G .359(hen the k)411.574 464.4 R .359(ernel is trans-)-.1 F .401(lating \ -a pathname in which one component is a symbolic link, it replaces all or part \ -of the pathname while)72 476.4 R .946(processing the link.)72 488.4 R .946 -(If the contents of the symbolic link be)5.946 F .946(gin with a slash, the k) --.15 F .947(ernel replaces the path-)-.1 F .661 -(name entirely; if not, the link contents replace the current component.)72 -500.4 R .66(In either case, the symbolic link is)5.66 F 2.546(visible. If)72 -512.4 R .046(the link v)2.546 F .047 -(alue is an absolute pathname, the user \214nds himself in a completely dif) --.25 F .047(ferent part of the)-.25 F(\214le system.)72 524.4 Q .599(Bash pro) -97 540 R .599(vides a)-.15 F F3(lo)3.099 E(gical)-.1 E F0(vie)4.765 E 3.099(wo) --.25 G 3.099(ft)224.761 540 S .599(he \214le system.)233.97 540 R .599 -(In this def)5.599 F .599(ault mode, command and \214lename com-)-.1 F .522 -(pletion and b)72 552 R .522(uiltin commands such as)-.2 F F2(cd)3.022 E F0 -(and)3.022 E F2(pushd)3.022 E F0 .522(which change the current w)3.022 F .522 -(orking directory transpar)-.1 F(-)-.2 E .127(ently follo)72 564 R 2.627(ws) --.25 G .127(ymbolic links as if the)127.004 564 R 2.627(yw)-.15 G .127 -(ere directories.)231.099 564 R(The)5.126 E F2($PWD)2.626 E F0 -.25(va)2.626 G -.126(riable, which holds the shell').25 F 2.626(si)-.55 G .126(dea of)479.164 -564 R .366(the current w)72 576 R .366(orking directory)-.1 F 2.866(,d)-.65 G -.367(epends on the path used to reach the directory rather than its ph)200.184 -576 R .367(ysical loca-)-.05 F(tion in the local \214le system hierarch)72 588 -Q 3.8 -.65(y. F)-.05 H(or e).5 E(xample:)-.15 E F1 6($c)97 606 S 6(d/)115 606 S -(usr/local/bin)133 606 Q 6($e)97 618 S(cho $PWD)115 618 Q(/usr/local/bin)97 630 -Q 6($p)97 642 S(wd)115 642 Q(/usr/local/bin)97 654 Q 6($/)97 666 S(bin/pwd)115 -666 Q(/net/share/sun4/local/bin)97 678 Q 6($c)97 690 S 6(d.)115 690 S(.)133 690 -Q 6($p)97 702 S(wd)115 702 Q(/usr/local)97 714 Q 6($/)97 726 S(bin/pwd)115 726 -Q EP -%%Page: 8 8 -%%BeginPageSetup -BP -%%EndPageSetup -/F0 10/Times-Roman@0 SF 2.5(-8-)279.67 48 S/F1 10/Courier@0 SF -(/net/share/sun4/local)97 84 Q 6($c)97 96 S 6(d.)115 96 S(.)133 96 Q 6($p)97 -108 S(wd)115 108 Q(/usr)97 120 Q 6($/)97 132 S(bin/pwd)115 132 Q(/usr)97 144 Q -F0 .3(One problem with this, of course, arises when programs that do not under\ -stand the shell')72 165.6 R 2.8(sl)-.55 G .3(ogical notion of)440.07 165.6 R -.717(the \214le system interpret `)72 177.6 R(`..)-.74 E 2.197 -.74('' d)-.7 H -(if).74 E(ferently)-.25 E 5.717(.T)-.65 G .717 -(his generally happens when Bash completes \214lenames contain-)246.521 177.6 R -.977(ing `)72 189.6 R(`..)-.74 E 2.457 -.74('' a)-.7 H .977 -(ccording to a logical hierarch).74 F 3.476(yw)-.05 G .976 -(hich does not correspond to their ph)249.056 189.6 R .976(ysical location.) --.05 F -.15(Fo)5.976 G 3.476(ru).15 G(sers)488.45 189.6 Q -(who \214nd this troublesome, a corresponding)72 201.6 Q/F2 10/Times-Italic@0 -SF(physical)2.5 E F0(vie)4.166 E 2.5(wo)-.25 G 2.5(ft)312.006 201.6 S -(he \214le system is a)320.616 201.6 Q -.25(va)-.2 G(ilable:).25 E F1 6($c)97 -219.6 S 6(d/)115 219.6 S(usr/local/bin)133 219.6 Q 6($p)97 231.6 S(wd)115 231.6 -Q(/usr/local/bin)97 243.6 Q 6($s)97 255.6 S(et -o physical)115 255.6 Q 6($p)97 -267.6 S(wd)115 267.6 Q(/net/share/sun4/local/bin)97 279.6 Q/F3 10/Times-Bold@0 -SF 2.5(4.10. Inter)72 309.6 R(nationalization)-.15 E F0 .052 -(One of the most signi\214cant impro)97 325.2 R -.15(ve)-.15 G .052(ments in v) -.15 F .053(ersion 1.13 of Bash w)-.15 F .053(as the change to `)-.1 F .053 -(`eight-bit clean-)-.74 F(liness')72 337.2 Q 2.846('. Pre)-.74 F .346(vious v) --.25 F .345 -(ersions used the eighth bit of characters to mark whether or not the)-.15 F -2.845(yw)-.15 G .345(ere quoted when)437.22 337.2 R 1.495(performing w)72 349.2 -R 1.495(ord e)-.1 F 3.995(xpansions. While)-.15 F 1.495(this did not af)3.995 F -1.496(fect the majority of users, most of whom used only)-.25 F(se)72 361.2 Q --.15(ve)-.25 G 1.236(n-bit ASCII characters, some found it con\214ning.).15 F -(Be)6.236 E 1.236(ginning with v)-.15 F 1.236(ersion 1.13, Bash implemented a) --.15 F(dif)72 373.2 Q .02 -(ferent quoting mechanism that did not alter the eighth bit of characters.)-.25 -F .021(This allo)5.021 F .021(wed Bash to manipulate)-.25 F .263 -(\214les with `)72 385.2 R(`odd')-.74 E 2.763('c)-.74 G .262 -(haracters in their names, b)146.019 385.2 R .262 -(ut did nothing to help users enter those names, so v)-.2 F .262(ersion 1.13) --.15 F 1.458 -(introduced changes to readline that made it eight-bit clean as well.)72 397.2 -R 1.458(Options e)6.458 F 1.458(xist that force readline to)-.15 F .744(attach\ - no special signi\214cance to characters with the eighth bit set \(the def)72 -409.2 R .744(ault beha)-.1 F .744(vior is to con)-.2 F -.15(ve)-.4 G .744 -(rt these).15 F 1.88(characters to meta-pre\214x)72 421.2 R 1.88(ed k)-.15 F -2.18 -.15(ey s)-.1 H 1.88 -(equences\) and to output these characters without con).15 F -.15(ve)-.4 G 1.88 -(rsion to meta-).15 F(pre\214x)72 433.2 Q .582(ed sequences.)-.15 F .581 -(These changes, along with the e)5.582 F .581(xpansion of k)-.15 F -.15(ey)-.1 -G .581(maps to a full eight bits, enable read-).15 F(line to w)72 445.2 Q -(ork with most of the ISO-8859 f)-.1 E(amily of character sets, used by man)-.1 -E 2.5(yE)-.15 G(uropean countries.)394.94 445.2 Q F3 2.5(4.11. POSIX)72 469.2 R -(Mode)2.5 E F0 .584(Although Bash is intended to be POSIX.2 conformant, there \ -are areas in which the def)97 484.8 R .584(ault beha)-.1 F(vior)-.2 E .463 -(is not compatible with the standard.)72 496.8 R -.15(Fo)5.463 G 2.962(ru).15 G -.462(sers who wish to operate in a strict POSIX.2 en)244.25 496.8 R .462 -(vironment, Bash)-.4 F .505(implements a)72 508.8 R F2 .505(POSIX mode)3.005 F -F0 5.505(.W)C .505(hen this mode is acti)199 508.8 R -.15(ve)-.25 G 3.005(,B) -.15 G .505(ash modi\214es its def)304.455 508.8 R .505 -(ault operation where it dif)-.1 F(fers)-.25 E .267 -(from POSIX.2 to match the standard.)72 520.8 R .266 -(POSIX mode is entered when Bash is started with the)5.267 F F3(-posix)2.766 E -F0(option.)2.766 E .149(This feature is also a)72 532.8 R -.25(va)-.2 G .149 -(ilable as an option to the).25 F F3(set)2.649 E F0 -.2(bu)2.649 G(iltin,).2 E -F3 .149(set -o posix)2.649 F F0 5.149(.F)C .149 -(or compatibility with other GNU)371.744 532.8 R(softw)72 544.8 Q 4.02(are tha\ -t attempts to be POSIX.2 compliant, Bash also enters POSIX mode if the v)-.1 F -(ariable)-.25 E F3($POSIXL)72 556.8 Q(Y_CORRECT)-.92 E F0 5.824 -(is set when Bash is started or assigned a v)8.324 F 5.825(alue during e)-.25 F --.15(xe)-.15 G(cution.).15 E F3($POSIX_PED)72 568.8 Q(ANTIC)-.35 E F0 .27 -(is accepted as well, to be compatible with some older GNU utilities.)2.77 F -.27(When Bash is)5.27 F .428(started in POSIX mode, for e)72 580.8 R .428 -(xample, it sources the \214le named by the v)-.15 F .429(alue of)-.25 F F3 -($ENV)2.929 E F0 .429(rather than the `)2.929 F(`nor)-.74 E(-)-.2 E(mal')72 -592.8 Q 2.5('s)-.74 G(tartup \214les, and does not allo)99.31 592.8 Q 2.5(wr) --.25 G(eserv)227.66 592.8 Q(ed w)-.15 E(ords to be aliased.)-.1 E F3 2.5 -(5. New)72 616.8 R -.25(Fe)2.5 G(atur).25 E(es and Futur)-.18 E 2.5(eP)-.18 G -(lans)201.65 616.8 Q F0 1.632(There are se)97 632.4 R -.15(ve)-.25 G 1.632 -(ral features introduced in the current v).15 F 1.631(ersion of Bash, v)-.15 F -1.631(ersion 1.14, and a number)-.15 F .241 -(under consideration for future releases.)72 644.4 R .242 -(This section will brie\215y detail the ne)5.242 F 2.742(wf)-.25 G .242 -(eatures in v)395.702 644.4 R .242(ersion 1.14 and)-.15 F(describe se)72 656.4 -Q -.15(ve)-.25 G(ral features that may appear in later v).15 E(ersions.)-.15 E -F3 2.5(5.1. New)72 680.4 R -.25(Fe)2.5 G(atur).25 E(es in Bash-1.14)-.18 E F0 -.884(The ne)97 696 R 3.384(wf)-.25 G .884(eatures a)139.058 696 R -.25(va)-.2 G -.884(ilable in Bash-1.14 answer se).25 F -.15(ve)-.25 G .883 -(ral of the most common requests for enhance-).15 F 2.931(ments. Most)72 708 R -(notably)2.931 E 2.931(,t)-.65 G .432(here is a mechanism for including non-vi\ -sible character sequences in prompts, such)164.873 708 R 1.533 -(as those which cause a terminal to print characters in dif)72 720 R 1.532 -(ferent colors or in standout mode.)-.25 F 1.532(There w)6.532 F(as)-.1 E EP -%%Page: 9 9 -%%BeginPageSetup -BP -%%EndPageSetup -/F0 10/Times-Roman@0 SF 2.5(-9-)279.67 48 S 1.967(nothing pre)72 84 R -.15(ve) --.25 G 1.967(nting the use of these sequences in earlier v).15 F 1.967 -(ersions, b)-.15 F 1.967(ut the readline redisplay algorithm)-.2 F -(assumed each character occupied ph)72 96 Q(ysical screen space and w)-.05 E -(ould wrap lines prematurely)-.1 E(.)-.65 E .13(Readline has a fe)97 111.6 R -2.63(wn)-.25 G .63 -.25(ew va)180.58 111.6 T .13(riables, se).25 F -.15(ve)-.25 -G .13(ral ne).15 F 2.63(wb)-.25 G .13 -(indable commands, and some additional emacs mode)290.19 111.6 R(def)72 123.6 Q -.918(ault k)-.1 F 1.218 -.15(ey b)-.1 H 3.418(indings. A).15 F(ne)3.418 E 3.418 -(wh)-.25 G .919 -(istory search mode has been implemented: in this mode, readline searches) -199.03 123.6 R .336(the history for lines be)72 135.6 R .336 -(ginning with the characters between the be)-.15 F .336 -(ginning of the current line and the cursor)-.15 F(.)-.55 E .555(The e)72 147.6 -R .556(xisting readline incremental search commands no longer match identical \ -lines more than once.)-.15 F(File-)5.556 E 1.979(name completion no)72 159.6 R -4.479(we)-.25 G 1.979(xpands v)173.357 159.6 R 1.979 -(ariables in directory names.)-.25 F 1.978(The history e)6.978 F 1.978 -(xpansion f)-.15 F 1.978(acilities are no)-.1 F(w)-.25 E 1.449 -(nearly completely csh-compatible: missing modi\214ers ha)72 171.6 R 1.749 -.15 -(ve b)-.2 H 1.449(een added and history substitution has been).15 F -.15(ex)72 -183.6 S(tended.).15 E(Se)97 199.2 Q -.15(ve)-.25 G .474 -(ral of the features described earlier).15 F 2.973(,s)-.4 G .473(uch as)266.483 -199.2 R/F1 10/Times-Bold@0 SF .473(set -o posix)2.973 F F0(and)2.973 E F1 -($POSIX_PED)2.973 E(ANTIC)-.35 E F0 2.973(,a)C .473(re ne)466.094 199.2 R 2.973 -(wi)-.25 G(n)499 199.2 Q -.15(ve)72 211.2 S .106(rsion 1.14.).15 F .106 -(There is a ne)5.106 F 2.606(ws)-.25 G .106(hell v)194.156 211.2 R(ariable,) --.25 E F1(OSTYPE)2.606 E F0 2.606(,t)C 2.606(ow)296.724 211.2 S .106 -(hich Bash assigns a v)311.55 211.2 R .106(alue that identi\214es the v)-.25 F -(er)-.15 E(-)-.2 E 1.38(sion of)72 223.2 R/F2 9/Times-Roman@0 SF(UNIX)3.88 E F0 -(it')3.88 E 3.879(sr)-.55 G 1.379(unning on \(great for putting architecture-s\ -peci\214c binary directories into the)150.57 223.2 R F1($P)3.879 E -.95(AT)-.74 -G(H).95 E F0(\).)A -1 -.8(Tw o)72 235.2 T -.25(va)6.215 G 2.915(riables ha).25 -F 3.215 -.15(ve b)-.2 H 2.915(een renamed:).15 F F1($HISTCONTR)5.416 E(OL)-.3 E -F0(replaces)5.416 E F1($history_contr)5.416 E(ol)-.18 E F0 5.416(,a)C(nd) -432.454 235.2 Q F1($HOSTFILE)5.416 E F0(replaces)72 247.2 Q F1 -($hostname_completion_\214le)2.521 E F0 5.021(.I)C 2.521(nb)234.242 247.2 S -.021(oth cases, the old names are accepted for backw)246.763 247.2 R .02 -(ards compatibil-)-.1 F(ity)72 259.2 Q 5.676(.T)-.65 G .677(he ksh)96.196 259.2 -R/F3 10/Times-Italic@0 SF(select)3.177 E F0 .677(construct, which allo)4.843 F -.677(ws the generation of simple menus, has been implemented.)-.25 F(Ne)5.677 E -(w)-.25 E 2.892(capabilities ha)72 271.2 R 3.192 -.15(ve b)-.2 H 2.892 -(een added to e).15 F 2.892(xisting v)-.15 F(ariables:)-.25 E F1($auto_r)5.392 -E(esume)-.18 E F0 2.892(can no)5.392 F 5.392(wt)-.25 G(ak)404.13 271.2 Q 5.391 -(ev)-.1 G 2.891(alues of)428.051 271.2 R F3 -.2(ex)5.391 G(act).2 E F0(or)7.057 -E F3(substring)72 283.2 Q F0 3.278(,a)1.666 G(nd)121.114 283.2 Q F1($HISTCONTR) -3.278 E(OL)-.3 E F0 .778(understands the v)3.278 F(alue)-.25 E F3(ignor)3.278 E -(eboth)-.37 E F0 3.278(,w)1.666 G .778(hich combines the tw)366.248 283.2 R -3.278(op)-.1 G(re)467.03 283.2 Q(viously)-.25 E 1.556(acceptable v)72 295.2 R -4.056(alues. The)-.25 F F1(dirs)4.056 E F0 -.2(bu)4.056 G 1.556 -(iltin has acquired options to print out speci\214c members of the directory).2 -F 3.062(stack. The)72 307.2 R F1($nolinks)3.062 E F0 -.25(va)3.062 G .562 -(riable, which forces a ph).25 F .562(ysical vie)-.05 F 3.062(wo)-.25 G 3.062 -(ft)322.028 307.2 S .563(he \214le system, has been superseded by the)331.2 -307.2 R F172 319.2 Q F0 .494(option to the)2.994 F F1(set)2.994 E F0 -.2 -(bu)2.994 G .494(iltin \(equi).2 F -.25(va)-.25 G .494(lent to).25 F F1 .494 -(set -o ph)2.994 F(ysical)-.15 E F0 .493(\); the v)B .493 -(ariable is retained for backw)-.25 F .493(ards compati-)-.1 F(bility)72 331.2 -Q 5.196(.T)-.65 G .196(he v)106.276 331.2 R .196(ersion string contained in) --.15 F F1($B)2.696 E(ASH_VERSION)-.3 E F0(no)2.696 E 2.696(wi)-.25 G .196 -(ncludes an indication of the patch le)335.558 331.2 R -.15(ve)-.25 G 2.696(la) -.15 G(s)500.11 331.2 Q .665(well as the `)72 343.2 R(`b)-.74 E .665(uild v)-.2 -F(ersion')-.15 E 3.165('. Some)-.74 F .665(little-used features ha)3.165 F .965 --.15(ve b)-.2 H .665(een remo).15 F -.15(ve)-.15 G 3.165(d: the).15 F F1(by) -3.165 E(e)-.1 E F0(synon)3.165 E .665(ym for)-.15 F F1(exit)3.165 E F0(and) -3.165 E(the)72 355.2 Q F1($NO_PR)3.498 E(OMPT_V)-.3 E(ARS)-1.35 E F0 -.25(va) -3.498 G .998(riable are gone.).25 F .998(There is no)5.998 F 3.498(wa)-.25 G -3.498(no)331.114 355.2 S -2.19 -.18(rg a)344.612 355.2 T .998 -(nized test suite that can be run as a).18 F(re)72 367.2 Q -(gression test when b)-.15 E(uilding a ne)-.2 E 2.5(wv)-.25 G(ersion of Bash.) -222.34 367.2 Q 1.696(The documentation has been thoroughly o)97 382.8 R -.15 -(ve)-.15 G 1.696(rhauled: there is a ne).15 F 4.196(wm)-.25 G 1.695 -(anual page on the readline)392.25 382.8 R .467(library and the)72 394.8 R F3 -(info)2.967 E F0 .467(\214le has been updated to re\215ect the current v)2.967 -F 2.968(ersion. As)-.15 F(al)2.968 E -.1(wa)-.1 G .468(ys, as man).1 F 2.968 -(yb)-.15 G .468(ugs as possi-)451.954 394.8 R(ble ha)72 406.8 Q .3 -.15(ve b) --.2 H(een \214x).15 E(ed, although some surely remain.)-.15 E F1 2.5 -(5.2. Other)72 430.8 R -.25(Fe)2.5 G(atur).25 E(es)-.18 E F0 1.68 -(There are a fe)97 446.4 R 4.18(wf)-.25 G 1.68 -(eatures that I hope to include in later Bash releases.)171.76 446.4 R 1.68 -(Some are based on w)6.68 F(ork)-.1 E(already done in other shells.)72 458.4 Q -.958(In addition to simple v)97 474 R .959 -(ariables, a future release of Bash will include one-dimensional arrays, using) --.25 F .206(the ksh implementation of arrays as a model.)72 486 R .205 -(Additions to the ksh syntax, such as)5.205 F F3(varname)2.705 E F0 .205 -(=\( ... \) to assign)B 2.587(al)72 498 S .087(ist of w)81.807 498 R .088 -(ords directly to an array and a mechanism to allo)-.1 F 2.588(wt)-.25 G(he) -320.248 498 Q F1 -.18(re)2.588 G(ad).18 E F0 -.2(bu)2.588 G .088 -(iltin to read a list of v).2 F .088(alues directly)-.25 F .092(into an array) -72 510 R 2.592(,w)-.65 G .092(ould be desirable.)134.286 510 R(Gi)5.092 E -.15 -(ve)-.25 G 2.592(nt).15 G .092(hose e)239.794 510 R .092(xtensions, the ksh) --.15 F F1 .092(set \255A)2.592 F F0 .091(syntax may not be w)2.591 F .091 -(orth support-)-.1 F(ing \(the)72 522 Q F12.5 E F0 -(option assigns a list of v)2.5 E(alues to an array)-.25 E 2.5(,b)-.65 G -(ut is a rather peculiar special case\).)292.41 522 Q .76 -(Some shells include a means of)97 537.6 R F3(pr)3.26 E -.1(og)-.45 G -.15(ra) -.1 G(mmable).15 E F0 -.1(wo)3.26 G .76 -(rd completion, where the user speci\214es on a per).1 F(-)-.2 E .163 -(command basis ho)72 549.6 R 2.663(wt)-.25 G .163(he ar)159.179 549.6 R .163(g\ -uments of the command are to be treated when completion is attempted: as \214l\ -e-)-.18 F .194(names, hostnames, e)72 561.6 R -.15(xe)-.15 G .194 -(cutable \214les, and so on.).15 F .195 -(The other aspects of the current Bash implementation could)5.195 F .482 -(remain as-is; the e)72 573.6 R .482(xisting heuristics w)-.15 F .481 -(ould still be v)-.1 F 2.981(alid. Only)-.25 F .481(when completing the ar) -2.981 F .481(guments to a simple)-.18 F(command w)72 585.6 Q -(ould the programmable completion be in ef)-.1 E(fect.)-.25 E .479(It w)97 -601.2 R .479(ould also be nice to gi)-.1 F .779 -.15(ve t)-.25 H .479 -(he user \214ner).15 F .479(-grained control o)-.2 F -.15(ve)-.15 G 2.98(rw).15 -G .48(hich commands are sa)363.92 601.2 R -.15(ve)-.2 G 2.98(do).15 G .48 -(nto the)476.02 601.2 R 1.786(history list.)72 613.2 R 1.786 -(One proposal is for a v)6.786 F 1.786(ariable, tentati)-.25 F -.15(ve)-.25 G -1.786(ly named).15 F F1(HISTIGNORE)4.286 E F0 4.285(,w)C 1.785(hich w)415.145 -613.2 R 1.785(ould contain a)-.1 F .496(colon-separated list of commands.)72 -625.2 R .496(Lines be)5.496 F .496 -(ginning with these commands, after the restrictions of)-.15 F F1($HIST)2.997 E -(-)-.92 E(CONTR)72 637.2 Q(OL)-.3 E F0(ha)2.65 E .45 -.15(ve b)-.2 H .15 -(een applied, w).15 F .15(ould not be placed onto the history list.)-.1 F .15 -(The shell pattern-matching capa-)5.15 F(bilities could also be a)72 649.2 Q --.25(va)-.2 G(ilable when specifying the contents of).25 E F1($HISTIGNORE)2.5 E -F0(.)A .729(One thing that ne)97 664.8 R .729(wer shells such as)-.25 F F1 -(wksh)3.229 E F0 .729(\(also kno)3.229 F .729(wn as)-.25 F F1(dtksh)3.23 E F0 -3.23(\)p)C(ro)370.79 664.8 Q .73(vide is a command to dynami-)-.15 F 1.189 -(cally load code implementing additional b)72 676.8 R 1.189 -(uiltin commands into a running shell.)-.2 F 1.188(This ne)6.188 F 3.688(wb) --.25 G 1.188(uiltin w)454.292 676.8 R(ould)-.1 E(tak)72 688.8 Q 2.69(ea)-.1 G -2.69(no)95.69 688.8 S .19(bject \214le or shared library implementing the `) -108.38 688.8 R(`body')-.74 E 2.69('o)-.74 G 2.69(ft)327.83 688.8 S .19(he b) -336.63 688.8 R .19(uiltin \()-.2 F F3(xxx_b)A(uiltin\(\))-.2 E F0 .19 -(for those f)2.69 F(amiliar)-.1 E .052 -(with Bash internals\) and a structure containing the name of the ne)72 700.8 R -2.552(wc)-.25 G .051(ommand, the function to call when the)349.544 700.8 R(ne) -72 712.8 Q 3.458(wb)-.25 G .958(uiltin is in)96.668 712.8 R -.2(vo)-.4 G -.1 -(ke).2 G 3.458(d\().1 G .959 -(presumably de\214ned in the shared object speci\214ed as an ar)169.682 712.8 R -.959(gument\), and the docu-)-.18 F 1.352(mentation to be printed by the)72 -724.8 R F1(help)3.851 E F0 1.351 -(command \(possibly present in the shared object as well\).)3.851 F 1.351(It w) -6.351 F(ould)-.1 E EP -%%Page: 10 10 -%%BeginPageSetup -BP -%%EndPageSetup -/F0 10/Times-Roman@0 SF 2.5(-1)277.17 48 S 2.5(0-)288 48 S -(manage the details of e)72 84 Q(xtending the internal table of b)-.15 E -(uiltins.)-.2 E 3.291(Af)97 99.6 S 1.291 -.25(ew o)110.841 99.6 T .791(ther b) -.25 F .791(uiltins w)-.2 F .791(ould also be desirable: tw)-.1 F 3.291(oa)-.1 G -.791(re the POSIX.2)307.609 99.6 R/F1 10/Times-Bold@0 SF(getconf)3.292 E F0 -.792(command, which prints)3.292 F 1.412(the v)72 111.6 R 1.412 -(alues of system con\214guration v)-.25 F 1.411 -(ariables de\214ned by POSIX.2, and a)-.25 F F1(diso)3.911 E(wn)-.1 E F0 -.2 -(bu)3.911 G 1.411(iltin, which causes a).2 F 1.173 -(shell running with job control acti)72 123.6 R 1.473 -.15(ve t)-.25 H 3.673 -(o`).15 G(`for)240.45 123.6 Q 1.173(get about')-.18 F 3.673('o)-.74 G 1.173 -(ne or more background jobs in its internal jobs)307.966 123.6 R 3.465 -(table. Using)72 135.6 R F1(getconf)3.465 E F0 3.465(,f)C .965(or e)167.655 -135.6 R .965(xample, a user could retrie)-.15 F 1.264 -.15(ve a v)-.25 H .964 -(alue for)-.1 F F1($P)3.464 E -.95(AT)-.74 G(H).95 E F0 .964 -(guaranteed to \214nd all of the)3.464 F .884 -(POSIX standard utilities, or \214nd out ho)72 147.6 R 3.385(wl)-.25 G .885 -(ong \214lenames may be in the \214le system containing a speci\214ed)247.39 -147.6 R(directory)72 159.6 Q(.)-.65 E 1.521 -(There are no implementation timetables for an)97 175.2 R 4.021(yo)-.15 G 4.021 -(ft)305.517 175.2 S 1.52(hese features, nor are there concrete plans to)315.648 -175.2 R(include them.)72 187.2 Q(If an)5 E -(yone has comments on these proposals, feel free to send me electronic mail.) --.15 E F1 2.5(6. Re\215ections)72 211.2 R(and Lessons Lear)2.5 E(ned)-.15 E F0 -.433(The lesson that has been repeated most often during Bash de)97 226.8 R --.15(ve)-.25 G .433(lopment is that there are dark corners).15 F .093 -(in the Bourne Shell, and people use all of them.)72 238.8 R .092 -(In the original description of the Bourne shell, quoting and)5.093 F .073(the\ - shell grammar are both poorly speci\214ed and incomplete; subsequent descript\ -ions ha)72 250.8 R .373 -.15(ve n)-.2 H .073(ot helped much.).15 F 1.856 -(The grammar presented in Bourne')72 262.8 R 4.356(sp)-.55 G 1.856 -(aper describing the shell distrib)232.64 262.8 R 1.855(uted with the Se)-.2 F --.15(ve)-.25 G 1.855(nth Edition of).15 F/F2 9/Times-Roman@0 SF(UNIX)72 274.8 Q -F0 2.5<8769>C 2.5(ss)104.771 274.8 S 2.5(of)115.051 274.8 S(ar of)125.781 274.8 -Q 2.5(ft)-.25 G(hat it does not allo)152.741 274.8 Q 2.5(wt)-.25 G(he command) -238.881 274.8 Q/F3 10/Courier@0 SF(who|wc)2.5 E F0 5(.I)C 2.5(nf)339.591 274.8 -S(act, as T)350.321 274.8 Q(om Duf)-.8 E 2.5(fs)-.25 G(tates:)423.421 274.8 Q -1.375(Nobody really kno)97 290.4 R 1.375(ws what the Bourne shell')-.25 F 3.875 -(sg)-.55 G 1.375(rammar is.)296.635 290.4 R(Ev)6.376 E 1.376(en e)-.15 F 1.376 -(xamination of the source)-.15 F(code is little help.\210)97 302.4 Q .382 -(The POSIX.2 standard includes a)72 318 R/F4 10/Times-Italic@0 SF(yacc)2.882 E -F0 .382(grammar that comes close to capturing the Bourne shell')2.882 F 2.882 -(sb)-.55 G(eha)472.11 318 Q(vior)-.2 E(,)-.4 E -.2(bu)72 330 S 3.246(ti).2 G -3.246(td)90.606 330 S(isallo)101.632 330 Q .747(ws some constructs which sh ac\ -cepts without complaint \255 and there are scripts out there that)-.25 F .501 -(use them.)72 342 R .501(It took a fe)5.501 F 3.001(wv)-.25 G .501 -(ersions and se)176.256 342 R -.15(ve)-.25 G .501(ral b).15 F .5 -(ug reports before Bash implemented sh-compatible quoting,)-.2 F .094 -(and there are still some `)72 354 R(`le)-.74 E -.05(ga)-.15 G(l').05 E 2.594 -('s)-.74 G 2.594(hc)205.294 354 S .094 -(onstructs which Bash \215ags as syntax errors.)217.328 354 R .095 -(Complete sh compatibility)5.095 F(is a tough nut.)72 366 Q 1.231 -(The shell is bigger and slo)97 381.6 R 1.231(wer than I w)-.25 F 1.231 -(ould lik)-.1 F 1.23(e, though the current v)-.1 F 1.23 -(ersion is substantially f)-.15 F(aster)-.1 E .086(than pre)72 393.6 R(viously) --.25 E 5.086(.T)-.65 G .087(he readline library could stand a substantial re) -146.822 393.6 R 2.587(write. A)-.25 F .087(hand-written parser to replace the) -2.587 F(current)72 405.6 Q F4(yacc)2.978 E F0 .478(-generated one w)B .477 -(ould probably result in a speedup, and w)-.1 F .477(ould solv)-.1 F 2.977(eo) --.15 G .477(ne glaring problem:)406.469 405.6 R(the)5.477 E .199 -(shell could parse commands in `)72 417.6 R(`$\(...\)')-.74 E 2.699('c)-.74 G -.199(onstructs as the)236.954 417.6 R 2.699(ya)-.15 G .2 -(re entered, rather than reporting errors when the)311.001 417.6 R -(construct is e)72 429.6 Q(xpanded.)-.15 E 1.064(As al)97 445.2 R -.1(wa)-.1 G -1.064(ys, there is some chaf).1 F 3.564(ft)-.25 G 3.564(og)230.404 445.2 S -3.564(ow)243.968 445.2 S 1.064(ith the wheat.)259.752 445.2 R 1.063 -(Areas of duplicated functionality need to be)6.063 F .382(cleaned up.)72 457.2 -R .382(There are se)5.382 F -.15(ve)-.25 G .382 -(ral cases where Bash treats a v).15 F .382 -(ariable specially to enable functionality a)-.25 F -.25(va)-.2 G(ilable).25 E -.185(another w)72 469.2 R .185(ay \()-.1 F F1($notify)A F0(vs.)2.684 E F1 .184 -(set -o notify)5.184 F F0(and)2.684 E F1($nolinks)2.684 E F0(vs.)2.684 E F1 -.184(set -o ph)2.684 F(ysical)-.15 E F0 2.684(,f)C .184 -(or instance\); the special treatment)368.294 469.2 R 3.421(of the v)72 481.2 R -3.421(ariable name should probably be remo)-.25 F -.15(ve)-.15 G 5.921(d. A).15 -F(fe)5.921 E 5.921(wm)-.25 G 3.422(ore things could stand remo)346.47 481.2 R --.25(va)-.15 G 3.422(l; the).25 F F1($allo)72 493.2 Q(w_null_glob_expansion)-.1 -E F0(and)4.112 E F1($glob_dot_\214lenames)4.112 E F0 -.25(va)4.111 G 1.611 -(riables are of particularly questionable v).25 F(alue.)-.25 E(The)72 505.2 Q -F1($[...])3.977 E F0 1.477(arithmetic e)3.977 F -.25(va)-.25 G 1.478 -(luation syntax is redundant no).25 F 3.978(wt)-.25 G 1.478 -(hat the POSIX-mandated)312.76 505.2 R F1($\(\(...\)\))3.978 E F0 1.478 -(construct has)3.978 F .326(been implemented, and could be deleted.)72 517.2 R -.326(It w)5.326 F .326(ould be nice if the te)-.1 F .326(xt output by the)-.15 -F F1(help)2.825 E F0 -.2(bu)2.825 G .325(iltin were e).2 F(xter)-.15 E(-)-.2 E -.061(nal to the shell rather than compiled into it.)72 529.2 R .062(The beha) -5.062 F .062(vior enabled by)-.2 F F1($command_oriented_history)2.562 E F0 -2.562(,w)C(hich)486.78 529.2 Q 1.125(causes the shell to attempt to sa)72 541.2 -R 1.424 -.15(ve a)-.2 H 1.124 -(ll lines of a multi-line command in a single history entry).15 F 3.624(,s)-.65 -G 1.124(hould be)468.156 541.2 R(made the def)72 553.2 Q(ault and the v)-.1 E -(ariable remo)-.25 E -.15(ve)-.15 G(d.).15 E F1 2.5(7. A)72 577.2 R -.1(va)-1 G -(ilability).1 E F0 8.538(As with all other GNU softw)97 592.8 R 8.538 -(are, Bash is a)-.1 F -.25(va)-.2 G 8.539(ilable for anon).25 F 8.539 -(ymous FTP from)-.15 F F4(pr)72 604.8 Q(ep.ai.mit.edu:/pub/gnu)-.37 E F0 4.552 -(and from other GNU softw)8.718 F 4.552(are mirror sites.)-.1 F 4.552 -(The current v)9.552 F 4.552(ersion is in)-.15 F F4(bash-1.14.1.tar)72 616.8 Q -(.gz)-1.11 E F0 .074(in that directory)4.24 F 5.075(.U)-.65 G(se)226.084 616.8 -Q F4(ar)2.575 E -.15(ch)-.37 G(ie).15 E F0 .075(to \214nd the nearest archi) -4.241 F .375 -.15(ve s)-.25 H 2.575(ite. The).15 F .075(latest v)2.575 F .075 -(ersion is al)-.15 F -.1(wa)-.1 G(ys).1 E -.2(av)72 628.8 S 3.659 -(ailable for FTP from)-.05 F F4(bash.CWR)6.159 E -.25(U.)-.4 G(Edu:/pub/dist.) -.25 E F0 3.658(Bash documentation is a)7.825 F -.25(va)-.2 G 3.658 -(ilable for FTP from).25 F F4(bash.CWR)72 640.8 Q -.25(U.)-.4 G(Edu:/pub/bash.) -.25 E F0 1.168(The Free Softw)97 656.4 R 1.168(are F)-.1 F 1.168 -(oundation sells tapes and CD-R)-.15 F 1.169 -(OMs containing Bash; send electronic mail to)-.4 F F3(gnu@prep.ai.mit.edu)72 -668.4 Q F0(or call)2.5 E F3(+1-617-876-3296)2.5 E F0(for more information.)2.5 -E .32 LW 76 678.4 72 678.4 DL 80 678.4 76 678.4 DL 84 678.4 80 678.4 DL 88 -678.4 84 678.4 DL 92 678.4 88 678.4 DL 96 678.4 92 678.4 DL 100 678.4 96 678.4 -DL 104 678.4 100 678.4 DL 108 678.4 104 678.4 DL 112 678.4 108 678.4 DL 116 -678.4 112 678.4 DL 120 678.4 116 678.4 DL 124 678.4 120 678.4 DL 128 678.4 124 -678.4 DL 132 678.4 128 678.4 DL 136 678.4 132 678.4 DL 140 678.4 136 678.4 DL -144 678.4 140 678.4 DL/F5 8/Times-Roman@0 SF 1.39(\207S. R. Bourne, `)72 688.4 -R 1.389(`UNIX T)-.592 F 1.389(ime-Sharing System:)-.28 F 1.389(The UNIX Shell') -5.389 F(',)-.592 E/F6 8/Times-Italic@0 SF 1.389(Bell System T)3.389 F(ec)-.736 -E 1.389(hnical J)-.12 F(ournal)-.2 E F5 3.389(,5)C 1.389(7\(6\), July-August,) -408.171 688.4 R(1978, pp. 1971-1990.)72 698.4 Q<8854>72 708.4 Q .684(om Duf) --.64 F .684(f, `)-.2 F .684(`Rc \255 A Shell for Plan 9 and)-.592 F/F7 7 -/Times-Roman@0 SF(UNIX)2.684 E F5(systems')2.684 E(',)-.592 E F6(Pr)2.684 E -.684(oc. of the Summer 1990 EUUG Confer)-.36 F(ence)-.296 E F5 2.685(,L)C .685 -(ondon, July)428.499 708.4 R(,)-.52 E(1990, pp. 21-33.)72 718.4 Q EP -%%Page: 11 11 -%%BeginPageSetup -BP -%%EndPageSetup -/F0 10/Times-Roman@0 SF 2.5(-1)277.17 48 S 2.5(1-)288 48 S .695 -(Bash is also distrib)97 84 R .694(uted with se)-.2 F -.15(ve)-.25 G .694 -(ral v).15 F .694(ersions of)-.15 F/F1 9/Times-Roman@0 SF(UNIX)3.194 E F0 .694 -(-compatible systems.)B .694(It is included as /bin/sh)5.694 F .948 -(and /bin/bash on se)72 96 R -.15(ve)-.25 G .948(ral Linux distrib).15 F .948 -(utions \(more about the dif)-.2 F .948(ference in a moment\), and as contrib) --.25 F(uted)-.2 E(softw)72 108 Q(are in BSDI')-.1 E 2.5(sB)-.55 G -(SD/386* and FreeBSD.)157.73 108 Q .599(The Linux distrib)97 123.6 R .599 -(ution deserv)-.2 F .599(es special mention.)-.15 F .598(There are tw)5.599 F -3.098(oc)-.1 G .598(on\214gurations included in the stan-)364.948 123.6 R .547 -(dard Bash distrib)72 135.6 R .547(ution: a `)-.2 F(`normal')-.74 E 3.047('c) --.74 G .548 -(on\214guration, in which all of the standard features are included, and a) -222.755 135.6 R -.74(``)72 147.6 S(minimal').74 E 2.792('c)-.74 G .292(on\214g\ -uration, which omits job control, aliases, history and command line editing, t\ -he directory)124.412 147.6 R .747(stack and)72 159.6 R/F2 10/Times-Bold@0 SF -(pushd/popd/dirs,)3.247 E F0 .747 -(process substitution, prompt string special character decoding, and the)3.247 -F/F3 10/Times-Italic@0 SF(select)3.247 E F0 3.369(construct. This)72 171.6 R -.869(minimal v)3.369 F .869 -(ersion is designed to be a drop-in replacement for the traditional)-.15 F F1 -(UNIX)3.368 E F0(/bin/sh,)3.368 E(and is included as the Linux /bin/sh in se)72 -183.6 Q -.15(ve)-.25 G(ral packagings.).15 E F2 2.5(8. Conclusion)72 207.6 R F0 -.8(Bash is a w)97 223.2 R(orth)-.1 E 3.3(ys)-.05 G .8(uccessor to sh.)173.379 -223.2 R .8(It is suf)5.8 F .8(\214ciently portable to run on nearly e)-.25 F --.15(ve)-.25 G .8(ry v).15 F .8(ersion of)-.15 F F1(UNIX)3.3 E F0 .311 -(from 4.3 BSD to SVR4.2, and se)72 235.2 R -.15(ve)-.25 G(ral).15 E F1(UNIX) -2.811 E F0 -.1(wo)2.811 G(rkalik).1 E 2.811(es. It)-.1 F .31(is rob)2.81 F .31 -(ust enough to replace sh on most of those)-.2 F 1.515(systems, and pro)72 -247.2 R 1.515(vides more functionality)-.15 F 6.515(.I)-.65 G 4.015(th)254.315 -247.2 S 1.515(as se)266.11 247.2 R -.15(ve)-.25 G 1.515(ral thousand re).15 F -1.515(gular users, and their feedback has)-.15 F(helped to mak)72 259.2 Q 2.5 -(ei)-.1 G 2.5(ta)138.28 259.2 S 2.5(sg)148 259.2 S -(ood as it is today \255 a testament to the bene\214ts of free softw)159.39 -259.2 Q(are.)-.1 E .32 LW 76 698 72 698 DL 80 698 76 698 DL 84 698 80 698 DL 88 -698 84 698 DL 92 698 88 698 DL 96 698 92 698 DL 100 698 96 698 DL 104 698 100 -698 DL 108 698 104 698 DL 112 698 108 698 DL 116 698 112 698 DL 120 698 116 698 -DL 124 698 120 698 DL 128 698 124 698 DL 132 698 128 698 DL 136 698 132 698 DL -140 698 136 698 DL 144 698 140 698 DL/F4 8/Times-Roman@0 SF -(*BSD/386 is a trademark of Berk)72 708 Q(ele)-.08 E 2(yS)-.12 G(oftw)198.896 -708 Q(are Design, Inc.)-.08 E EP -%%Trailer -end -%%EOF diff --git a/documentation/article.txt b/documentation/article.txt deleted file mode 100644 index 38cd71f..0000000 --- a/documentation/article.txt +++ /dev/null @@ -1,1111 +0,0 @@ - - - - - - - - - - Bash - The GNU shell* - - - Chet Ramey - Case Western Reserve University - chet@po.cwru.edu - - - - - - -_1. _I_n_t_r_o_d_u_c_t_i_o_n - - _B_a_s_h is the shell, or command language interpreter, -that will appear in the GNU operating system. The name is -an acronym for the "Bourne-Again SHell", a pun on Steve -Bourne, the author of the direct ancestor of the current -UNIX|- shell /_b_i_n/_s_h, which appeared in the Seventh Edition -Bell Labs Research version of UNIX. - - Bash is an sh-compatible shell that incorporates useful -features from the Korn shell (ksh) and the C shell (csh), -described later in this article. It is ultimately intended -to be a conformant implementation of the IEEE POSIX Shell -and Utilities specification (IEEE Working Group 1003.2). It -offers functional improvements over sh for both interactive -and programming use. - - While the GNU operating system will most likely include -a version of the Berkeley shell csh, Bash will be the -default shell. Like other GNU software, Bash is quite port- -able. It currently runs on nearly every version of UNIX and -a few other operating systems - an independently-supported -port exists for OS/2, and there are rumors of ports to DOS -and Windows NT. Ports to UNIX-like systems such as QNX and -Minix are part of the distribution. - - The original author of Bash was Brian Fox, an employee -of the Free Software Foundation. The current developer and -maintainer is Chet Ramey, a volunteer who works at Case -Western Reserve University. - -_2. _W_h_a_t'_s _P_O_S_I_X, _a_n_y_w_a_y? - - _P_O_S_I_X is a name originally coined by Richard Stallman -_________________________ -*An earlier version of this article appeared in The -Linux Journal. -|- UNIX is a trademark of Bell Laboratories. - - - - - July 18, 1994 - - - - - - - 2 - - - -for a family of open system standards based on UNIX. There -are a number of aspects of UNIX under consideration for -standardization, from the basic system services at the sys- -tem call and C library level to applications and tools to -system administration and management. Each area of stan- -dardization is assigned to a working group in the 1003 -series. - - The POSIX Shell and Utilities standard has been -developed by IEEE Working Group 1003.2 (POSIX.2).|= It con- -centrates on the command interpreter interface and utility -programs commonly executed from the command line or by other -programs. An initial version of the standard has been -approved and published by the IEEE, and work is currently -underway to update it. There are four primary areas of work -in the 1003.2 standard: - -o+ Aspects of the shell's syntax and command language. A - number of special builtins such as _c_d and _e_x_e_c are - being specified as part of the shell, since their func- - tionality usually cannot be implemented by a separate - executable; - -o+ A set of utilities to be called by shell scripts and - applications. Examples are programs like _s_e_d, _t_r, and - _a_w_k. Utilities commonly implemented as shell builtins - are described in this section, such as _t_e_s_t and _k_i_l_l. - An expansion of this section's scope, termed the User - Portability Extension, or UPE, has standardized - interactive programs such as _v_i and _m_a_i_l_x; - -o+ A group of functional interfaces to services provided - by the shell, such as the traditional system() C - library function. There are functions to perform shell - word expansions, perform filename expansion (_g_l_o_b_b_i_n_g), - obtain values of POSIX.2 system configuration vari- - ables, retrieve values of environment variables - (getenv()), _a_n_d _o_t_h_e_r _s_e_r_v_i_c_e_s; - -o+ A suite of "development" utilities such as _c_8_9 (the - POSIX.2 version of _c_c), and _y_a_c_c. - - Bash is concerned with the aspects of the shell's -behavior defined by POSIX.2. The shell command language has -of course been standardized, including the basic flow con- -trol and program execution constructs, I/O redirection and -pipelining, argument handling, variable expansion, and quot- -ing. The _s_p_e_c_i_a_l builtins, which must be implemented as -part of the shell to provide the desired functionality, are -_________________________ -|=IEEE, _I_E_E_E _S_t_a_n_d_a_r_d _f_o_r _I_n_f_o_r_m_a_t_i_o_n _T_e_c_h_n_o_l_o_g_y -- -_P_o_r_t_a_b_l_e _O_p_e_r_a_t_i_n_g _S_y_s_t_e_m _I_n_t_e_r_f_a_c_e (_P_O_S_I_X) _P_a_r_t _2: -_S_h_e_l_l _a_n_d _U_t_i_l_i_t_i_e_s, 1992. - - - - - July 18, 1994 - - - - - - - 3 - - - -specified as being part of the shell; examples of these are -_e_v_a_l and _e_x_p_o_r_t. Other utilities appear in the sections of -POSIX.2 not devoted to the shell which are commonly (and in -some cases must be) implemented as builtin commands, such as -_r_e_a_d and _t_e_s_t. POSIX.2 also specifies aspects of the -shell's interactive behavior as part of the UPE, including -job control and command line editing. Interestingly enough, -only _v_i-style line editing commands have been standardized; -_e_m_a_c_s editing commands were left out due to objections. - - While POSIX.2 includes much of what the shell has trad- -itionally provided, some important things have been omitted -as being "beyond its scope." There is, for instance, no -mention of a difference between a _l_o_g_i_n shell and any other -interactive shell (since POSIX.2 does not specify a login -program). No fixed startup files are defined, either - the -standard does not mention ._p_r_o_f_i_l_e. - -_3. _B_a_s_i_c _B_a_s_h _f_e_a_t_u_r_e_s - - Since the Bourne shell provides Bash with most of its -philosophical underpinnings, Bash inherits most of its -features and functionality from sh. Bash implements all of -the traditional sh flow control constructs (_f_o_r, _i_f, _w_h_i_l_e, -etc.). All of the Bourne shell builtins, including those -not specified in the POSIX.2 standard, appear in Bash. -Shell _f_u_n_c_t_i_o_n_s, introduced in the SVR2 version of the -Bourne shell, are similar to shell scripts, but are defined -using a special syntax and are executed in the same process -as the calling shell. Bash has shell functions which behave -in a fashion upward-compatible with sh functions. There are -certain shell variables that Bash interprets in the same way -as sh, such as _P_S_1, _I_F_S, and _P_A_T_H. Bash implements essen- -tially the same grammar, parameter and variable expansion -semantics, redirection, and quoting as the Bourne shell. -Where differences appear between the POSIX.2 standard and -traditional sh behavior, Bash follows POSIX. - - The Korn Shell (ksh) is a descendent of the Bourne -shell written at AT&T Bell Laboratories by David Korn|-. It -provides a number of useful features that POSIX and Bash -have adopted. Many of the interactive facilities in POSIX.2 -have their roots in the ksh: for example, the POSIX and ksh -job control facilities are nearly identical. Bash includes -features from the Korn Shell for both interactive use and -shell programming. For programming, Bash provides variables -such as _R_A_N_D_O_M and _R_E_P_L_Y, the _t_y_p_e_s_e_t builtin, the ability -to remove substrings from variables based on patterns, and -shell arithmetic. _R_A_N_D_O_M expands to a random number each -time it is referenced; assigning a value to _R_A_N_D_O_M seeds the -_________________________ -|-Morris Bolsky and David Korn, _T_h_e _K_o_r_n_S_h_e_l_l _C_o_m_m_a_n_d -_a_n_d _P_r_o_g_r_a_m_m_i_n_g _L_a_n_g_u_a_g_e, Prentice Hall, 1989. - - - - - July 18, 1994 - - - - - - - 4 - - - -random number generator. _R_E_P_L_Y is the default variable used -by the _r_e_a_d builtin when no variable names are supplied as -arguments. The _t_y_p_e_s_e_t builtin is used to define variables -and give them attributes such as readonly. Bash arithmetic -allows the evaluation of an expression and the substitution -of the result. Shell variables may be used as operands, and -the result of an expression may be assigned to a variable. -Nearly all of the operators from the C language are avail- -able, with the same precedence rules: -9 $ echo $((3 + 5 * 32)) - 163 -9 -For interactive use, Bash implements ksh-style aliases and -builtins such as _f_c (discussed below) and _j_o_b_s. Bash -aliases allow a string to be substituted for a command name. -They can be used to create a mnemonic for a UNIX command -name (alias del=rm), to expand a single word to a complex -command (alias news='xterm -g 80x45 -title trn -e trn -e -S1 --N &'), or to ensure that a command is invoked with a basic -set of options (alias ls="/bin/ls -F"). - - The C shell (csh)|-, originally written by Bill Joy -while at Berkeley, is widely used and quite popular for its -interactive facilities. Bash includes a csh-compatible his- -tory expansion mechanism ("! history"), brace expansion, -access to a stack of directories via the _p_u_s_h_d, _p_o_p_d, and -_d_i_r_s builtins, and tilde expansion, to generate users' home -directories. Tilde expansion has also been adopted by both -the Korn Shell and POSIX.2. - - There were certain areas in which POSIX.2 felt stan- -dardization was necessary, but no existing implementation -provided the proper behavior. The working group invented -and standardized functionality in these areas, which Bash -implements. The _c_o_m_m_a_n_d builtin was invented so that shell -functions could be written to replace builtins; it makes the -capabilities of the builtin available to the function. The -reserved word "!" was added to negate the return value of a -command or pipeline; it was nearly impossible to express "if -not x" cleanly using the sh language. There exist multiple -incompatible implementations of the _t_e_s_t builtin, which -tests files for type and other attributes and performs -arithmetic and string comparisons. POSIX considered none of -these correct, so the standard behavior was specified in -terms of the number of arguments to the command. POSIX.2 -dictates exactly what will happen when four or fewer argu- -ments are given to _t_e_s_t, and leaves the behavior undefined -when more arguments are supplied. Bash uses the POSIX.2 -_________________________ -|-Bill Joy, An Introduction to the C Shell, _U_N_I_X _U_s_e_r'_s -_S_u_p_p_l_e_m_e_n_t_a_r_y _D_o_c_u_m_e_n_t_s, University of California at -Berkeley, 1986. - - - - - July 18, 1994 - - - - - - - 5 - - - -algorithm, which was conceived by David Korn. - -_3._1. _F_e_a_t_u_r_e_s _n_o_t _i_n _t_h_e _B_o_u_r_n_e _S_h_e_l_l - - There are a number of minor differences between Bash -and the version of sh present on most other versions of -UNIX. The majority of these are due to the POSIX standard, -but some are the result of Bash adopting features from other -shells. For instance, Bash includes the new "!" reserved -word, the _c_o_m_m_a_n_d builtin, the ability of the _r_e_a_d builtin -to correctly return a line ending with a backslash, symbolic -arguments to the _u_m_a_s_k builtin, variable substring removal, -a way to get the length of a variable, and the new algorithm -for the _t_e_s_t builtin from the POSIX.2 standard, none of -which appear in sh. - - Bash also implements the "$(...)" command substitution -syntax, which supersedes the sh `...` construct. The -"$(...)" construct expands to the output of the command con- -tained within the parentheses, with trailing newlines -removed. The sh syntax is accepted for backwards compati- -bility, but the "$(...)" form is preferred because its quot- -ing rules are much simpler and it is easier to nest. - - The Bourne shell does not provide such features as -brace expansion, the ability to define a variable and a -function with the same name, local variables in shell func- -tions, the ability to enable and disable individual builtins -or write a function to replace a builtin, or a means to -export a shell function to a child process. - - Bash has closed a long-standing shell security hole by -not using the $_I_F_S variable to split each word read by the -shell, but splitting only the results of expansion (ksh and -the 4.4 BSD sh have fixed this as well). Useful behavior -such as a means to abort execution of a script read with the -"." command using the return builtin or automatically -exporting variables in the shell's environment to children -is also not present in the Bourne shell. Bash provides a -much more powerful environment for both interactive use and -programming. - -_4. _B_a_s_h-_s_p_e_c_i_f_i_c _F_e_a_t_u_r_e_s - - This section details a few of the features which make -Bash unique. Most of them provide improved interactive use, -but a few programming improvements are present as well. -Full descriptions of these features can be found in the Bash -documentation. - -_4._1. _S_t_a_r_t_u_p _F_i_l_e_s - - Bash executes startup files differently than other -shells. The Bash behavior is a compromise between the csh - - - - July 18, 1994 - - - - - - - 6 - - - -principle of startup files with fixed names executed for -each shell and the sh "minimalist" behavior. An interactive -instance of Bash started as a login shell reads and executes -~/._b_a_s_h__p_r_o_f_i_l_e (the file .bash_profile in the user's home -directory), if it exists. An interactive non-login shell -reads and executes ~/._b_a_s_h_r_c. A non-interactive shell (one -begun to execute a shell script, for example) reads no fixed -startup file, but uses the value of the variable $_E_N_V, if -set, as the name of a startup file. The ksh practice of -reading $_E_N_V for every shell, with the accompanying diffi- -culty of defining the proper variables and functions for -interactive and non-interactive shells or having the file -read only for interactive shells, was considered too com- -plex. Ease of use won out here. Interestingly, the next -release of ksh will change to reading $_E_N_V only for interac- -tive shells. - -_4._2. _N_e_w _B_u_i_l_t_i_n _C_o_m_m_a_n_d_s - - There are a few builtins which are new or have been -extended in Bash. The _e_n_a_b_l_e builtin allows builtin com- -mands to be turned on and off arbitrarily. To use the ver- -sion of _e_c_h_o found in a user's search path rather than the -Bash builtin, enable -n echo suffices. The _h_e_l_p builtin -provides quick synopses of the shell facilities without -requiring access to a manual page. _B_u_i_l_t_i_n is similar to -_c_o_m_m_a_n_d in that it bypasses shell functions and directly -executes builtin commands. Access to a csh-style stack of -directories is provided via the _p_u_s_h_d, _p_o_p_d, and _d_i_r_s buil- -tins. _P_u_s_h_d and _p_o_p_d insert and remove directories from the -stack, respectively, and _d_i_r_s lists the stack contents. On -systems that allow fine-grained control of resources, the -_u_l_i_m_i_t builtin can be used to tune these settings. _U_l_i_m_i_t -allows a user to control, among other things, whether core -dumps are to be generated, how much memory the shell or a -child process is allowed to allocate, and how large a file -created by a child process can grow. The _s_u_s_p_e_n_d command -will stop the shell process when job control is active; most -other shells do not allow themselves to be stopped like -that. _T_y_p_e, the Bash answer to _w_h_i_c_h and _w_h_e_n_c_e, shows what -will happen when a word is typed as a command: -9 $ type export - export is a shell builtin - $ type -t export - builtin - $ type bash - bash is /bin/bash - $ type cd - cd is a function - cd () - { - builtin cd ${1+"$@"} && xtitle $HOST: $PWD - } -9 - - - July 18, 1994 - - - - - - - 7 - - - -Various modes tell what a command word is (reserved word, -alias, function, builtin, or file) or which version of a -command will be executed based on a user's search path. -Some of this functionality has been adopted by POSIX.2 and -folded into the _c_o_m_m_a_n_d utility. - -_4._3. _E_d_i_t_i_n_g _a_n_d _C_o_m_p_l_e_t_i_o_n - - One area in which Bash shines is command line editing. -Bash uses the _r_e_a_d_l_i_n_e library to read and edit lines when -interactive. Readline is a powerful and flexible input -facility that a user can configure to individual tastes. It -allows lines to be edited using either emacs or vi commands, -where those commands are appropriate. The full capability -of emacs is not present - there is no way to execute a named -command with M-x, for instance - but the existing commands -are more than adequate. The vi mode is compliant with the -command line editing standardized by POSIX.2. - - Readline is fully customizable. In addition to the -basic commands and key bindings, the library allows users to -define additional key bindings using a startup file. The -_i_n_p_u_t_r_c file, which defaults to the file ~/._i_n_p_u_t_r_c, is read -each time readline initializes, permitting users to maintain -a consistent interface across a set of programs. Readline -includes an extensible interface, so each program using the -library can add its own bindable commands and program- -specific key bindings. Bash uses this facility to add bind- -ings that perform history expansion or shell word expansions -on the current input line. - - Readline interprets a number of variables which further -tune its behavior. Variables exist to control whether or -not eight-bit characters are directly read as input or con- -verted to meta-prefixed key sequences (a meta-prefixed key -sequence consists of the character with the eighth bit -zeroed, preceded by the _m_e_t_a-_p_r_e_f_i_x character, usually -escape, which selects an alternate keymap), to decide -whether to output characters with the eighth bit set -directly or as a meta-prefixed key sequence, whether or not -to wrap to a new screen line when a line being edited is -longer than the screen width, the keymap to which subsequent -key bindings should apply, or even what happens when read- -line wants to ring the terminal's bell. All of these vari- -ables can be set in the inputrc file. - - The startup file understands a set of C preprocessor- -like conditional constructs which allow variables or key -bindings to be assigned based on the application using read- -line, the terminal currently being used, or the editing -mode. Users can add program-specific bindings to make their -lives easier: I have bindings that let me edit the value of -$_P_A_T_H and double-quote the current or previous word: -9 # Macros that are convenient for shell interaction - - -9 July 18, 1994 - - - - - - - 8 - - - - $if Bash - # edit the path - "\C-xp": "PATH=${PATH}\e\C-e\C-a\ef\C-f" - # prepare to type a quoted word -- insert open and close double - # quotes and move to just after the open quote - "\C-x\"": "\"\"\C-b" - # Quote the current or previous word - "\C-xq": "\eb\"\ef\"" - $endif -9 -There is a readline command to re-read the file, so users -can edit the file, change some bindings, and begin to use -them almost immediately. - - Bash implements the _b_i_n_d builtin for more dyamic con- -trol of readline than the startup file permits. _B_i_n_d is -used in several ways. In _l_i_s_t mode, it can display the -current key bindings, list all the readline editing direc- -tives available for binding, list which keys invoke a given -directive, or output the current set of key bindings in a -format that can be incorporated directly into an inputrc -file. In _b_a_t_c_h mode, it reads a series of key bindings -directly from a file and passes them to readline. In its -most common usage, _b_i_n_d takes a single string and passes it -directly to readline, which interprets the line as if it had -just been read from the inputrc file. Both key bindings and -variable assignments may appear in the string given to _b_i_n_d. - - The readline library also provides an interface for -_w_o_r_d _c_o_m_p_l_e_t_i_o_n. When the _c_o_m_p_l_e_t_i_o_n character (usually -TAB) is typed, readline looks at the word currently being -entered and computes the set of filenames of which the -current word is a valid prefix. If there is only one possi- -ble completion, the rest of the characters are inserted -directly, otherwise the common prefix of the set of -filenames is added to the current word. A second TAB char- -acter entered immediately after a non-unique completion -causes readline to list the possible completions; there is -an option to have the list displayed immediately. Readline -provides hooks so that applications can provide specific -types of completion before the default filename completion -is attempted. This is quite flexible, though it is not com- -pletely user-programmable. Bash, for example, can complete -filenames, command names (including aliases, builtins, shell -reserved words, shell functions, and executables found in -the file system), shell variables, usernames, and hostnames. -It uses a set of heuristics that, while not perfect, is gen- -erally quite good at determining what type of completion to -attempt. - -_4._4. _H_i_s_t_o_r_y - - Access to the list of commands previously entered (the -_c_o_m_m_a_n_d _h_i_s_t_o_r_y) is provided jointly by Bash and the - - -9 July 18, 1994 - - - - - - - 9 - - - -readline library. Bash provides variables ($HISTFILE, -$HISTSIZE, and $HISTCONTROL) and the _h_i_s_t_o_r_y and _f_c builtins -to manipulate the history list. The value of $_H_I_S_T_F_I_L_E -specifes the file where Bash writes the command history on -exit and reads it on startup. $_H_I_S_T_S_I_Z_E is used to limit -the number of commands saved in the history. $_H_I_S_T_C_O_N_T_R_O_L -provides a crude form of control over which commands are -saved on the history list: a value of _i_g_n_o_r_e_s_p_a_c_e means to -not save commands which begin with a space; a value of -_i_g_n_o_r_e_d_u_p_s means to not save commands identical to the last -command saved. $HISTCONTROL was named $history_control in -earlier versions of Bash; the old name is still accepted for -backwards compatibility. The _h_i_s_t_o_r_y command can read or -write files containing the history list and display the -current list contents. The _f_c builtin, adopted from POSIX.2 -and the Korn Shell, allows display and re-execution, with -optional editing, of commands from the history list. The -readline library offers a set of commands to search the his- -tory list for a portion of the current input line or a -string typed by the user. Finally, the _h_i_s_t_o_r_y library, -generally incorporated directly into the readline library, -implements a facility for history recall, expansion, and -re-execution of previous commands very similar to csh ("bang -history", so called because the exclamation point introduces -a history substitution): -9 $ echo a b c d e - a b c d e - $ !! f g h i - echo a b c d e f g h i - a b c d e f g h i - $ !-2 - echo a b c d e - a b c d e - $ echo !-2:1-4 - echo a b c d - a b c d -9 -The command history is only saved when the shell is interac- -tive, so it is not available for use by shell scripts. - -_4._5. _N_e_w _S_h_e_l_l _V_a_r_i_a_b_l_e_s - - There are a number of convenience variables that Bash -interprets to make life easier. These include _F_I_G_N_O_R_E, -which is a set of filename suffixes identifying files to -exclude when completing filenames; _H_O_S_T_T_Y_P_E, which is -automatically set to a string describing the type of -hardware on which Bash is currently executing; -_c_o_m_m_a_n_d__o_r_i_e_n_t_e_d__h_i_s_t_o_r_y, which directs Bash to save all -lines of a multiple-line command such as a _w_h_i_l_e or _f_o_r loop -in a single history entry, allowing easy re-editing; and -_I_G_N_O_R_E_E_O_F, whose value indicates the number of consecutive -EOF characters that an interactive shell will read before - - - - July 18, 1994 - - - - - - - 10 - - - -exiting - an easy way to keep yourself from being logged out -accidentally. The _a_u_t_o__r_e_s_u_m_e variable alters the way the -shell treats simple command names: if job control is active, -and this variable is set, single-word simple commands -without redirections cause the shell to first look for and -restart a suspended job with that name before starting a new -process. - -_4._6. _B_r_a_c_e _E_x_p_a_n_s_i_o_n - - Since sh offers no convenient way to generate arbitrary -strings that share a common prefix or suffix (filename -expansion requires that the filenames exist), Bash imple- -ments _b_r_a_c_e _e_x_p_a_n_s_i_o_n, a capability picked up from csh. -Brace expansion is similar to filename expansion, but the -strings generated need not correspond to existing files. A -brace expression consists of an optional _p_r_e_a_m_b_l_e, followed -by a pair of braces enclosing a series of comma-separated -strings, and an optional _p_o_s_t_a_m_b_l_e. The preamble is -prepended to each string within the braces, and the postam- -ble is then appended to each resulting string: -9 $ echo a{d,c,b}e - ade ace abe -9 -As this example demonstrates, the results of brace expansion -are not sorted, as they are by filename expansion. - -_4._7. _P_r_o_c_e_s_s _S_u_b_s_t_i_t_u_t_i_o_n - - On systems that can support it, Bash provides a facil- -ity known as _p_r_o_c_e_s_s _s_u_b_s_t_i_t_u_t_i_o_n. Process substitution is -similar to command substitution in that its specification -includes a command to execute, but the shell does not col- -lect the command's output and insert it into the command -line. Rather, Bash opens a pipe to the command, which is -run in the background. The shell uses named pipes (FIFOs) -or the /_d_e_v/_f_d method of naming open files to expand the -process substitution to a filename which connects to the -pipe when opened. This filename becomes the result of the -expansion. Process substitution can be used to compare the -outputs of two different versions of an application as part -of a regression test: -9 $ cmp <(old_prog) <(new_prog) -9 -_4._8. _P_r_o_m_p_t _C_u_s_t_o_m_i_z_a_t_i_o_n - - One of the more popular interactive features that Bash -provides is the ability to customize the prompt. Both $_P_S_1 -and $_P_S_2, the primary and secondary prompts, are expanded -before being displayed. Parameter and variable expansion is -performed when the prompt string is expanded, so any shell -variable can be put into the prompt (e.g., $_S_H_L_V_L, which - - - - July 18, 1994 - - - - - - - 11 - - - -indicates how deeply the current shell is nested). Bash -specially interprets characters in the prompt string pre- -ceded by a backslash. Some of these backslash escapes are -replaced with the current time, the date, the current work- -ing directory, the username, and the command number or his- -tory number of the command being entered. There is even a -backslash escape to cause the shell to change its prompt -when running as root after an _s_u. Before printing each pri- -mary prompt, Bash expands the variable $_P_R_O_M_P_T__C_O_M_M_A_N_D and, -if it has a value, executes the expanded value as a command, -allowing additional prompt customization. For example, this -assignment causes the current user, the current host, the -time, the last component of the current working directory, -the level of shell nesting, and the history number of the -current command to be embedded into the primary prompt: -9 $ PS1='\u@\h [\t] \W($SHLVL:\!)\$ ' - chet@odin [21:03:44] documentation(2:636)$ cd .. - chet@odin [21:03:54] src(2:637)$ -9 -The string being assigned is surrounded by single quotes so -that if it is exported, the value of $_S_H_L_V_L will be updated -by a child shell: -9 chet@odin [21:17:35] src(2:638)$ export PS1 - chet@odin [21:17:40] src(2:639)$ bash - chet@odin [21:17:46] src(3:696)$ -9 -The \$ escape is displayed as "$" when running as a normal -user, but as "#" when running as root. - -_4._9. _F_i_l_e _S_y_s_t_e_m _V_i_e_w_s - - Since Berkeley introduced symbolic links in 4.2 BSD, -one of their most annoying properties has been the "warping" -to a completely different area of the file system when using -_c_d, and the resultant non-intuitive behavior of "cd ..". -The UNIX kernel treats symbolic links _p_h_y_s_i_c_a_l_l_y. When the -kernel is translating a pathname in which one component is a -symbolic link, it replaces all or part of the pathname while -processing the link. If the contents of the symbolic link -begin with a slash, the kernel replaces the pathname -entirely; if not, the link contents replace the current com- -ponent. In either case, the symbolic link is visible. If -the link value is an absolute pathname, the user finds him- -self in a completely different part of the file system. - - Bash provides a _l_o_g_i_c_a_l view of the file system. In -this default mode, command and filename completion and buil- -tin commands such as _c_d and _p_u_s_h_d which change the current -working directory transparently follow symbolic links as if -they were directories. The $_P_W_D variable, which holds the -shell's idea of the current working directory, depends on -the path used to reach the directory rather than its - - - - July 18, 1994 - - - - - - - 12 - - - -physical location in the local file system hierarchy. For -example: -9 $ cd /usr/local/bin - $ echo $PWD - /usr/local/bin - $ pwd - /usr/local/bin - $ /bin/pwd - /net/share/sun4/local/bin - $ cd .. - $ pwd - /usr/local - $ /bin/pwd - /net/share/sun4/local - $ cd .. - $ pwd - /usr - $ /bin/pwd - /usr -9 -One problem with this, of course, arises when programs that -do not understand the shell's logical notion of the file -system interpret ".." differently. This generally happens -when Bash completes filenames containing ".." according to a -logical hierarchy which does not correspond to their physi- -cal location. For users who find this troublesome, a -corresponding _p_h_y_s_i_c_a_l view of the file system is available: -9 $ cd /usr/local/bin - $ pwd - /usr/local/bin - $ set -o physical - $ pwd - /net/share/sun4/local/bin -9 -_4._1_0. _I_n_t_e_r_n_a_t_i_o_n_a_l_i_z_a_t_i_o_n - - One of the most significant improvements in version -1.13 of Bash was the change to "eight-bit cleanliness". -Previous versions used the eighth bit of characters to mark -whether or not they were quoted when performing word expan- -sions. While this did not affect the majority of users, -most of whom used only seven-bit ASCII characters, some -found it confining. Beginning with version 1.13, Bash -implemented a different quoting mechanism that did not alter -the eighth bit of characters. This allowed Bash to manipu- -late files with "odd" characters in their names, but did -nothing to help users enter those names, so version 1.13 -introduced changes to readline that made it eight-bit clean -as well. Options exist that force readline to attach no -special significance to characters with the eighth bit set -(the default behavior is to convert these characters to -meta-prefixed key sequences) and to output these characters - - - - July 18, 1994 - - - - - - - 13 - - - -without conversion to meta-prefixed sequences. These -changes, along with the expansion of keymaps to a full eight -bits, enable readline to work with most of the ISO-8859 fam- -ily of character sets, used by many European countries. - -_4._1_1. _P_O_S_I_X _M_o_d_e - - Although Bash is intended to be POSIX.2 conformant, -there are areas in which the default behavior is not compa- -tible with the standard. For users who wish to operate in a -strict POSIX.2 environment, Bash implements a _P_O_S_I_X _m_o_d_e. -When this mode is active, Bash modifies its default opera- -tion where it differs from POSIX.2 to match the standard. -POSIX mode is entered when Bash is started with the -_p_o_s_i_x -option. This feature is also available as an option to the -set builtin, set -o posix. For compatibility with other GNU -software that attempts to be POSIX.2 compliant, Bash also -enters POSIX mode if the variable $_P_O_S_I_X_L_Y__C_O_R_R_E_C_T is set -when Bash is started or assigned a value during execution. -$_P_O_S_I_X__P_E_D_A_N_T_I_C is accepted as well, to be compatible with -some older GNU utilities. When Bash is started in POSIX -mode, for example, it sources the file named by the value of -$_E_N_V rather than the "normal" startup files, and does not -allow reserved words to be aliased. - -_5. _N_e_w _F_e_a_t_u_r_e_s _a_n_d _F_u_t_u_r_e _P_l_a_n_s - - There are several features introduced in the current -version of Bash, version 1.14, and a number under considera- -tion for future releases. This section will briefly detail -the new features in version 1.14 and describe several -features that may appear in later versions. - -_5._1. _N_e_w _F_e_a_t_u_r_e_s _i_n _B_a_s_h-_1._1_4 - - The new features available in Bash-1.14 answer several -of the most common requests for enhancements. Most notably, -there is a mechanism for including non-visible character -sequences in prompts, such as those which cause a terminal -to print characters in different colors or in standout mode. -There was nothing preventing the use of these sequences in -earlier versions, but the readline redisplay algorithm -assumed each character occupied physical screen space and -would wrap lines prematurely. - - Readline has a few new variables, several new bindable -commands, and some additional emacs mode default key bind- -ings. A new history search mode has been implemented: in -this mode, readline searches the history for lines beginning -with the characters between the beginning of the current -line and the cursor. The existing readline incremental -search commands no longer match identical lines more than -once. Filename completion now expands variables in direc- -tory names. The history expansion facilities are now nearly - - - - July 18, 1994 - - - - - - - 14 - - - -completely csh-compatible: missing modifiers have been added -and history substitution has been extended. - - Several of the features described earlier, such as _s_e_t --_o _p_o_s_i_x and $_P_O_S_I_X__P_E_D_A_N_T_I_C, are new in version 1.14. -There is a new shell variable, _O_S_T_Y_P_E, to which Bash assigns -a value that identifies the version of UNIX it's running on -(great for putting architecture-specific binary directories -into the $PATH). Two variables have been renamed: $_H_I_S_T_C_O_N_- -_T_R_O_L replaces $_h_i_s_t_o_r_y__c_o_n_t_r_o_l, and $_H_O_S_T_F_I_L_E replaces -$_h_o_s_t_n_a_m_e__c_o_m_p_l_e_t_i_o_n__f_i_l_e. In both cases, the old names are -accepted for backwards compatibility. The ksh _s_e_l_e_c_t con- -struct, which allows the generation of simple menus, has -been implemented. New capabilities have been added to -existing variables: $_a_u_t_o__r_e_s_u_m_e can now take values of -_e_x_a_c_t or _s_u_b_s_t_r_i_n_g, and $_H_I_S_T_C_O_N_T_R_O_L understands the value -_i_g_n_o_r_e_b_o_t_h, which combines the two previously acceptable -values. The _d_i_r_s builtin has acquired options to print out -specific members of the directory stack. The $_n_o_l_i_n_k_s vari- -able, which forces a physical view of the file system, has -been superseded by the -_P option to the _s_e_t builtin -(equivalent to set -o physical); the variable is retained -for backwards compatibility. The version string contained -in $_B_A_S_H__V_E_R_S_I_O_N now includes an indication of the patch -level as well as the "build version". Some little-used -features have been removed: the _b_y_e synonym for _e_x_i_t and -the $_N_O__P_R_O_M_P_T__V_A_R_S variable are gone. There is now an -organized test suite that can be run as a regression test -when building a new version of Bash. - - The documentation has been thoroughly overhauled: there -is a new manual page on the readline library and the _i_n_f_o -file has been updated to reflect the current version. As -always, as many bugs as possible have been fixed, although -some surely remain. - -_5._2. _O_t_h_e_r _F_e_a_t_u_r_e_s - - There are a few features that I hope to include in -later Bash releases. Some are based on work already done in -other shells. - - In addition to simple variables, a future release of -Bash will include one-dimensional arrays, using the ksh -implementation of arrays as a model. Additions to the ksh -syntax, such as _v_a_r_n_a_m_e=( ... ) to assign a list of words -directly to an array and a mechanism to allow the _r_e_a_d buil- -tin to read a list of values directly into an array, would -be desirable. Given those extensions, the ksh _s_e_t -_A syntax -may not be worth supporting (the -_A option assigns a list of -values to an array, but is a rather peculiar special case). - - Some shells include a means of _p_r_o_g_r_a_m_m_a_b_l_e word com- -pletion, where the user specifies on a per-command basis how - - - - July 18, 1994 - - - - - - - 15 - - - -the arguments of the command are to be treated when comple- -tion is attempted: as filenames, hostnames, executable -files, and so on. The other aspects of the current Bash -implementation could remain as-is; the existing heuristics -would still be valid. Only when completing the arguments to -a simple command would the programmable completion be in -effect. - - It would also be nice to give the user finer-grained -control over which commands are saved onto the history list. -One proposal is for a variable, tentatively named _H_I_S_T_I_G_- -_N_O_R_E, which would contain a colon-separated list of com- -mands. Lines beginning with these commands, after the res- -trictions of $_H_I_S_T_C_O_N_T_R_O_L have been applied, would not be -placed onto the history list. The shell pattern-matching -capabilities could also be available when specifying the -contents of $_H_I_S_T_I_G_N_O_R_E. - - One thing that newer shells such as _w_k_s_h (also known as -_d_t_k_s_h) provide is a command to dynamically load code imple- -menting additional builtin commands into a running shell. -This new builtin would take an object file or shared library -implementing the "body" of the builtin (_x_x_x__b_u_i_l_t_i_n() for -those familiar with Bash internals) and a structure contain- -ing the name of the new command, the function to call when -the new builtin is invoked (presumably defined in the shared -object specified as an argument), and the documentation to -be printed by the _h_e_l_p command (possibly present in the -shared object as well). It would manage the details of -extending the internal table of builtins. - - A few other builtins would also be desirable: two are -the POSIX.2 _g_e_t_c_o_n_f command, which prints the values of sys- -tem configuration variables defined by POSIX.2, and a _d_i_s_o_w_n -builtin, which causes a shell running with job control -active to "forget about" one or more background jobs in its -internal jobs table. Using _g_e_t_c_o_n_f, for example, a user -could retrieve a value for $_P_A_T_H guaranteed to find all of -the POSIX standard utilities, or find out how long filenames -may be in the file system containing a specified directory. - - There are no implementation timetables for any of these -features, nor are there concrete plans to include them. If -anyone has comments on these proposals, feel free to send me -electronic mail. - -_6. _R_e_f_l_e_c_t_i_o_n_s _a_n_d _L_e_s_s_o_n_s _L_e_a_r_n_e_d - - The lesson that has been repeated most often during -Bash development is that there are dark corners in the -Bourne Shell, and people use all of them. In the original -description of the Bourne shell, quoting and the shell gram- -mar are both poorly specified and incomplete; subsequent -descriptions have not helped much. The grammar presented in - - - - July 18, 1994 - - - - - - - 16 - - - -Bourne's paper describing the shell distributed with the -Seventh Edition of UNIX|- is so far off that it does not -allow the command who|wc. In fact, as Tom Duff states: - - Nobody really knows what the Bourne shell's gram- - mar is. Even examination of the source code is - little help.|= - -The POSIX.2 standard includes a _y_a_c_c grammar that comes -close to capturing the Bourne shell's behavior, but it -disallows some constructs which sh accepts without complaint -- and there are scripts out there that use them. It took a -few versions and several bug reports before Bash implemented -sh-compatible quoting, and there are still some "legal" sh -constructs which Bash flags as syntax errors. Complete sh -compatibility is a tough nut. - - The shell is bigger and slower than I would like, -though the current version is substantially faster than pre- -viously. The readline library could stand a substantial -rewrite. A hand-written parser to replace the current -_y_a_c_c-generated one would probably result in a speedup, and -would solve one glaring problem: the shell could parse com- -mands in "$(...)" constructs as they are entered, rather -than reporting errors when the construct is expanded. - - As always, there is some chaff to go with the wheat. -Areas of duplicated functionality need to be cleaned up. -There are several cases where Bash treats a variable spe- -cially to enable functionality available another way -($notify vs. set -o notify and $nolinks vs. set -o physi- -cal, for instance); the special treatment of the variable -name should probably be removed. A few more things could -stand removal; the $_a_l_l_o_w__n_u_l_l__g_l_o_b__e_x_p_a_n_s_i_o_n and -$_g_l_o_b__d_o_t__f_i_l_e_n_a_m_e_s variables are of particularly question- -able value. The $[...] arithmetic evaluation syntax is -redundant now that the POSIX-mandated $((...)) construct has -been implemented, and could be deleted. It would be nice if -the text output by the _h_e_l_p builtin were external to the -shell rather than compiled into it. The behavior enabled by -$_c_o_m_m_a_n_d__o_r_i_e_n_t_e_d__h_i_s_t_o_r_y, which causes the shell to attempt -to save all lines of a multi-line command in a single his- -tory entry, should be made the default and the variable -removed. - - -_________________________ -|-S. R. Bourne, "UNIX Time-Sharing System: The UNIX -Shell", _B_e_l_l _S_y_s_t_e_m _T_e_c_h_n_i_c_a_l _J_o_u_r_n_a_l, 57(6), July- -August, 1978, pp. 1971-1990. -|=Tom Duff, "Rc - A Shell for Plan 9 and UNIX systems", -_P_r_o_c. _o_f _t_h_e _S_u_m_m_e_r _1_9_9_0 _E_U_U_G _C_o_n_f_e_r_e_n_c_e, London, July, -1990, pp. 21-33. - - - - - July 18, 1994 - - - - - - - 17 - - - -_7. _A_v_a_i_l_a_b_i_l_i_t_y - - As with all other GNU software, Bash is available for -anonymous FTP from _p_r_e_p._a_i._m_i_t._e_d_u:/_p_u_b/_g_n_u and from other -GNU software mirror sites. The current version is in _b_a_s_h- -_1._1_4._1._t_a_r._g_z in that directory. Use _a_r_c_h_i_e to find the -nearest archive site. The latest version is always avail- -able for FTP from _b_a_s_h._C_W_R_U._E_d_u:/_p_u_b/_d_i_s_t. Bash documenta- -tion is available for FTP from _b_a_s_h._C_W_R_U._E_d_u:/_p_u_b/_b_a_s_h. - - The Free Software Foundation sells tapes and CD-ROMs -containing Bash; send electronic mail to gnu@prep.ai.mit.edu -or call +1-617-876-3296 for more information. - - Bash is also distributed with several versions of -UNIX-compatible systems. It is included as /bin/sh and -/bin/bash on several Linux distributions (more about the -difference in a moment), and as contributed software in -BSDI's BSD/386* and FreeBSD. - - The Linux distribution deserves special mention. There -are two configurations included in the standard Bash distri- -bution: a "normal" configuration, in which all of the stan- -dard features are included, and a "minimal" configuration, -which omits job control, aliases, history and command line -editing, the directory stack and _p_u_s_h_d/_p_o_p_d/_d_i_r_s, process -substitution, prompt string special character decoding, and -the _s_e_l_e_c_t construct. This minimal version is designed to -be a drop-in replacement for the traditional UNIX /bin/sh, -and is included as the Linux /bin/sh in several packagings. - -_8. _C_o_n_c_l_u_s_i_o_n - - Bash is a worthy successor to sh. It is sufficiently -portable to run on nearly every version of UNIX from 4.3 BSD -to SVR4.2, and several UNIX workalikes. It is robust enough -to replace sh on most of those systems, and provides more -functionality. It has several thousand regular users, and -their feedback has helped to make it as good as it is today -- a testament to the benefits of free software. - - - - - - - - - - -_________________________ -*BSD/386 is a trademark of Berkeley Software Design, -Inc. - - - - - July 18, 1994 - - diff --git a/documentation/bash.ps b/documentation/bash.ps deleted file mode 100644 index c3a4643..0000000 --- a/documentation/bash.ps +++ /dev/null @@ -1,3959 +0,0 @@ -%!PS-Adobe-3.0 -%%Creator: groff version 1.08 -%%DocumentNeededResources: font Times-Roman -%%+ font Times-Bold -%%+ font Times-Italic -%%+ font Symbol -%%DocumentSuppliedResources: procset grops 1.08 0 -%%Pages: 37 -%%PageOrder: Ascend -%%Orientation: Portrait -%%EndComments -%%BeginProlog -%%BeginResource: procset grops 1.08 0 -/setpacking where{ -pop -currentpacking -true setpacking -}if -/grops 120 dict dup begin -/SC 32 def -/A/show load def -/B{0 SC 3 -1 roll widthshow}bind def -/C{0 exch ashow}bind def -/D{0 exch 0 SC 5 2 roll awidthshow}bind def -/E{0 rmoveto show}bind def -/F{0 rmoveto 0 SC 3 -1 roll widthshow}bind def -/G{0 rmoveto 0 exch ashow}bind def -/H{0 rmoveto 0 exch 0 SC 5 2 roll awidthshow}bind def -/I{0 exch rmoveto show}bind def -/J{0 exch rmoveto 0 SC 3 -1 roll widthshow}bind def -/K{0 exch rmoveto 0 exch ashow}bind def -/L{0 exch rmoveto 0 exch 0 SC 5 2 roll awidthshow}bind def -/M{rmoveto show}bind def -/N{rmoveto 0 SC 3 -1 roll widthshow}bind def -/O{rmoveto 0 exch ashow}bind def -/P{rmoveto 0 exch 0 SC 5 2 roll awidthshow}bind def -/Q{moveto show}bind def -/R{moveto 0 SC 3 -1 roll widthshow}bind def -/S{moveto 0 exch ashow}bind def -/T{moveto 0 exch 0 SC 5 2 roll awidthshow}bind def -/SF{ -findfont exch -[exch dup 0 exch 0 exch neg 0 0]makefont -dup setfont -[exch/setfont cvx]cvx bind def -}bind def -/MF{ -findfont -[5 2 roll -0 3 1 roll -neg 0 0]makefont -dup setfont -[exch/setfont cvx]cvx bind def -}bind def -/level0 0 def -/RES 0 def -/PL 0 def -/LS 0 def -/PLG{ -gsave newpath clippath pathbbox grestore -exch pop add exch pop -}bind def -/BP{ -/level0 save def -1 setlinecap -1 setlinejoin -72 RES div dup scale -LS{ -90 rotate -}{ -0 PL translate -}ifelse -1 -1 scale -}bind def -/EP{ -level0 restore -showpage -}bind def -/DA{ -newpath arcn stroke -}bind def -/SN{ -transform -.25 sub exch .25 sub exch -round .25 add exch round .25 add exch -itransform -}bind def -/DL{ -SN -moveto -SN -lineto stroke -}bind def -/DC{ -newpath 0 360 arc closepath -}bind def -/TM matrix def -/DE{ -TM currentmatrix pop -translate scale newpath 0 0 .5 0 360 arc closepath -TM setmatrix -}bind def -/RC/rcurveto load def -/RL/rlineto load def -/ST/stroke load def -/MT/moveto load def -/CL/closepath load def -/FL{ -currentgray exch setgray fill setgray -}bind def -/BL/fill load def -/LW/setlinewidth load def -/RE{ -findfont -dup maxlength 1 index/FontName known not{1 add}if dict begin -{ -1 index/FID ne{def}{pop pop}ifelse -}forall -/Encoding exch def -dup/FontName exch def -currentdict end definefont pop -}bind def -/DEFS 0 def -/EBEGIN{ -moveto -DEFS begin -}bind def -/EEND/end load def -/CNT 0 def -/level1 0 def -/PBEGIN{ -/level1 save def -translate -div 3 1 roll div exch scale -neg exch neg exch translate -0 setgray -0 setlinecap -1 setlinewidth -0 setlinejoin -10 setmiterlimit -[]0 setdash -/setstrokeadjust where{ -pop -false setstrokeadjust -}if -/setoverprint where{ -pop -false setoverprint -}if -newpath -/CNT countdictstack def -userdict begin -/showpage{}def -}bind def -/PEND{ -clear -countdictstack CNT sub{end}repeat -level1 restore -}bind def -end def -/setpacking where{ -pop -setpacking -}if -%%EndResource -%%IncludeResource: font Times-Roman -%%IncludeResource: font Times-Bold -%%IncludeResource: font Times-Italic -%%IncludeResource: font Symbol -grops begin/DEFS 1 dict def DEFS begin/u{.001 mul}bind def end/RES 72 def/PL -792 def/LS false def/ENC0[/asciicircum/asciitilde/Scaron/Zcaron/scaron/zcaron -/Ydieresis/trademark/quotesingle/.notdef/.notdef/.notdef/.notdef/.notdef -/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef -/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/space -/exclam/quotedbl/numbersign/dollar/percent/ampersand/quoteright/parenleft -/parenright/asterisk/plus/comma/hyphen/period/slash/zero/one/two/three/four -/five/six/seven/eight/nine/colon/semicolon/less/equal/greater/question/at/A/B/C -/D/E/F/G/H/I/J/K/L/M/N/O/P/Q/R/S/T/U/V/W/X/Y/Z/bracketleft/backslash -/bracketright/circumflex/underscore/quoteleft/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q -/r/s/t/u/v/w/x/y/z/braceleft/bar/braceright/tilde/.notdef/quotesinglbase -/guillemotleft/guillemotright/bullet/florin/fraction/perthousand/dagger -/daggerdbl/endash/emdash/ff/fi/fl/ffi/ffl/dotlessi/dotlessj/grave/hungarumlaut -/dotaccent/breve/caron/ring/ogonek/quotedblleft/quotedblright/oe/lslash -/quotedblbase/OE/Lslash/.notdef/exclamdown/cent/sterling/currency/yen/brokenbar -/section/dieresis/copyright/ordfeminine/guilsinglleft/logicalnot/minus -/registered/macron/degree/plusminus/twosuperior/threesuperior/acute/mu -/paragraph/periodcentered/cedilla/onesuperior/ordmasculine/guilsinglright -/onequarter/onehalf/threequarters/questiondown/Agrave/Aacute/Acircumflex/Atilde -/Adieresis/Aring/AE/Ccedilla/Egrave/Eacute/Ecircumflex/Edieresis/Igrave/Iacute -/Icircumflex/Idieresis/Eth/Ntilde/Ograve/Oacute/Ocircumflex/Otilde/Odieresis -/multiply/Oslash/Ugrave/Uacute/Ucircumflex/Udieresis/Yacute/Thorn/germandbls -/agrave/aacute/acircumflex/atilde/adieresis/aring/ae/ccedilla/egrave/eacute -/ecircumflex/edieresis/igrave/iacute/icircumflex/idieresis/eth/ntilde/ograve -/oacute/ocircumflex/otilde/odieresis/divide/oslash/ugrave/uacute/ucircumflex -/udieresis/yacute/thorn/ydieresis]def/Times-Italic@0 ENC0/Times-Italic RE -/Times-Bold@0 ENC0/Times-Bold RE/Times-Roman@0 ENC0/Times-Roman RE -%%EndProlog -%%Page: 1 1 -%%BeginPageSetup -BP -%%EndPageSetup -/F0 10/Times-Roman@0 SF -.35(BA)72 48 S 389.54(SH\(1\) B).35 F(ASH\(1\))-.35 E -/F1 9/Times-Bold@0 SF -.18(NA)72 84 S(ME).18 E F0(bash \255 GNU Bourne\255Ag) -108 96 Q(ain SHell)-.05 E F1(SYNOPSIS)72 112.8 Q/F2 10/Times-Bold@0 SF(bash)108 -124.8 Q F0([options] [\214le])2.5 E F1(COPYRIGHT)72 141.6 Q F0(Bash is Cop)108 -153.6 Q(yright \251 1989, 1991 by the Free Softw)-.1 E(are F)-.1 E -(oundation, Inc.)-.15 E F1(DESCRIPTION)72 170.4 Q F2(Bash)108 182.4 Q F0 .796 -(is an)3.296 F F2(sh)3.296 E F0 .795 -(\255compatible command language interpreter that e)B -.15(xe)-.15 G .795 -(cutes commands read from the standard).15 F(input or from a \214le.)108 194.4 -Q F2(Bash)5 E F0(also incorporates useful features from the)2.5 E/F3 10 -/Times-Italic@0 SF -.4(Ko)2.5 G(rn).4 E F0(and)2.5 E F3(C)2.5 E F0(shells \() -2.5 E F2(ksh)A F0(and)2.5 E F2(csh)2.5 E F0(\).)A F2(Bash)108 211.2 Q F0 .488(\ -is ultimately intended to be a conformant implementation of the IEEE Posix She\ -ll and T)2.988 F .489(ools speci\214-)-.8 F(cation \(IEEE W)108 223.2 Q -(orking Group 1003.2\).)-.8 E F1(OPTIONS)72 240 Q F0 .366(In addition to the s\ -ingle\255character shell options documented in the description of the)108 252 R -F2(set)2.866 E F0 -.2(bu)2.866 G .366(iltin command,).2 F F2(bash)108 264 Q F0 -(interprets the follo)2.5 E(wing \215ags when it is in)-.25 E -.2(vo)-.4 G -.1 -(ke).2 G(d:).1 E F2108 280.8 Q F3(string)4.166 E F0 .504(If the)158 280.8 -R F23.004 E F0 .505(\215ag is present, then commands are read from)3.004 -F F3(string)3.005 E F0 5.505(.I).22 G 3.005(ft)417.425 280.8 S .505 -(here are ar)426.54 280.8 R .505(guments after the)-.18 F F3(string)158 292.8 Q -F0 2.5(,t).22 G(he)189.34 292.8 Q 2.5(ya)-.15 G -(re assigned to the positional parameters, starting with)210.57 292.8 Q F2($0) -2.5 E F0(.)A F2108 304.8 Q F0(If the)158 304.8 Q F22.5 E F0 -(\215ag is present, the shell is)2.5 E F3(inter)2.5 E(active)-.15 E F0(.).18 E -F2108 316.8 Q F0 .305(If the)158 316.8 R F22.805 E F0 .305 -(\215ag is present, or if no ar)2.805 F .305 -(guments remain after option processing, then commands are)-.18 F 1.711 -(read from the standard input.)158 328.8 R 1.711(This option allo)6.711 F 1.712 -(ws the positional parameters to be set when)-.25 F(in)158 340.8 Q -.2(vo)-.4 G -(king an interacti).2 E .3 -.15(ve s)-.25 H(hell.).15 E F2108 352.8 Q F0 -3.373(As)158 352.8 S(ingle)172.483 352.8 Q F23.373 E F0 .873 -(signals the end of options and disables further option processing.)3.373 F(An) -5.872 E 3.372(ya)-.15 G -.18(rg)502.96 352.8 S(uments).18 E .044(after the)158 -364.8 R F22.544 E F0 .044(are treated as \214lenames and ar)2.544 F 2.544 -(guments. An)-.18 F(ar)2.544 E .044(gument of)-.18 F F22.544 E F0 .044 -(is equi)2.544 F -.25(va)-.25 G .045(lent to an ar).25 F(gu-)-.18 E(ment of)158 -376.8 Q F22.5 E F0(.)A F2(Bash)108 393.6 Q F0 .15 -(also interprets a number of multi\255character options.)2.65 F .149 -(These options must appear on the command line)5.149 F -(before the single\255character options to be recognized.)108 405.6 Q F2 -(\255nor)108 422.4 Q(c)-.18 E F0 .282(Do not read and e)158 422.4 R -.15(xe) --.15 G .282(cute the personal initialization \214le).15 F F3(~/.bashr)2.782 E -(c)-.37 E F0 .282(if the shell is interacti)2.782 F -.15(ve)-.25 G 5.282(.T).15 -G(his)528.33 422.4 Q(option is on by def)158 434.4 Q(ault if the shell is in) --.1 E -.2(vo)-.4 G -.1(ke).2 G 2.5(da).1 G(s)342.75 434.4 Q F2(sh)2.5 E F0(.)A -F2(\255nopr)108 446.4 Q(o\214le)-.18 E F0 .223 -(Do not read either the system\255wide startup \214le)6.14 F F3(/etc/pr)4.389 E -(o\214le)-.45 E F0 .223(or an)4.389 F 2.722(yo)-.15 G 2.722(ft)431.844 446.4 S -.222(he personal initialization)440.676 446.4 R(\214les)158 458.4 Q F3 -(~/.bash_pr)4.066 E(o\214le)-.45 E F0(,).18 E F3(~/.bash_lo)4.066 E(gin)-.1 E -F0 4.066(,o).24 G(r)308.408 458.4 Q F3(~/.pr)4.066 E(o\214le)-.45 E F0 6.566 -(.B).18 G 4.066(yd)365.99 458.4 S(ef)380.056 458.4 Q(ault,)-.1 E F2(bash)4.066 -E F0 1.567(normally reads these \214les)4.067 F(when it is in)158 470.4 Q -.2 -(vo)-.4 G -.1(ke).2 G 2.5(da).1 G 2.5(sal)237.85 470.4 S(ogin shell \(see) -253.96 470.4 Q F1(INV)2.5 E(OCA)-.405 E(TION)-.855 E F0(belo)2.25 E(w\).)-.25 E -F2108 482.4 Q(c\214le)-.18 E F3(\214le)2.5 E F0(Ex)8.1 E .452 -(ecute commands from)-.15 F F3(\214le)2.952 E F0 .452 -(instead of the standard personal initialization \214le)2.952 F F3(~/.bashr) -2.951 E(c)-.37 E F0 2.951(,i).31 G 2.951(ft)521.499 482.4 S(he)530.56 482.4 Q -(shell is interacti)158 494.4 Q .3 -.15(ve \()-.25 H(see).15 E F1(INV)2.5 E -(OCA)-.405 E(TION)-.855 E F0(belo)2.25 E(w\).)-.25 E F2108 506.4 Q -(ersion)-.1 E F0(Sho)158 506.4 Q 2.5(wt)-.25 G(he v)185.81 506.4 Q -(ersion number of this instance of)-.15 E F2(bash)2.5 E F0(when starting.)2.5 E -F2(\255quiet)108 518.4 Q F0 .71(Do not be v)158 518.4 R .71 -(erbose when starting up \(do not sho)-.15 F 3.21(wt)-.25 G .71(he shell v) -366.9 518.4 R .71(ersion or an)-.15 F 3.21(yo)-.15 G .71(ther information\).) -468.19 518.4 R(This is the def)158 530.4 Q(ault.)-.1 E F2(\255login)108 542.4 Q -F0(Mak)158 542.4 Q(e)-.1 E F2(bash)2.5 E F0(act as if it had been in)2.5 E -.2 -(vo)-.4 G -.1(ke).2 G 2.5(da).1 G 2.5(sal)324.12 542.4 S(ogin shell.)340.23 -542.4 Q F2(\255nobraceexpansion)108 554.4 Q F0(Do not perform curly brace e)158 -566.4 Q(xpansion \(see)-.15 E F2(Brace Expansion)2.5 E F0(belo)2.5 E(w\).)-.25 -E F2(\255nolineediting)108 578.4 Q F0(Do not use the GNU)158 590.4 Q F3 -.37 -(re)2.5 G(adline).37 E F0(library to read command lines if interacti)2.5 E -.15 -(ve)-.25 G(.).15 E F2(\255posix)108 602.4 Q F0 1.001(Change the beha)158 602.4 -R 1.001(vior of bash where the def)-.2 F 1.001(ault operation dif)-.1 F 1 -(fers from the Posix 1003.2 stan-)-.25 F(dard to match the standard)158 614.4 Q -F1(ARGUMENTS)72 631.2 Q F0 .016(If ar)108 643.2 R .016 -(guments remain after option processing, and neither the)-.18 F F22.516 E -F0 .016(nor the)2.516 F F22.516 E F0 .016 -(option has been supplied, the \214rst)2.516 F(ar)108 655.2 Q .041 -(gument is assumed to be the name of a \214le containing shell commands.)-.18 F -(If)5.041 E F2(bash)2.541 E F0 .041(is in)2.541 F -.2(vo)-.4 G -.1(ke).2 G -2.541(di).1 G 2.541(nt)483.628 655.2 S .041(his f)493.949 655.2 R(ashion,)-.1 E -F2($0)108 667.2 Q F0 .936(is set to the name of the \214le, and the positional\ - parameters are set to the remaining ar)3.435 F(guments.)-.18 E F2(Bash)5.936 E -F0 .225(reads and e)108 679.2 R -.15(xe)-.15 G .224 -(cutes commands from this \214le, then e).15 F(xits.)-.15 E F2(Bash')5.224 E(s) --.37 E F0 -.15(ex)2.724 G .224(it status is the e).15 F .224 -(xit status of the last com-)-.15 F(mand e)108 691.2 Q -.15(xe)-.15 G -(cuted in the script.).15 E 185.675(GNU 1995)72 768 R(May 5)2.5 E(1)535 768 Q -EP -%%Page: 2 2 -%%BeginPageSetup -BP -%%EndPageSetup -/F0 10/Times-Roman@0 SF -.35(BA)72 48 S 389.54(SH\(1\) B).35 F(ASH\(1\))-.35 E -/F1 9/Times-Bold@0 SF(DEFINITIONS)72 84 Q/F2 10/Times-Bold@0 SF(blank)108 96 Q -F0 2.5(As)144 96 S(pace or tab)157.61 96 Q(.)-.4 E F2 -.1(wo)108 108 S(rd).1 E -F0 2.5(As)144 108 S -(equence of characters considered as a single unit by the shell.)157.61 108 Q -(Also kno)5 E(wn as a)-.25 E F2(tok)2.5 E(en)-.1 E F0(.)A F2(name)108 120 Q F0 -(A)144 120 Q/F3 10/Times-Italic@0 SF(wor)2.75 E(d)-.37 E F0 .251 -(consisting only of alphanumeric characters and underscores, and be)2.75 F .251 -(ginning with an alpha-)-.15 F(betic character or an underscore.)144 132 Q -(Also referred to as an)5 E F2(identi\214er)2.5 E F0(.)A F2(metacharacter)108 -144 Q F0 2.5(Ac)144 156 S(haracter that, when unquoted, separates w)158.16 156 -Q 2.5(ords. One)-.1 F(of the follo)2.5 E(wing:)-.25 E F2 5(|&;\(\)<>s)144 168 S -2.5(pace tab)214.81 168 R(contr)108 180 Q(ol operator)-.18 E F0(A)144 192 Q F3 -(tok)2.5 E(en)-.1 E F0(that performs a control function.)2.5 E -(It is one of the follo)5 E(wing symbols:)-.25 E/F4 10/Symbol SF 1.666144 -204 S F2 5(&&)3.334 G 5(&;;)182.206 204 S 5(;\(\)|<)207.196 204 S(newline>) -245.086 204 Q F1(RESER)72 220.8 Q(VED W)-.495 E(ORDS)-.09 E F3 .307 -(Reserved wor)108 232.8 R(ds)-.37 E F0 .307(are w)2.807 F .307(ords that ha)-.1 -F .607 -.15(ve a s)-.2 H .306(pecial meaning to the shell.).15 F .306 -(The follo)5.306 F .306(wing w)-.25 F .306(ords are recognized as)-.1 F(reserv) -108 244.8 Q .227(ed when unquoted and either the \214rst w)-.15 F .227 -(ord of a simple command \(see)-.1 F F1 .227(SHELL GRAMMAR)2.727 F F0(belo) -2.477 E .227(w\) or)-.25 F(the third w)108 256.8 Q(ord of a)-.1 E F2(case)2.5 E -F0(or)2.5 E F2 -.25(fo)2.5 G(r).25 E F0(command:)2.5 E F2 11.916(!c)144 273.6 S -9.416(ase do done elif else esac \214 f)163.686 273.6 R 9.415 -(or function if in select then until)-.25 F 7.5(while { })144 285.6 R F1 -(SHELL GRAMMAR)72 302.4 Q F2(Simple Commands)87 314.4 Q F0(A)108 326.4 Q F3 -.383(simple command)2.883 F F0 .383(is a sequence of optional v)2.883 F .384 -(ariable assignments follo)-.25 F .384(wed by)-.25 F F3(blank)2.884 E F0 .384 -(\255separated w)B .384(ords and)-.1 F .816(redirections, and terminated by a) -108 338.4 R F3(contr)3.316 E .815(ol oper)-.45 F(ator)-.15 E F0 5.815(.T)C .815 -(he \214rst w)326.97 338.4 R .815(ord speci\214es the command to be e)-.1 F --.15(xe)-.15 G(cuted.).15 E(The remaining w)108 350.4 Q(ords are passed as ar) --.1 E(guments to the in)-.18 E -.2(vo)-.4 G -.1(ke).2 G 2.5(dc).1 G(ommand.) -358.08 350.4 Q .175(The return v)108 367.2 R .175(alue of a)-.25 F F3 .175 -(simple command)2.675 F F0 .175(is its e)2.675 F .175(xit status, or 128+)-.15 -F F3(n)A F0 .176(if the command is terminated by signal)3.508 F F3(n)2.676 E F0 -(.).24 E F2(Pipelines)87 384 Q F0(A)108 396 Q F3(pipeline)2.92 E F0 .42 -(is a sequence of one or more commands separated by the character)2.92 F F2(|) -2.919 E F0 5.419(.T)C .419(he format for a pipeline)443.904 396 R(is:)108 408 Q -2.5([!])144 424.8 S F3(command)A F0([)2.5 E F2(|)2.5 E F3(command2)2.5 E F0 -(... ])2.5 E .418(The standard output of)108 441.6 R F3(command)2.918 E F0 .418 -(is connected to the standard input of)2.918 F F3(command2)2.918 E F0 5.418(.T) -.02 G .419(his connection is per)453.124 441.6 R(-)-.2 E(formed before an)108 -453.6 Q 2.5(yr)-.15 G(edirections speci\214ed by the command \(see)187.54 453.6 -Q F1(REDIRECTION)2.5 E F0(belo)2.25 E(w\).)-.25 E .238(If the reserv)108 470.4 -R .238(ed w)-.15 F(ord)-.1 E F2(!)2.737 E F0 .237(precedes a pipeline, the e) -5.237 F .237(xit status of that pipeline is the logical NO)-.15 F 2.737(To)-.4 -G 2.737(ft)486.949 470.4 S .237(he e)495.796 470.4 R .237(xit sta-)-.15 F .612 -(tus of the last command.)108 482.4 R .612 -(Otherwise, the status of the pipeline is the e)5.612 F .612 -(xit status of the last command.)-.15 F(The)5.613 E(shell w)108 494.4 Q -(aits for all commands in the pipeline to terminate before returning a v)-.1 E -(alue.)-.25 E(Each command in a pipeline is e)108 511.2 Q -.15(xe)-.15 G -(cuted as a separate process \(i.e., in a subshell\).).15 E F2(Lists)87 528 Q -F0(A)108 540 Q F3(list)2.727 E F0 .227 -(is a sequence of one or more pipelines separated by one of the operators)2.727 -F F2(;)2.727 E F0(,)A F2(&)2.727 E F0(,)A F2(&&)2.727 E F0 2.727(,o)C(r)475.563 -540 Q F4 1.6662.727 G F0 2.727(,a)-1.666 G .227(nd termi-)502.833 540 R -(nated by one of)108 552 Q F2(;)2.5 E F0(,)A F2(&)2.5 E F0 2.5(,o)C(r)199.09 -552 Q F2()2.5 E F0(.)A .563(Of these list operators,)108 568.8 R F2 -(&&)3.063 E F0(and)3.063 E F4 1.6663.063 G F0(ha)1.397 E .863 -.15(ve e) --.2 H .564(qual precedence, follo).15 F .564(wed by)-.25 F F2(;)3.064 E F0(and) -3.064 E F2(&,)3.064 E F0 .564(which ha)3.064 F .864 -.15(ve e)-.2 H .564 -(qual prece-).15 F(dence.)108 580.8 Q .029 -(If a command is terminated by the control operator)108 597.6 R F2(&)2.529 E F0 -2.529(,t)C .029(he shell e)330.75 597.6 R -.15(xe)-.15 G .029 -(cutes the command in the).15 F F3(bac)2.528 E(kgr)-.2 E(ound)-.45 E F0(in) -2.528 E 2.875(as)108 609.6 S 2.875(ubshell. The)119.205 609.6 R .375 -(shell does not w)2.875 F .375 -(ait for the command to \214nish, and the return status is 0.)-.1 F .376 -(Commands sepa-)5.376 F .849(rated by a)108 621.6 R F2(;)3.349 E F0 .849(are e) -3.349 F -.15(xe)-.15 G .848(cuted sequentially; the shell w).15 F .848 -(aits for each command to terminate in turn.)-.1 F .848(The return)5.848 F -(status is the e)108 633.6 Q(xit status of the last command e)-.15 E -.15(xe) --.15 G(cuted.).15 E(The control operators)108 650.4 Q F2(&&)2.5 E F0(and)2.5 E -F4 1.6662.5 G F0(denote AND lists and OR lists, respecti).834 E -.15(ve) --.25 G(ly).15 E 5(.A)-.65 G 2.5(nA)435.116 650.4 S(ND list has the form)449.836 -650.4 Q F3(command)144 667.2 Q F2(&&)2.5 E F3(command2)2.5 E(command2)108 684 Q -F0(is e)2.5 E -.15(xe)-.15 G(cuted if, and only if,).15 E F3(command)2.5 E F0 -(returns an e)2.5 E(xit status of zero.)-.15 E(An OR list has the form)108 -700.8 Q F3(command)144 717.6 Q F4 1.6662.5 G F3(command2).834 E F0 -185.675(GNU 1995)72 768 R(May 5)2.5 E(2)535 768 Q EP -%%Page: 3 3 -%%BeginPageSetup -BP -%%EndPageSetup -/F0 10/Times-Roman@0 SF -.35(BA)72 48 S 389.54(SH\(1\) B).35 F(ASH\(1\))-.35 E -/F1 10/Times-Italic@0 SF(command2)108 84 Q F0 .911(is e)3.411 F -.15(xe)-.15 G -.911(cuted if and only if).15 F F1(command)3.412 E F0 .912 -(returns a non\255zero e)3.412 F .912(xit status.)-.15 F .912 -(The return status of AND)5.912 F(and OR lists is the e)108 96 Q -(xit status of the last command e)-.15 E -.15(xe)-.15 G(cuted in the list.).15 -E/F2 10/Times-Bold@0 SF(Compound Commands)87 112.8 Q F0(A)108 124.8 Q F1 -(compound command)2.5 E F0(is one of the follo)2.5 E(wing:)-.25 E(\()108 141.6 -Q F1(list)A F0(\))A F1(list)144 141.6 Q F0 1.12(is e)3.62 F -.15(xe)-.15 G 1.12 -(cuted in a subshell.).15 F -1.11(Va)6.119 G 1.119(riable assignments and b) -1.11 F 1.119(uiltin commands that af)-.2 F 1.119(fect the shell')-.25 F(s)-.55 -E(en)144 153.6 Q 1.068(vironment do not remain in ef)-.4 F 1.069 -(fect after the command completes.)-.25 F 1.069(The return status is the e) -6.069 F(xit)-.15 E(status of)144 165.6 Q F1(list)2.5 E F0(.)A({)108 182.4 Q F1 -(list)2.5 E F0 2.5(;})C F1(list)3.89 E F0 .326(is simply e)2.826 F -.15(xe)-.15 -G .326(cuted in the current shell en).15 F 2.826(vironment. This)-.4 F .325 -(is kno)2.826 F .325(wn as a)-.25 F F1(gr)2.825 E .325(oup command)-.45 F F0 -5.325(.T)C(he)530.56 182.4 Q(return status is the e)144 194.4 Q(xit status of) --.15 E F1(list)2.5 E F0(.)A F2 -.25(fo)108 211.2 S(r).25 E F1(name)2.5 E F0([) -2.5 E F2(in)2.5 E F1(wor)2.5 E(d)-.37 E F0 2.5(;])C F2(do)A F1(list)2.5 E F0(;) -2.5 E F2(done)2.5 E F0 .423(The list of w)144 223.2 R .423(ords follo)-.1 F -(wing)-.25 E F2(in)2.923 E F0 .423(is e)2.923 F .423 -(xpanded, generating a list of items.)-.15 F .424(The v)5.424 F(ariable)-.25 E -F1(name)2.924 E F0 .424(is set to)2.924 F .653 -(each element of this list in turn, and)144 235.2 R F1(list)3.153 E F0 .653 -(is e)3.153 F -.15(xe)-.15 G .653(cuted each time.).15 F .653(If the)5.653 F F2 -(in)3.153 E F1(wor)3.153 E(d)-.37 E F0 .653(is omitted, the)3.153 F F2 -.25(fo) -3.153 G(r).25 E F0(command e)144 247.2 Q -.15(xe)-.15 G(cutes).15 E F1(list)2.5 -E F0(once for each positional parameter that is set \(see)2.5 E/F3 9 -/Times-Bold@0 SF -.666(PA)2.5 G(RAMETERS).666 E F0(belo)2.25 E(w\).)-.25 E F2 -(select)108 264 Q F1(name)2.5 E F0([)2.5 E F2(in)2.5 E F1(wor)2.5 E(d)-.37 E F0 -2.5(;])C F2(do)A F1(list)2.5 E F0(;)2.5 E F2(done)2.5 E F0 .432(The list of w) -144 276 R .432(ords follo)-.1 F(wing)-.25 E F2(in)2.932 E F0 .432(is e)2.932 F -.432(xpanded, generating a list of items.)-.15 F .433(The set of e)5.433 F .433 -(xpanded w)-.15 F(ords)-.1 E .843(is printed on the standard error)144 288 R -3.342(,e)-.4 G .842(ach preceded by a number)281.126 288 R 5.842(.I)-.55 G -3.342(ft)400.576 288 S(he)410.028 288 Q F2(in)3.342 E F1(wor)3.342 E(d)-.37 E -F0 .842(is omitted, the posi-)3.342 F .064(tional parameters are printed \(see) -144 300 R F3 -.666(PA)2.564 G(RAMETERS).666 E F0(belo)2.314 E 2.564(w\). The) --.25 F F2(PS3)2.564 E F0 .064(prompt is then displayed and a)2.564 F .798 -(line read from the standard input.)144 312 R .797 -(If the line consists of the number corresponding to one of the)5.798 F .951 -(displayed w)144 324 R .951(ords, then the v)-.1 F .951(alue of)-.25 F F1(name) -3.451 E F0 .952(is set to that w)3.451 F 3.452(ord. If)-.1 F .952 -(the line is empty)3.452 F 3.452(,t)-.65 G .952(he w)484.876 324 R .952 -(ords and)-.1 F .066(prompt are displayed ag)144 336 R 2.566(ain. If)-.05 F -.065(EOF is read, the command completes.)2.566 F(An)5.065 E 2.565(yo)-.15 G -.065(ther v)452.035 336 R .065(alue read causes)-.25 F F1(name)144 348 Q F0 -.809(to be set to null.)3.309 F .809(The line read is sa)5.809 F -.15(ve)-.2 G -3.31(di).15 G 3.31(nt)338.36 348 S .81(he v)349.45 348 R(ariable)-.25 E F2 -(REPL)3.31 E(Y)-.92 E F0 5.81(.T)C(he)444.86 348 Q F1(list)3.31 E F0 .81(is e) -3.31 F -.15(xe)-.15 G .81(cuted after).15 F .667(each selection until a)144 360 -R F2(br)3.167 E(eak)-.18 E F0(or)3.167 E F2 -.18(re)3.167 G(tur).18 E(n)-.15 E -F0 .667(command is e)3.167 F -.15(xe)-.15 G 3.167(cuted. The).15 F -.15(ex) -3.167 G .667(it status of).15 F F2(select)3.167 E F0 .667(is the e)3.167 F(xit) --.15 E(status of the last command e)144 372 Q -.15(xe)-.15 G(cuted in).15 E F1 -(list)2.5 E F0 2.5(,o).68 G 2.5(rz)324.09 372 S(ero if no commands were e) -334.36 372 Q -.15(xe)-.15 G(cuted.).15 E F2(case)108 388.8 Q F1(wor)2.5 E(d) --.37 E F2(in)2.5 E F0([)2.5 E F1(pattern)2.5 E F0([)2.5 E F2(|)2.5 E F1 -(pattern)2.5 E F0 2.5(].)2.5 G(.. \))249.27 388.8 Q F1(list)2.5 E F0(;; ] ...) -2.5 E F2(esac)2.5 E F0(A)144 400.8 Q F2(case)3.264 E F0 .764(command \214rst e) -3.264 F(xpands)-.15 E F1(wor)3.264 E(d)-.37 E F0 3.264(,a)C .764 -(nd tries to match it ag)303.324 400.8 R .764(ainst each)-.05 F F1(pattern) -3.264 E F0 .765(in turn, using the)3.264 F 2.028 -(same matching rules as for pathname e)144 412.8 R 2.027(xpansion \(see)-.15 F -F2 -.1(Pa)4.527 G 2.027(thname Expansion).1 F F0(belo)4.527 E 4.527(w\). When) --.25 F(a)4.527 E .89(match is found, the corresponding)144 424.8 R F1(list)3.39 -E F0 .89(is e)3.39 F -.15(xe)-.15 G 3.39(cuted. After).15 F .89 -(the \214rst match, no subsequent matches)3.39 F .308(are attempted.)144 436.8 -R .308(The e)5.308 F .307(xit status is zero if no patterns are matches.)-.15 F -.307(Otherwise, it is the e)5.307 F .307(xit status of)-.15 F -(the last command e)144 448.8 Q -.15(xe)-.15 G(cuted in).15 E F1(list)2.5 E F0 -(.)A F2(if)108 465.6 Q F1(list)2.5 E F2(then)2.5 E F1(list)2.5 E F0([)2.5 E F2 -(elif)2.5 E F1(list)2.5 E F2(then)2.5 E F1(list)2.5 E F0 2.5(].)2.5 G(.. [) -248.3 465.6 Q F2(else)2.5 E F1(list)2.5 E F0(])2.5 E F2<8c>2.5 E F0(The)144 -477.6 Q F2(if)2.534 E F1(list)2.534 E F0 .034(is e)2.534 F -.15(xe)-.15 G 2.534 -(cuted. If).15 F .034(its e)2.534 F .034(xit status is zero, the)-.15 F F2 -(then)2.534 E F1(list)2.534 E F0 .034(is e)2.534 F -.15(xe)-.15 G 2.534 -(cuted. Otherwise,).15 F(each)2.534 E F2(elif)2.534 E F1(list)2.534 E F0(is) -2.534 E -.15(exe)144 489.6 S .316(cuted in turn, and if its e).15 F .316 -(xit status is zero, the corresponding)-.15 F F2(then)2.816 E F1(list)2.816 E -F0 .316(is e)2.816 F -.15(xe)-.15 G .316(cuted and the com-).15 F .658 -(mand completes.)144 501.6 R .658(Otherwise, the)5.658 F F2(else)3.158 E F1 -(list)3.158 E F0 .658(is e)3.158 F -.15(xe)-.15 G .658(cuted, if present.).15 F -.658(The e)5.658 F .658(xit status is the e)-.15 F .659(xit status)-.15 F -(of the last command e)144 513.6 Q -.15(xe)-.15 G -(cuted, or zero if no condition tested true.).15 E F2(while)108 530.4 Q F1 -(list)2.5 E F2(do)2.5 E F1(list)2.5 E F2(done)2.5 E(until)108 542.4 Q F1(list) -2.5 E F2(do)2.5 E F1(list)2.5 E F2(done)2.5 E F0(The)144 554.4 Q F2(while)3.104 -E F0 .603(command continuously e)3.104 F -.15(xe)-.15 G .603(cutes the).15 F F2 -(do)3.103 E F1(list)3.103 E F0 .603(as long as the last command in)3.103 F F1 -(list)3.103 E F0(returns)3.103 E .47(an e)144 566.4 R .47(xit status of zero.) --.15 F(The)5.47 E F2(until)2.97 E F0 .471(command is identical to the)2.97 F F2 -(while)2.971 E F0 .471(command, e)2.971 F .471(xcept that the test)-.15 F .055 -(is ne)144 578.4 R -.05(ga)-.15 G .055(ted; the).05 F F2(do)2.555 E F1(list) -2.555 E F0 .055(is e)2.555 F -.15(xe)-.15 G .055 -(cuted as long as the last command in).15 F F1(list)2.555 E F0 .054 -(returns a non\255zero e)2.554 F .054(xit status.)-.15 F 1.306(The e)144 590.4 -R 1.306(xit status of the)-.15 F F2(while)3.806 E F0(and)3.806 E F2(until)3.807 -E F0 1.307(commands is the e)3.807 F 1.307(xit status of the last)-.15 F F2(do) -3.807 E F1(list)3.807 E F0(command)3.807 E -.15(exe)144 602.4 S -(cuted, or zero if none w).15 E(as e)-.1 E -.15(xe)-.15 G(cuted.).15 E([)108 -619.2 Q F2(function)2.5 E F0(])2.5 E F1(name)2.5 E F0(\(\) {)2.5 E F1(list)2.5 -E F0 2.5(;})C .385(This de\214nes a function named)144 631.2 R F1(name)2.884 E -F0 5.384(.T)C(he)304.616 631.2 Q F1(body)2.884 E F0 .384 -(of the function is the)2.884 F F1(list)2.884 E F0 .384(of commands between {) -2.884 F .785(and }.)144 643.2 R .785(This list is e)5.785 F -.15(xe)-.15 G .785 -(cuted whene).15 F -.15(ve)-.25 G(r).15 E F1(name)3.285 E F0 .785 -(is speci\214ed as the name of a simple command.)3.285 F(The)5.786 E -.15(ex) -144 655.2 S .64(it status of a function is the e).15 F .64 -(xit status of the last command e)-.15 F -.15(xe)-.15 G .64(cuted in the body) -.15 F 5.64(.\()-.65 G(See)494.43 655.2 Q F3(FUNC-)3.14 E(TIONS)144 667.2 Q F0 -(belo)2.25 E -.65(w.)-.25 G(\)).65 E F3(COMMENTS)72 684 Q F0 .785 -(In a non\255interacti)108 696 R 1.085 -.15(ve s)-.25 H .785 -(hell, or an interacti).15 F 1.086 -.15(ve s)-.25 H .786(hell in which the).15 -F F2 .786(-o interacti)3.286 F -.1(ve)-.1 G(\255comments).1 E F0 .786 -(option to the)3.286 F F2(set)3.286 E F0 -.2(bu)108 708 S .343 -(iltin is enabled, a w).2 F .342(ord be)-.1 F .342(ginning with)-.15 F F2(#) -2.842 E F0 .342(causes that w)2.842 F .342 -(ord and all remaining characters on that line to be)-.1 F 5.693(ignored. An) -108 720 R(interacti)5.693 E 3.493 -.15(ve s)-.25 H 3.193(hell without the).15 F -F2 3.193(-o interacti)5.693 F -.1(ve)-.1 G(\255comments).1 E F0 3.194 -(option enabled does not allo)5.693 F(w)-.25 E 185.675(GNU 1995)72 768 R(May 5) -2.5 E(3)535 768 Q EP -%%Page: 4 4 -%%BeginPageSetup -BP -%%EndPageSetup -/F0 10/Times-Roman@0 SF -.35(BA)72 48 S 389.54(SH\(1\) B).35 F(ASH\(1\))-.35 E -(comments.)108 84 Q/F1 9/Times-Bold@0 SF -.09(QU)72 100.8 S -.36(OT).09 G(ING) -.36 E/F2 10/Times-Italic@0 SF(Quoting)108 112.8 Q F0 .478(is used to remo)2.978 -F .777 -.15(ve t)-.15 H .477(he special meaning of certain characters or w).15 -F .477(ords to the shell.)-.1 F .477(Quoting can be)5.477 F .184 -(used to disable special treatment for special characters, to pre)108 124.8 R --.15(ve)-.25 G .185(nt reserv).15 F .185(ed w)-.15 F .185 -(ords from being recognized as)-.1 F(such, and to pre)108 136.8 Q -.15(ve)-.25 -G(nt parameter e).15 E(xpansion.)-.15 E .289(Each of the)108 153.6 R F2(metac) -2.789 E(har)-.15 E(acter)-.15 E(s)-.1 E F0 .288(listed abo)2.789 F .588 -.15 -(ve u)-.15 H(nder).15 E F1(DEFINITIONS)2.788 E F0 .288 -(has special meaning to the shell and must be)2.538 F .242(quoted if the)108 -165.6 R 2.742(ya)-.15 G .242(re to represent themselv)171.066 165.6 R 2.742 -(es. There)-.15 F .242(are three quoting mechanisms: the)2.742 F F2 .242 -(escape c)2.742 F(har)-.15 E(acter)-.15 E F0 2.742(,s).73 G(in-)528.89 165.6 Q -(gle quotes, and double quotes.)108 177.6 Q 2.975(An)108 194.4 S .475 -(on-quoted backslash \()123.195 194.4 R/F3 10/Times-Bold@0 SF(\\)A F0 2.974 -(\)i)C 2.974(st)223.768 194.4 S(he)233.412 194.4 Q F2 .474(escape c)2.974 F -(har)-.15 E(acter)-.15 E F0 5.474(.I).73 G 2.974(tp)326.624 194.4 S(reserv) -337.378 194.4 Q .474(es the literal v)-.15 F .474(alue of the ne)-.25 F .474 -(xt character that)-.15 F(follo)108 206.4 Q .024(ws, with the e)-.25 F .024 -(xception of . If)-.25 F(a)2.524 E F3(\\)2.524 E F0( pair appears, and the backslash is not quoted, the)-.25 F F3(\\) -108 218.4 Q F0( is treated as a line continuation \(that is, it is ef)-.25 E(fecti)-.25 -E -.15(ve)-.25 G(ly ignored\).).15 E .295 -(Enclosing characters in single quotes preserv)108 235.2 R .295 -(es the literal v)-.15 F .295(alue of each character within the quotes.)-.25 F -2.795(As)5.295 G(in-)528.89 235.2 Q -(gle quote may not occur between single quotes, e)108 247.2 Q -.15(ve)-.25 G -2.5(nw).15 G(hen preceded by a backslash.)328.67 247.2 Q .033 -(Enclosing characters in double quotes preserv)108 264 R .034(es the literal v) --.15 F .034(alue of all characters within the quotes, with the)-.25 F -.15(ex) -108 276 S 1.267(ception of).15 F F3($)3.767 E F0(,)A F3(`)3.766 E F0 3.766(,a)C -(nd)187.896 276 Q F3(\\)3.766 E F0 6.266(.T)C 1.266(he characters)219.318 276 R -F3($)3.766 E F0(and)3.766 E F3(`)3.766 E F0 1.266 -(retain their special meaning within double quotes.)3.766 F(The)6.266 E .637 -(backslash retains its special meaning only when follo)108 288 R .637 -(wed by one of the follo)-.25 F .637(wing characters:)-.25 F F3($)3.137 E F0(,) -A F3(`)3.137 E F0(,)A F3(")3.97 E F0(,).833 E F3(\\)3.137 E F0 3.137(,o)C(r) -536.67 288 Q F3()108 300 Q F0 5(.A)C(double quote may be quoted withi\ -n double quotes by preceding it with a backslash.)169.4 300 Q -(The special parameters)108 316.8 Q F3(*)2.5 E F0(and)2.5 E F3(@)2.5 E F0(ha) -2.5 E .3 -.15(ve s)-.2 H(pecial meaning when in double quotes \(see).15 E F1 --.666(PA)2.5 G(RAMETERS).666 E F0(belo)2.25 E(w\).)-.25 E F1 -.666(PA)72 333.6 -S(RAMETERS).666 E F0(A)108 345.6 Q F2(par)3.334 E(ameter)-.15 E F0 .833 -(is an entity that stores v)3.334 F .833(alues, some)-.25 F .833(what lik)-.25 -F 3.333(eav)-.1 G .833(ariable in a con)362.805 345.6 R -.15(ve)-.4 G .833 -(ntional programming lan-).15 F 2.51(guage. It)108 357.6 R .01(can be a)2.51 F -F2(name)2.51 E F0 2.51(,an).18 G(umber)222.1 357.6 Q 2.51(,o)-.4 G 2.511(ro) -257.26 357.6 S .011(ne of the special characters listed belo)268.101 357.6 R -2.511(wu)-.25 G(nder)434.828 357.6 Q F3 .011(Special P)2.511 F(arameters)-.1 E -F0(.)A -.15(Fo)108 369.6 S 2.5(rt).15 G(he shell')127.02 369.6 Q 2.5(sp)-.55 G -(urposes, a)172.02 369.6 Q F2(variable)2.5 E F0(is a parameter denoted by a)2.5 -E F2(name)2.5 E F0(.).18 E 2.755(Ap)108 386.4 S .255 -(arameter is set if it has been assigned a v)122.975 386.4 R 2.754(alue. The) --.25 F .254(null string is a v)2.754 F .254(alid v)-.25 F 2.754(alue. Once)-.25 -F 2.754(av)2.754 G .254(ariable is set, it)478.688 386.4 R -(may be unset only by using the)108 398.4 Q F3(unset)2.5 E F0 -.2(bu)2.5 G -(iltin command \(see).2 E F1(SHELL B)2.5 E(UIL)-.09 E(TIN COMMANDS)-.828 E F0 -(belo)2.25 E(w\).)-.25 E(A)108 415.2 Q F2(variable)2.5 E F0 -(may be assigned to by a statement of the form)2.5 E F2(name)144 432 Q F0(=[)A -F2(value)A F0(])A(If)108 448.8 Q F2(value)2.792 E F0 .293(is not gi)2.793 F --.15(ve)-.25 G .293(n, the v).15 F .293(ariable is assigned the null string.) --.25 F(All)5.293 E F2(values)2.793 E F0(under)2.793 E .293(go tilde e)-.18 F -.293(xpansion, parameter)-.15 F 1.314(and v)108 460.8 R 1.314(ariable e)-.25 F -1.314(xpansion, command substitution, arithmetic e)-.15 F 1.313 -(xpansion, and quote remo)-.15 F -.25(va)-.15 G 3.813(l. If).25 F 1.313(the v) -3.813 F(ariable)-.25 E .432(has its)108 472.8 R F32.932 E F0(attrib)2.932 -E .432(ute set \(see)-.2 F F3(declar)2.932 E(e)-.18 E F0(belo)2.932 E 2.932(wi) --.25 G(n)280.946 472.8 Q F1 .432(SHELL B)2.932 F(UIL)-.09 E .432(TIN COMMANDS) --.828 F/F4 9/Times-Roman@0 SF(\))A F0(then)2.682 E F2(value)2.933 E F0 .433 -(is subject to arith-)2.933 F .455(metic e)108 484.8 R .455(xpansion e)-.15 F --.15(ve)-.25 G 2.955(ni).15 G 2.955(ft)200.745 484.8 S .455 -(he $[...] syntax does not appear)209.81 484.8 R 5.455(.W)-.55 G .454 -(ord splitting is not performed, with the e)353.1 484.8 R(xcep-)-.15 E(tion of) -108 496.8 Q F3("$@")2.5 E F0(as e)2.5 E(xplained belo)-.15 E 2.5(wu)-.25 G -(nder)248.54 496.8 Q F3(Special P)2.5 E(arameters)-.1 E F0 5(.P)C(athname e) -364.1 496.8 Q(xpansion is not performed.)-.15 E F3 -.2(Po)87 513.6 S -(sitional P).2 E(arameters)-.1 E F0(A)108 525.6 Q F2 .815(positional par)3.315 -F(ameter)-.15 E F0 .816 -(is a parameter denoted by one or more digits, other than the single digit 0.) -3.315 F(Posi-)5.816 E .445(tional parameters are assigned from the shell')108 -537.6 R 2.944(sa)-.55 G -.18(rg)303.574 537.6 S .444(uments when it is in).18 F --.2(vo)-.4 G -.1(ke).2 G .444(d, and may be reassigned using).1 F(the)108 549.6 -Q F3(set)3.333 E F0 -.2(bu)3.333 G .833(iltin command.).2 F .834 -(Positional parameters may not be assigned to with assignment statements.)5.833 -F(The)5.834 E .334 -(positional parameters are temporarily replaced when a shell function is e)108 -561.6 R -.15(xe)-.15 G .333(cuted \(see).15 F F1(FUNCTIONS)2.833 E F0(belo) -2.583 E(w\).)-.25 E 1.403 -(When a positional parameter consisting of more than a single digit is e)108 -578.4 R 1.404(xpanded, it must be enclosed in)-.15 F(braces \(see)108 590.4 Q -F1(EXP)2.5 E(ANSION)-.666 E F0(belo)2.25 E(w\).)-.25 E F3(Special P)87 607.2 Q -(arameters)-.1 E F0 1.675(The shell treats se)108 619.2 R -.15(ve)-.25 G 1.675 -(ral parameters specially).15 F 6.675(.T)-.65 G 1.674 -(hese parameters may only be referenced; assignment to)306.95 619.2 R -(them is not allo)108 631.2 Q(wed.)-.25 E F3(*)108 643.2 Q F0 .605 -(Expands to the positional parameters, starting from one.)144 643.2 R .606 -(When the e)5.605 F .606(xpansion occurs within dou-)-.15 F .084 -(ble quotes, it e)144 655.2 R .084(xpands to a single w)-.15 F .084 -(ord with the v)-.1 F .084 -(alue of each parameter separated by the \214rst char)-.25 F(-)-.2 E .943 -(acter of the)144 667.2 R F1(IFS)3.444 E F0 .944(special v)3.194 F 3.444 -(ariable. That)-.25 F .944(is, `)3.444 F(`)-.74 E F3($*)A F0 2.424 -.74('' i)D -3.444(se).74 G(qui)357.352 667.2 Q -.25(va)-.25 G .944(lent to `).25 F(`)-.74 E -F3($1)A F2(c)A F3($2)A F2(c)A F3(...)A F0 -.74('')C 3.444(,w).74 G(here)470.124 -667.2 Q F2(c)3.444 E F0 .944(is the \214rst)3.444 F .583(character of the v)144 -679.2 R .583(alue of the)-.25 F F1(IFS)3.083 E F0 -.25(va)2.833 G 3.083 -(riable. If).25 F F1(IFS)3.083 E F0 .583 -(is null or unset, the parameters are separated by)2.833 F(spaces.)144 691.2 Q -F3(@)108 703.2 Q F0 .605 -(Expands to the positional parameters, starting from one.)144 703.2 R .606 -(When the e)5.605 F .606(xpansion occurs within dou-)-.15 F 1.387 -(ble quotes, each parameter e)144 715.2 R 1.386(xpands as a separate w)-.15 F -3.886(ord. That)-.1 F 1.386(is, `)3.886 F(`)-.74 E F3($@)3.886 E F0 2.866 -.74 -('' i)D 3.886(se).74 G(qui)465.888 715.2 Q -.25(va)-.25 G 1.386(lent to `).25 F -(`)-.74 E F3($1)A F0 -.74('')C -.74(``)144 727.2 S F3($2).74 E F0 1.666 -.74 -('' .)D 2.686(.. When).74 F .186(there are no positional parameters, `)2.686 F -(`)-.74 E F3($@)A F0 1.666 -.74('' a)D(nd).74 E F3($@)2.686 E F0 -.15(ex)2.686 -G .187(pand to nothing \(i.e., the).15 F 2.687(ya)-.15 G(re)532.23 727.2 Q -185.675(GNU 1995)72 768 R(May 5)2.5 E(4)535 768 Q EP -%%Page: 5 5 -%%BeginPageSetup -BP -%%EndPageSetup -/F0 10/Times-Roman@0 SF -.35(BA)72 48 S 389.54(SH\(1\) B).35 F(ASH\(1\))-.35 E -(remo)144 84 Q -.15(ve)-.15 G(d\).).15 E/F1 10/Times-Bold@0 SF(#)108 96 Q F0 -(Expands to the number of positional parameters in decimal.)144 96 Q F1(?)108 -108 Q F0(Expands to the status of the most recently e)144 108 Q -.15(xe)-.15 G -(cuted fore).15 E(ground pipeline.)-.15 E F1108 120 Q F0 .882 -(Expands to the current option \215ags as speci\214ed upon in)144 120 R -.2(vo) --.4 G .881(cation, by the).2 F F1(set)3.381 E F0 -.2(bu)3.381 G .881 -(iltin command, or).2 F(those set by the shell itself \(such as the)144 132 Q -F12.5 E F0(\215ag\).)2.5 E F1($)108 144 Q F0 .214 -(Expands to the process ID of the shell.)144 144 R .214 -(In a \(\) subshell, it e)5.214 F .214(xpands to the process ID of the current) --.15 F(shell, not the subshell.)144 156 Q F1(!)108 168 Q F0 -(Expands to the process ID of the most recently e)144 168 Q -.15(xe)-.15 G -(cuted background \(asynchronous\) command.).15 E F1(0)108 180 Q F0 1.692 -(Expands to the name of the shell or shell script.)144 180 R 1.691 -(This is set at shell initialization.)6.692 F(If)6.691 E F1(bash)4.191 E F0(is) -4.191 E(in)144 192 Q -.2(vo)-.4 G -.1(ke).2 G 3.077(dw).1 G .577 -(ith a \214le of commands,)185.817 192 R F1($0)3.077 E F0 .578 -(is set to the name of that \214le.)3.077 F(If)5.578 E F1(bash)3.078 E F0 .578 -(is started with the)3.078 F F13.078 E F0 .369(option, then)144 204 R F1 -($0)2.869 E F0 .369(is set to the \214rst ar)2.869 F .369 -(gument after the string to be e)-.18 F -.15(xe)-.15 G .369 -(cuted, if one is present.).15 F(Other)5.368 E(-)-.2 E -(wise, it is set to the pathname used to in)144 216 Q -.2(vo)-.4 G -.1(ke).2 G -F1(bash)2.6 E F0 2.5(,a)C 2.5(sg)354.13 216 S -2.15 -.25(iv e)365.52 216 T 2.5 -(nb).25 G 2.5(ya)389.84 216 S -.18(rg)401.78 216 S(ument zero.).18 E F1(_)108 -228 Q F0 .361(Expands to the last ar)144 228 R .362(gument to the pre)-.18 F -.362(vious command, after e)-.25 F 2.862(xpansion. Also)-.15 F .362 -(set to the full path-)2.862 F(name of each command e)144 240 Q -.15(xe)-.15 G -(cuted and placed in the en).15 E(vironment e)-.4 E(xported to that command.) --.15 E F1(Shell V)87 256.8 Q(ariables)-.92 E F0(The follo)108 268.8 Q(wing v) --.25 E(ariables are set by the shell:)-.25 E F1(PPID)108 285.6 Q F0 -(The process ID of the shell')144 285.6 Q 2.5(sp)-.55 G(arent.)266.2 285.6 Q F1 -(PWD)108 297.6 Q F0(The current w)144 297.6 Q(orking directory as set by the) --.1 E F1(cd)2.5 E F0(command.)2.5 E F1(OLDPWD)108 309.6 Q F0(The pre)144 321.6 -Q(vious w)-.25 E(orking directory as set by the)-.1 E F1(cd)2.5 E F0(command.) -2.5 E F1(REPL)108 333.6 Q(Y)-.92 E F0(Set to the line of input read by the)144 -345.6 Q F1 -.18(re)2.5 G(ad).18 E F0 -.2(bu)2.5 G(iltin command when no ar).2 E -(guments are supplied.)-.18 E F1(UID)108 357.6 Q F0 -(Expands to the user ID of the current user)144 357.6 Q 2.5(,i)-.4 G -(nitialized at shell startup.)318.56 357.6 Q F1(EUID)108 369.6 Q F0 -(Expands to the ef)144 369.6 Q(fecti)-.25 E .3 -.15(ve u)-.25 H -(ser ID of the current user).15 E 2.5(,i)-.4 G(nitialized at shell startup.) -355.39 369.6 Q F1 -.3(BA)108 381.6 S(SH).3 E F0 -(Expands to the full pathname used to in)9.07 E -.2(vo)-.4 G .2 -.1(ke t).2 H -(his instance of).1 E F1(bash)2.5 E F0(.)A F1 -.3(BA)108 393.6 S(SH_VERSION).3 -E F0(Expands to the v)144 405.6 Q(ersion number of this instance of)-.15 E F1 -(bash)2.5 E F0(.)A F1(SHL)108 417.6 Q(VL)-.92 E F0 -(Incremented by one each time an instance of)144 429.6 Q F1(bash)2.5 E F0 -(is started.)2.5 E F1(RANDOM)108 441.6 Q F0 .944 -(Each time this parameter is referenced, a random inte)144 453.6 R .943 -(ger is generated.)-.15 F .943(The sequence of random)5.943 F .91 -(numbers may be initialized by assigning a v)144 465.6 R .91(alue to)-.25 F/F2 -9/Times-Bold@0 SF(RANDOM)3.41 E/F3 9/Times-Roman@0 SF(.)A F0(If)5.41 E F2 -(RANDOM)3.41 E F0 .91(is unset, it loses its)3.16 F(special properties, e)144 -477.6 Q -.15(ve)-.25 G 2.5(ni).15 G 2.5(fi)243.02 477.6 S 2.5(ti)251.63 477.6 S -2.5(ss)259.69 477.6 S(ubsequently reset.)269.97 477.6 Q F1(SECONDS)108 489.6 Q -F0 .795 -(Each time this parameter is referenced, the number of seconds since shell in) -144 501.6 R -.2(vo)-.4 G .795(cation is returned.).2 F .712(If a v)144 513.6 R -.712(alue is assigned to)-.25 F F2(SECONDS)3.212 E F3(,)A F0 .712(the v)2.962 F -.712(alue returned upon subsequent references is the number)-.25 F .408 -(of seconds since the assignment plus the v)144 525.6 R .408(alue assigned.) --.25 F(If)5.408 E F2(SECONDS)2.908 E F0 .407(is unset, it loses its special) -2.658 F(properties, e)144 537.6 Q -.15(ve)-.25 G 2.5(ni).15 G 2.5(fi)212.75 -537.6 S 2.5(ti)221.36 537.6 S 2.5(ss)229.42 537.6 S(ubsequently reset.)239.7 -537.6 Q F1(LINENO)108 549.6 Q F0 1.408(Each time this parameter is referenced,\ - the shell substitutes a decimal number representing the)144 561.6 R .078(curr\ -ent sequential line number \(starting with 1\) within a script or function.)144 -573.6 R .078(When not in a script or)5.078 F .603(function, the v)144 585.6 R -.603(alue substituted is not guaranteed to be meaningful.)-.25 F .604 -(When in a function, the v)5.603 F(alue)-.25 E .601(is not the number of the s\ -ource line that the command appears on \(that information has been lost)144 -597.6 R .461(by the time the function is e)144 609.6 R -.15(xe)-.15 G .461 -(cuted\), b).15 F .461(ut is an approximation of the number of)-.2 F/F4 10 -/Times-Italic@0 SF .462(simple commands)2.962 F F0 -.15(exe)144 621.6 S 1.02 -(cuted in the current function.).15 F(If)6.019 E F2(LINENO)3.519 E F0 1.019 -(is unset, it loses its special properties, e)3.269 F -.15(ve)-.25 G 3.519(ni) -.15 G 3.519(fi)517.402 621.6 S 3.519(ti)527.031 621.6 S(s)536.11 621.6 Q -(subsequently reset.)144 633.6 Q F1(HISTCMD)108 645.6 Q F0 .355 -(The history number)144 657.6 R 2.855(,o)-.4 G 2.855(ri)233.545 657.6 S(nde) -242.51 657.6 Q 2.856(xi)-.15 G 2.856(nt)267.436 657.6 S .356 -(he history list, of the current command.)278.072 657.6 R(If)5.356 E F2 -(HISTCMD)2.856 E F0 .356(is unset, it)2.606 F(loses its special properties, e) -144 669.6 Q -.15(ve)-.25 G 2.5(ni).15 G 2.5(fi)277.47 669.6 S 2.5(ti)286.08 -669.6 S 2.5(ss)294.14 669.6 S(ubsequently reset.)304.42 669.6 Q F1(OPT)108 -681.6 Q(ARG)-.9 E F0 1.627(The v)144 693.6 R 1.627(alue of the last option ar) --.25 F 1.627(gument processed by the)-.18 F F1(getopts)4.127 E F0 -.2(bu)4.127 -G 1.626(iltin command \(see).2 F F2(SHELL)4.126 E -.09(BU)144 705.6 S(IL).09 E -(TIN COMMANDS)-.828 E F0(belo)2.25 E(w\).)-.25 E 185.675(GNU 1995)72 768 R -(May 5)2.5 E(5)535 768 Q EP -%%Page: 6 6 -%%BeginPageSetup -BP -%%EndPageSetup -/F0 10/Times-Roman@0 SF -.35(BA)72 48 S 389.54(SH\(1\) B).35 F(ASH\(1\))-.35 E -/F1 10/Times-Bold@0 SF(OPTIND)108 84 Q F0 1.651(The inde)144 96 R 4.151(xo)-.15 -G 4.151(ft)194.922 96 S 1.651(he ne)205.183 96 R 1.651(xt ar)-.15 F 1.652 -(gument to be processed by the)-.18 F F1(getopts)4.152 E F0 -.2(bu)4.152 G -1.652(iltin command \(see).2 F/F2 9/Times-Bold@0 SF(SHELL)4.152 E -.09(BU)144 -108 S(IL).09 E(TIN COMMANDS)-.828 E F0(belo)2.25 E(w\).)-.25 E F1(HOSTTYPE)108 -120 Q F0 .223(Automatically set to a string that uniquely describes the type o\ -f machine on which)144 132 R F1(bash)2.722 E F0 .222(is e)2.722 F -.15(xe)-.15 -G(cut-).15 E 2.5(ing. The)144 144 R(def)2.5 E(ault is system-dependent.)-.1 E -F1(OSTYPE)108 156 Q F0 .329 -(Automatically set to a string that describes the operating system on which)144 -168 R F1(bash)2.83 E F0 .33(is e)2.83 F -.15(xe)-.15 G 2.83(cuting. The).15 F -(def)144 180 Q(ault is system-dependent.)-.1 E .994(The follo)108 196.8 R .994 -(wing v)-.25 F .994(ariables are used by the shell.)-.25 F .994(In some cases,) -5.994 F F1(bash)3.494 E F0 .994(assigns a def)3.494 F .994(ault v)-.1 F .993 -(alue to a v)-.25 F(ariable;)-.25 E(these cases are noted belo)108 208.8 Q -.65 -(w.)-.25 G F1(IFS)108 225.6 Q F0(The)144 225.6 Q/F3 10/Times-Italic@0 SF .637 -(Internal F)3.137 F .637(ield Separ)-.45 F(ator)-.15 E F0 .637 -(that is used for w)3.137 F .638(ord splitting after e)-.1 F .638 -(xpansion and to split lines into)-.15 F -.1(wo)144 237.6 S(rds with the).1 E -F1 -.18(re)2.5 G(ad).18 E F0 -.2(bu)2.5 G(iltin command.).2 E(The def)5 E -(ault v)-.1 E(alue is `)-.25 E(`')-.25 E('.)-.74 E -F1 -.74(PA)108 249.6 S(TH)-.21 E F0 .588(The search path for commands.)9.91 F -.587(It is a colon-separated list of directories in which the shell looks)5.588 -F .211(for commands \(see)144 261.6 R F2 .212(COMMAND EXECUTION)2.712 F F0 -(belo)2.462 E 2.712(w\). The)-.25 F(def)2.712 E .212 -(ault path is system\255dependent, and)-.1 F 12.209 -(is set by the administrator who installs)144 273.6 R F1(bash)385.854 273.6 Q -F0 17.209(.A)C 12.209(common v)447.502 273.6 R 12.209(alue is)-.25 F -.74(``) -144 285.6 S(/usr/gnu/bin:/usr/local/bin:/usr/ucb:/bin:/usr/bin:.).74 E -.74('') --.7 G(.).74 E F1(HOME)108 297.6 Q F0 -(The home directory of the current user; the def)144 309.6 Q(ault ar)-.1 E -(gument for the)-.18 E F1(cd)2.5 E F0 -.2(bu)2.5 G(iltin command.).2 E F1(CDP) -108 321.6 Q -.95(AT)-.74 G(H).95 E F0 1.247(The search path for the)144 333.6 R -F1(cd)3.747 E F0 3.747(command. This)3.747 F 1.248 -(is a colon-separated list of directories in which the)3.747 F -(shell looks for destination directories speci\214ed by the)144 345.6 Q F1(cd) -2.5 E F0 2.5(command. A)2.5 F(sample v)2.5 E(alue is `)-.25 E(`.:~:/usr')-.74 E -('.)-.74 E F1(ENV)108 357.6 Q F0 .506(If this parameter is set when)144 357.6 R -F1(bash)3.006 E F0 .506(is e)3.006 F -.15(xe)-.15 G .505 -(cuting a shell script, its v).15 F .505(alue is interpreted as a \214lename) --.25 F 1.968(containing commands to initialize the shell, as in)144 369.6 R F3 -(.bashr)4.469 E(c)-.37 E F0 6.969(.T).31 G 1.969(he v)403.037 369.6 R 1.969 -(alue of)-.25 F F2(ENV)4.469 E F0 1.969(is subjected to)4.219 F .47 -(parameter e)144 381.6 R .47(xpansion, command substitution, and arithmetic e) --.15 F .47(xpansion before being interpreted as)-.15 F 2.5(ap)144 393.6 S -(athname.)155.94 393.6 Q F2 -.666(PA)5 G(TH)-.189 E F0 -(is not used to search for the resultant pathname.)2.25 E F1(MAIL)108 405.6 Q -F0 .336(If this parameter is set to a \214lename and the)8.78 F F2(MAILP)2.837 -E -.855(AT)-.666 G(H).855 E F0 -.25(va)2.587 G .337(riable is not set,).25 F F1 -(bash)2.837 E F0 .337(informs the user)2.837 F(of the arri)144 417.6 Q -.25(va) --.25 G 2.5(lo).25 G 2.5(fm)202.65 417.6 S(ail in the speci\214ed \214le.)216.26 -417.6 Q F1(MAILCHECK)108 429.6 Q F0 .099(Speci\214es ho)144 441.6 R 2.599(wo) --.25 G .099(ften \(in seconds\))207.278 441.6 R F1(bash)2.598 E F0 .098 -(checks for mail.)2.598 F .098(The def)5.098 F .098(ault is 60 seconds.)-.1 F -.098(When it is time)5.098 F .779 -(to check for mail, the shell does so before prompting.)144 453.6 R .779 -(If this v)5.779 F .779(ariable is unset, the shell disables)-.25 F -(mail checking.)144 465.6 Q F1(MAILP)108 477.6 Q -.95(AT)-.74 G(H).95 E F0 -3.512(Ac)144 489.6 S 1.012(olon-separated list of pathnames to be check)159.172 -489.6 R 1.011(ed for mail.)-.1 F 1.011(The message to be printed may be)6.011 F -.635(speci\214ed by separating the pathname from the message with a `?'.)144 -501.6 R .636($_ stands for the name of the)5.635 F(current mail\214le.)144 -513.6 Q(Example:)5 E F1(MAILP)144 525.6 Q -.95(AT)-.74 G(H).95 E F0 -(='/usr/spool/mail/bfox?"Y)A(ou ha)-1.1 E .3 -.15(ve m)-.2 H -(ail":~/shell-mail?"$_ has mail!"').15 E F1(Bash)144 537.6 Q F0 .389 -(supplies a def)2.889 F .389(ault v)-.1 F .389(alue for this v)-.25 F .389 -(ariable, b)-.25 F .388 -(ut the location of the user mail \214les that it uses is)-.2 F -(system dependent \(e.g., /usr/spool/mail/)144 549.6 Q F1($USER)A F0(\).)A F1 -(MAIL_W)108 561.6 Q(ARNING)-1.2 E F0 1.932(If set, and a \214le that)144 573.6 -R F1(bash)4.432 E F0 1.932 -(is checking for mail has been accessed since the last time it w)4.432 F(as)-.1 -E(check)144 585.6 Q(ed, the message `)-.1 E(`The mail in)-.74 E F3(mail\214le) -2.5 E F0(has been read')2.5 E 2.5('i)-.74 G 2.5(sp)385.41 585.6 S(rinted.)396.8 -585.6 Q F1(PS1)108 597.6 Q F0 .065(The v)144 597.6 R .065 -(alue of this parameter is e)-.25 F .065(xpanded \(see)-.15 F F2(PR)2.565 E -(OMPTING)-.27 E F0(belo)2.315 E .065(w\) and used as the primary prompt)-.25 F -2.5(string. The)144 609.6 R(def)2.5 E(ault v)-.1 E(alue is `)-.25 E(`)-.74 E F1 -(bash\\$)A F0 -.74('')2.5 G(.).74 E F1(PS2)108 621.6 Q F0 .688(The v)144 621.6 -R .688(alue of this parameter is e)-.25 F .689 -(xpanded and used as the secondary prompt string.)-.15 F .689(The def)5.689 F -.689(ault is)-.1 F -.74(``)144 633.6 S F1(>).74 E F0 -.74('')2.5 G(.).74 E F1 -(PS3)108 645.6 Q F0 1.15(The v)144 645.6 R 1.15 -(alue of this parameter is used as the prompt for the)-.25 F F3(select)3.649 E -F0 1.149(command \(see)3.649 F F2 1.149(SHELL GRAM-)3.649 F(MAR)144 657.6 Q F0 -(abo)2.25 E -.15(ve)-.15 G(\).).15 E F1(PS4)108 669.6 Q F0 .628(The v)144 669.6 -R .628(alue of this parameter is e)-.25 F .629(xpanded and the v)-.15 F .629 -(alue is printed before each command)-.25 F F1(bash)3.129 E F0(dis-)3.129 E -.702(plays during an e)144 681.6 R -.15(xe)-.15 G .701(cution trace.).15 F .701 -(The \214rst character of)5.701 F F2(PS4)3.201 E F0 .701 -(is replicated multiple times, as neces-)2.951 F(sary)144 693.6 Q 2.5(,t)-.65 G -2.5(oi)167.79 693.6 S(ndicate multiple le)178.07 693.6 Q -.15(ve)-.25 G -(ls of indirection.).15 E(The def)5 E(ault is `)-.1 E(`)-.74 E F1(+)A F0 -.74 -('')2.5 G(.).74 E F1(HISTSIZE)108 705.6 Q F0 1.942 -(The number of commands to remember in the command history \(see)144 717.6 R F2 -(HIST)4.443 E(OR)-.162 E(Y)-.315 E F0(belo)4.193 E 4.443(w\). The)-.25 F(def) -144 729.6 Q(ault v)-.1 E(alue is 500.)-.25 E 185.675(GNU 1995)72 768 R(May 5) -2.5 E(6)535 768 Q EP -%%Page: 7 7 -%%BeginPageSetup -BP -%%EndPageSetup -/F0 10/Times-Roman@0 SF -.35(BA)72 48 S 389.54(SH\(1\) B).35 F(ASH\(1\))-.35 E -/F1 10/Times-Bold@0 SF(HISTFILE)108 84 Q F0 1.386 -(The name of the \214le in which command history is sa)144 96 R -.15(ve)-.2 G -3.886(d. \(See).15 F/F2 9/Times-Bold@0 SF(HIST)3.886 E(OR)-.162 E(Y)-.315 E F0 -(belo)3.636 E -.65(w.)-.25 G 6.386(\)T).65 G 1.385(he def)499.005 96 R(ault)-.1 -E -.25(va)144 108 S .034(lue is).25 F/F3 10/Times-Italic@0 SF(~/.bash_history) -2.534 E F0 5.034(.I)C 2.534(fu)248.292 108 S .035 -(nset, the command history is not sa)259.156 108 R -.15(ve)-.2 G 2.535(dw).15 G -.035(hen an interacti)424.04 108 R .335 -.15(ve s)-.25 H .035(hell e).15 F -(xits.)-.15 E F1(HISTFILESIZE)108 120 Q F0 1.623 -(The maximum number of lines contained in the history \214le.)144 132 R 1.622 -(When this v)6.623 F 1.622(ariable is assigned a)-.25 F -.25(va)144 144 S .311 -(lue, the history \214le is truncated, if necessary).25 F 2.811(,t)-.65 G 2.811 -(oc)339.168 144 S .311(ontain no more than that number of lines.)351.419 144 R -(The)5.312 E(def)144 156 Q(ault v)-.1 E(alue is 500.)-.25 E F1(OPTERR)108 168 Q -F0 .39(If set to the v)144 180 R .39(alue 1,)-.25 F F1(bash)2.89 E F0 .389 -(displays error messages generated by the)2.889 F F1(getopts)2.889 E F0 -.2(bu) -2.889 G .389(iltin command \(see).2 F F2 .359(SHELL B)144 192 R(UIL)-.09 E .359 -(TIN COMMANDS)-.828 F F0(belo)2.609 E(w\).)-.25 E F2(OPTERR)5.359 E F0 .36 -(is initialized to 1 each time the shell is in)2.609 F -.2(vo)-.4 G -.1(ke).2 G -(d).1 E(or a shell script is e)144 204 Q -.15(xe)-.15 G(cuted.).15 E F1(PR)108 -216 Q(OMPT_COMMAND)-.3 E F0(If set, the v)144 228 Q(alue is e)-.25 E -.15(xe) --.15 G(cuted as a command prior to issuing each primary prompt.).15 E F1 -(IGNOREEOF)108 240 Q F0 .14(Controls the action of the shell on receipt of an) -144 252 R F2(EOF)2.639 E F0 .139(character as the sole input.)2.389 F .139 -(If set, the v)5.139 F .139(alue is)-.25 F 1.493(the number of consecuti)144 -264 R -.15(ve)-.25 G F2(EOF)4.143 E F0 1.494 -(characters typed as the \214rst characters on an input line before)3.744 F F1 -(bash)144 276 Q F0 -.15(ex)3.333 G 3.333(its. If).15 F .833(the v)3.333 F .832 -(ariable e)-.25 F .832(xists b)-.15 F .832(ut does not ha)-.2 F 1.132 -.15 -(ve a n)-.2 H .832(umeric v).15 F .832(alue, or has no v)-.25 F .832 -(alue, the def)-.25 F(ault)-.1 E -.25(va)144 288 S .585(lue is 10.).25 F .585 -(If it does not e)5.585 F(xist,)-.15 E F2(EOF)3.085 E F0 .586 -(signi\214es the end of input to the shell.)2.835 F .586(This is only in ef) -5.586 F(fect)-.25 E(for interacti)144 300 Q .3 -.15(ve s)-.25 H(hells.).15 E F1 -(TMOUT)108 312 Q F0 1.113(If set to a v)144 324 R 1.113 -(alue greater than zero, the v)-.25 F 1.112 -(alue is interpreted as the number of seconds to w)-.25 F 1.112(ait for)-.1 F -.558(input after issuing the primary prompt.)144 336 R F1(Bash)5.558 E F0 .558 -(terminates after w)3.058 F .558(aiting for that number of seconds)-.1 F -(if input does not arri)144 348 Q -.15(ve)-.25 G(.).15 E F1(FCEDIT)108 360 Q F0 -(The def)144 372 Q(ault editor for the)-.1 E F1(fc)2.5 E F0 -.2(bu)2.5 G -(iltin command.).2 E F1(FIGNORE)108 384 Q F0 2.599(Ac)144 396 S .098 -(olon-separated list of suf)158.259 396 R<8c78>-.25 E .098 -(es to ignore when performing \214lename completion \(see)-.15 F F2(READLINE) -2.598 E F0(belo)144 408 Q 2.704(w\). A)-.25 F .204(\214lename whose suf)2.704 F -.205(\214x matches one of the entries in)-.25 F F2(FIGNORE)2.705 E F0 .205 -(is e)2.455 F .205(xcluded from the list)-.15 F(of matched \214lenames.)144 420 -Q 2.5(As)5 G(ample v)250.65 420 Q(alue is `)-.25 E(`.o:~')-.74 E('.)-.74 E F1 -(INPUTRC)108 432 Q F0 1.637(The \214lename for the readline startup \214le, o) -144 444 R -.15(ve)-.15 G 1.637(rriding the def).15 F 1.636(ault of)-.1 F F3 -(~/.inputr)5.802 E(c)-.37 E F0(\(see)5.802 E F2(READLINE)4.136 E F0(belo)144 -456 Q(w\).)-.25 E F1(notify)108 468 Q F0 .031(If set,)144 468 R F1(bash)2.531 E -F0 .031(reports terminated background jobs immediately)2.531 F 2.532(,r)-.65 G -.032(ather than w)394.13 468 R .032(aiting until before print-)-.1 F -(ing the ne)144 480 Q(xt primary prompt \(see also the)-.15 E F12.5 E F0 -(option to the)2.5 E F1(set)2.5 E F0 -.2(bu)2.5 G(iltin command\).).2 E F1 -(history_contr)108 492 Q(ol)-.18 E(HISTCONTR)108 504 Q(OL)-.3 E F0 .881 -(If set to a v)144 516 R .881(alue of)-.25 F F3(ignor)3.381 E(espace)-.37 E F0 -3.381(,l).18 G .881(ines which be)281.367 516 R .881(gin with a)-.15 F F1 -(space)3.38 E F0 .88(character are not entered on the)3.38 F .401 -(history list.)144 528 R .401(If set to a v)5.401 F .401(alue of)-.25 F F3 -(ignor)2.901 E(edups)-.37 E F0 2.901(,l).27 G .401 -(ines matching the last history line are not entered.)325.029 528 R(A)5.402 E --.25(va)144 540 S 1.304(lue of).25 F F3(ignor)3.804 E(eboth)-.37 E F0 1.304 -(combines the tw)3.804 F 3.804(oo)-.1 G 3.804(ptions. If)310.534 540 R 1.303 -(unset, or if set to an)3.804 F 3.803(yo)-.15 G 1.303(ther v)453.301 540 R -1.303(alue than those)-.25 F(abo)144 552 Q -.15(ve)-.15 G 2.5(,a).15 G -(ll lines read by the parser are sa)177.02 552 Q -.15(ve)-.2 G 2.5(do).15 G 2.5 -(nt)324.96 552 S(he history list.)335.24 552 Q F1(command_oriented_history)108 -568.8 Q F0 .472(If set,)144 580.8 R F1(bash)2.973 E F0 .473(attempts to sa) -2.973 F .773 -.15(ve a)-.2 H .473 -(ll lines of a multiple\255line command in the same history entry).15 F 5.473 -(.T)-.65 G(his)528.33 580.8 Q(allo)144 592.8 Q -(ws easy re\255editing of multi\255line commands.)-.25 E F1 -(glob_dot_\214lenames)108 609.6 Q F0(If set,)144 621.6 Q F1(bash)2.5 E F0 -(includes \214lenames be)2.5 E(ginning with a `.)-.15 E 2.5('i)-.7 G 2.5(nt) -351.75 621.6 S(he results of pathname e)362.03 621.6 Q(xpansion.)-.15 E F1 -(allo)108 638.4 Q(w_null_glob_expansion)-.1 E F0 .652(If set,)144 650.4 R F1 -(bash)3.152 E F0(allo)3.152 E .651 -(ws pathname patterns which match no \214les \(see)-.25 F F1 -.1(Pa)3.151 G -.651(thname Expansion).1 F F0(belo)3.151 E .651(w\) to)-.25 F -.15(ex)144 662.4 -S(pand to a null string, rather than themselv).15 E(es.)-.15 E F1(histchars)108 -679.2 Q F0 2.069(The tw)144 691.2 R 4.57(oo)-.1 G 4.57(rt)188.589 691.2 S 2.07 -(hree characters which control history e)199.269 691.2 R 2.07(xpansion and tok) --.15 F 2.07(enization \(see)-.1 F F2(HIST)4.57 E(OR)-.162 E(Y)-.315 E(EXP)144 -703.2 Q(ANSION)-.666 E F0(belo)2.965 E 3.215(w\). The)-.25 F .714 -(\214rst character is the)3.215 F F3 .714(history e)3.214 F .714(xpansion c)-.2 -F(har)-.15 E(acter)-.15 E F0 3.214(,t).73 G .714(hat is, the character)460.108 -703.2 R .141(which signals the start of a history e)144 715.2 R .141 -(xpansion, normally `)-.15 F F1(!)A F0 2.641('. The)B .142 -(second character is the)2.641 F F3(quic)2.642 E 2.642(ks)-.2 G(ub-)526.67 -715.2 Q(stitution)144 727.2 Q F0(character)4.635 E 4.635(,w)-.4 G 2.134 -(hich is used as shorthand for re-running the pre)232.02 727.2 R 2.134 -(vious command entered,)-.25 F 185.675(GNU 1995)72 768 R(May 5)2.5 E(7)535 768 -Q EP -%%Page: 8 8 -%%BeginPageSetup -BP -%%EndPageSetup -/F0 10/Times-Roman@0 SF -.35(BA)72 48 S 389.54(SH\(1\) B).35 F(ASH\(1\))-.35 E -.466(substituting one string for another in the command.)144 84 R .466(The def) -5.466 F .466(ault is `)-.1 F/F1 10/Times-Bold@0 SF(^)A F0 2.966('. The)B .466 -(optional third charac-)2.966 F .414(ter is the character which signi\214es th\ -at the remainder of the line is a comment, when found as the)144 96 R .389 -(\214rst character of a w)144 108 R .389(ord, normally `)-.1 F F1(#)A F0 2.889 -('. The)B .39(history comment character causes history substitution)2.889 F .25 -(to be skipped for the remaining w)144 120 R .25(ords on the line.)-.1 F .25 -(It does not necessarily cause the shell parser to)5.25 F -(treat the rest of the line as a comment.)144 132 Q F1(nolinks)108 148.8 Q F0 -.44(If set, the shell does not follo)144 160.8 R 2.94(ws)-.25 G .44 -(ymbolic links when e)276.82 160.8 R -.15(xe)-.15 G .44 -(cuting commands that change the current).15 F -.1(wo)144 172.8 S .981 -(rking directory).1 F 5.981(.I)-.65 G 3.481(tu)227.972 172.8 S .981(ses the ph) -239.233 172.8 R .981(ysical directory structure instead.)-.05 F .981(By def) -5.981 F(ault,)-.1 E F1(bash)3.48 E F0(follo)3.48 E .98(ws the)-.25 F .585(logi\ -cal chain of directories when performing commands which change the current dir\ -ectory)144 184.8 R 3.085(,s)-.65 G(uch)525.56 184.8 Q(as)144 196.8 Q F1(cd)2.65 -E F0 5.15(.S)C .149(ee also the description of the)178.19 196.8 R F12.649 -E F0 .149(option to the)2.649 F F1(set)2.649 E F0 -.2(bu)2.649 G .149(iltin \() -.2 F/F2 9/Times-Bold@0 SF .149(SHELL B)2.649 F(UIL)-.09 E .149(TIN COMMANDS) --.828 F F0(belo)144 208.8 Q(w\).)-.25 E F1(hostname_completion_\214le)108 220.8 -Q(HOSTFILE)108 232.8 Q F0 1.015 -(Contains the name of a \214le in the same format as)144 244.8 R/F3 10 -/Times-Italic@0 SF(/etc/hosts)5.181 E F0 1.015 -(that should be read when the shell)5.181 F 1.425 -(needs to complete a hostname.)144 256.8 R 1.424 -(The \214le may be changed interacti)6.424 F -.15(ve)-.25 G 1.424(ly; the ne) -.15 F 1.424(xt time hostname)-.15 F(completion is attempted)144 268.8 Q F1 -(bash)2.5 E F0(adds the contents of the ne)2.5 E 2.5<778c>-.25 G -(le to the already e)386.52 268.8 Q(xisting database.)-.15 E F1(noclob)108 -285.6 Q(ber)-.1 E F0 .38(If set,)144 297.6 R F1(bash)2.88 E F0 .38(does not o) -2.88 F -.15(ve)-.15 G .38(rwrite an e).15 F .381(xisting \214le with the)-.15 F -F1(>)2.881 E F0(,)A F1(>&)2.881 E F0 2.881(,a)C(nd)403.766 297.6 Q F1(<>)2.881 -E F0 .381(redirection operators.)2.881 F(This)5.381 E -.25(va)144 309.6 S .465 -(riable may be o).25 F -.15(ve)-.15 G .464 -(rridden when creating output \214les by using the redirection operator).15 F -F1(>|)2.964 E F0(instead)2.964 E(of)144 321.6 Q F1(>)2.5 E F0(\(see also the) -2.5 E F12.5 E F0(option to the)2.5 E F1(set)2.5 E F0 -.2(bu)2.5 G -(iltin command\).).2 E F1(auto_r)108 338.4 Q(esume)-.18 E F0 .53(This v)144 -350.4 R .53(ariable controls ho)-.25 F 3.03(wt)-.25 G .531 -(he shell interacts with the user and job control.)257.83 350.4 R .531 -(If this v)5.531 F .531(ariable is set,)-.25 F .539(single w)144 362.4 R .538(\ -ord simple commands without redirections are treated as candidates for resumpt\ -ion of an)-.1 F -.15(ex)144 374.4 S .366(isting stopped job).15 F 5.366(.T)-.4 -G .366(here is no ambiguity allo)238.718 374.4 R .366 -(wed; if there is more than one job be)-.25 F .367(ginning with)-.15 F 1.157 -(the string typed, the job most recently accessed is selected.)144 386.4 R(The) -6.156 E F3(name)3.656 E F0 1.156(of a stopped job, in this)3.656 F(conte)144 -398.4 Q 1.132(xt, is the command line used to start it.)-.15 F 1.133 -(If set to the v)6.133 F(alue)-.25 E F3 -.2(ex)3.633 G(act).2 E F0 3.633(,t).68 -G 1.133(he string supplied must)443.541 398.4 R .625 -(match the name of a stopped job e)144 410.4 R .624(xactly; if set to)-.15 F F3 -(substring)3.124 E F0 3.124(,t).22 G .624(he string supplied needs to match a) -395.716 410.4 R .924(substring of the name of a stopped job)144 422.4 R 5.924 -(.T)-.4 G(he)317.642 422.4 Q F3(substring)3.424 E F0 -.25(va)3.424 G .925 -(lue pro).25 F .925(vides functionality analogous to)-.15 F(the)144 434.4 Q F1 -(%?)2.545 E F0 .045(job id \(see)5.045 F F2 .044(JOB CONTR)2.545 F(OL)-.27 E F0 -(belo)2.294 E 2.544(w\). If)-.25 F .044(set to an)2.544 F 2.544(yo)-.15 G .044 -(ther v)380.512 434.4 R .044(alue, the supplied string must be a)-.25 F -(pre\214x of a stopped job')144 446.4 Q 2.5(sn)-.55 G(ame; this pro)248.16 -446.4 Q(vides functionality analogous to the)-.15 E F1(%)2.5 E F0(job id.)2.5 E -F1(no_exit_on_failed_exec)108 463.2 Q F0 .69(If this v)144 475.2 R .69 -(ariable e)-.25 F .69(xists, a non-interacti)-.15 F .99 -.15(ve s)-.25 H .691 -(hell will not e).15 F .691(xit if it cannot e)-.15 F -.15(xe)-.15 G .691 -(cute the \214le speci\214ed in).15 F(the)144 487.2 Q F1(exec)2.5 E F0 -.2(bu) -2.5 G(iltin command.).2 E(An interacti)5 E .3 -.15(ve s)-.25 H(hell does not e) -.15 E(xit if)-.15 E F1(exec)2.5 E F0 -.1(fa)2.5 G(ils.).1 E F1(cdable_v)108 504 -Q(ars)-.1 E F0 .834(If this is set, an ar)144 516 R .834(gument to the)-.18 F -F1(cd)3.334 E F0 -.2(bu)3.334 G .834 -(iltin command that is not a directory is assumed to be the).2 F(name of a v) -144 528 Q(ariable whose v)-.25 E(alue is the directory to change to.)-.25 E F2 -(EXP)72 544.8 Q(ANSION)-.666 E F0 .76 -(Expansion is performed on the command line after it has been split into w)108 -556.8 R 3.26(ords. There)-.1 F .76(are se)3.26 F -.15(ve)-.25 G 3.26(nk).15 G -.76(inds of)511.74 556.8 R -.15(ex)108 568.8 S .37(pansion performed:).15 F F3 -(br)2.869 E .369(ace e)-.15 F(xpansion)-.2 E F0(,).24 E F3 .369(tilde e)2.869 F -(xpansion)-.2 E F0(,).24 E F3(par)2.869 E .369(ameter and variable e)-.15 F -(xpansion)-.2 E F0(,).24 E F3 .369(command sub-)2.869 F(stitution)108 580.8 Q -F0(,).24 E F3(arithmetic e)2.5 E(xpansion)-.2 E F0(,).24 E F3(wor)2.5 E 2.5(ds) --.37 G(plitting)261.81 580.8 Q F0 2.5(,a).22 G(nd)300.37 580.8 Q F3(pathname e) -2.5 E(xpansion)-.2 E F0(.).24 E .16(The order of e)108 597.6 R .16 -(xpansions is: brace e)-.15 F .16(xpansion, tilde e)-.15 F .16 -(xpansion, parameter)-.15 F 2.66(,v)-.4 G .16(ariable, command, and arithmetic) -405.38 597.6 R(substitution \(done in a left\255to\255right f)108 609.6 Q -(ashion\), w)-.1 E(ord splitting, and pathname e)-.1 E(xpansion.)-.15 E -(On systems that can support it, there is an additional e)108 626.4 Q -(xpansion a)-.15 E -.25(va)-.2 G(ilable:).25 E F3(pr)2.5 E(ocess substitution) --.45 E F0(.)A 1.487(Only brace e)108 643.2 R 1.487(xpansion, w)-.15 F 1.487 -(ord splitting, and pathname e)-.1 F 1.487(xpansion can change the number of w) --.15 F 1.486(ords of the)-.1 F -.15(ex)108 655.2 S 1.36(pansion; other e).15 F -1.36(xpansions e)-.15 F 1.36(xpand a single w)-.15 F 1.36(ord to a single w)-.1 -F 3.86(ord. The)-.1 F 1.36(single e)3.86 F 1.36(xception to this is the)-.15 F --.15(ex)108 667.2 S(pansion of `).15 E(`)-.74 E F1($@)A F0 1.48 -.74('' a)D 2.5 -(se).74 G(xplained abo)205.49 667.2 Q .3 -.15(ve \()-.15 H(see).15 E F2 -.666 -(PA)2.5 G(RAMETERS).666 E/F4 9/Times-Roman@0 SF(\).)A F1(Brace Expansion)87 684 -Q F3(Br)108 696 Q .661(ace e)-.15 F(xpansion)-.2 E F0 .661 -(is a mechanism by which arbitrary strings may be generated.)3.161 F .66 -(This mechanism is similar)5.66 F(to)108 708 Q F3 .415(pathname e)2.915 F -(xpansion)-.2 E F0 2.915(,b)C .415(ut the \214lenames generated need not e) -211.615 708 R 2.915(xist. P)-.15 F .415(atterns to be brace e)-.15 F .415 -(xpanded tak)-.15 F 2.915(et)-.1 G(he)530.56 708 Q .889(form of an optional)108 -720 R F3(pr)3.388 E(eamble)-.37 E F0 3.388(,f).18 G(ollo)238.342 720 Q .888 -(wed by a series of comma-separated strings between a pair of braces,)-.25 F -185.675(GNU 1995)72 768 R(May 5)2.5 E(8)535 768 Q EP -%%Page: 9 9 -%%BeginPageSetup -BP -%%EndPageSetup -/F0 10/Times-Roman@0 SF -.35(BA)72 48 S 389.54(SH\(1\) B).35 F(ASH\(1\))-.35 E -(follo)108 84 Q .402(wed by an optional)-.25 F/F1 10/Times-Italic@0 SF -(postamble)2.902 E F0 5.402(.T).18 G .402 -(he preamble is prepended to each string contained within the braces,)262.43 84 -R(and the postamble is then appended to each resulting string, e)108 96 Q -(xpanding left to right.)-.15 E .719(Brace e)108 112.8 R .719 -(xpansions may be nested.)-.15 F .719(The results of each e)5.719 F .719 -(xpanded string are not sorted; left to right order is)-.15 F(preserv)108 124.8 -Q 2.5(ed. F)-.15 F(or e)-.15 E(xample, a)-.15 E/F2 10/Times-Bold@0 SF({)A F0 -(d,c,b)A F2(})A F0 2.5(ee)C(xpands into `ade ace abe'.)252.18 124.8 Q .581 -(Brace e)108 141.6 R .581(xpansion is performed before an)-.15 F 3.081(yo)-.15 -G .581(ther e)283.356 141.6 R .581(xpansions, and an)-.15 F 3.082(yc)-.15 G -.582(haracters special to other e)391.192 141.6 R(xpansions)-.15 E .016 -(are preserv)108 153.6 R .016(ed in the result.)-.15 F .016(It is strictly te) -5.016 F(xtual.)-.15 E F2(Bash)5.016 E F0 .015(does not apply an)2.516 F 2.515 -(ys)-.15 G .015(yntactic interpretation to the con-)406.63 153.6 R(te)108 165.6 -Q(xt of the e)-.15 E(xpansion or the te)-.15 E(xt between the braces.)-.15 E -3.632(Ac)108 182.4 S 1.132(orrectly-formed brace e)123.292 182.4 R 1.132 -(xpansion must contain unquoted opening and closing braces, and at least one) --.15 F(unquoted comma.)108 194.4 Q(An)5 E 2.5(yi)-.15 G -(ncorrectly formed brace e)207.01 194.4 Q(xpansion is left unchanged.)-.15 E -1.476(This construct is typically used as shorthand when the common pre\214x o\ -f the strings to be generated is)108 211.2 R(longer than in the abo)108 223.2 Q -.3 -.15(ve ex)-.15 H(ample:).15 E(mkdir /usr/local/src/bash/{old,ne)144 240 Q --.65(w,)-.25 G(dist,b).65 E(ugs})-.2 E(or)108 252 Q(cho)144 264 Q -(wn root /usr/{ucb/{e)-.25 E(x,edit},lib/{e)-.15 E(x?.?*,ho)-.15 E(w_e)-.25 E -(x}})-.15 E 1.177(Brace e)108 280.8 R 1.177 -(xpansion introduces a slight incompatibility with traditional v)-.15 F 1.177 -(ersions of)-.15 F F2(sh)3.677 E F0 3.677(,t)C 1.177(he Bourne shell.)456.747 -280.8 R F2(sh)6.178 E F0 .015 -(does not treat opening or closing braces specially when the)108 292.8 R 2.515 -(ya)-.15 G .015(ppear as part of a w)355.73 292.8 R .014(ord, and preserv)-.1 F -.014(es them in)-.15 F .693(the output.)108 304.8 R F2(Bash)5.693 E F0(remo) -3.193 E -.15(ve)-.15 G 3.193(sb).15 G .694(races from w)223.252 304.8 R .694 -(ords as a consequence of brace e)-.1 F 3.194(xpansion. F)-.15 F .694(or e)-.15 -F .694(xample, a w)-.15 F(ord)-.1 E 1.45(entered to)108 316.8 R F2(sh)3.95 E F0 -(as)3.95 E F1(\214le{1,2})3.95 E F0 1.45(appears identically in the output.) -3.95 F 1.45(The same w)6.45 F 1.45(ord is output as)-.1 F F1 1.45 -(\214le1 \214le2)3.95 F F0(after)3.95 E -.15(ex)108 328.8 S .576(pansion by).15 -F F2(bash)3.076 E F0 5.576(.I)C 3.076(fs)195.968 328.8 S .576 -(trict compatibility with)206.264 328.8 R F2(sh)3.077 E F0 .577 -(is desired, start)3.077 F F2(bash)3.077 E F0 .577(with the)3.077 F F2 -(\255nobraceexpansion)3.077 E F0(\215ag)3.077 E(\(see)108 340.8 Q/F3 9 -/Times-Bold@0 SF(OPTIONS)2.598 E F0(abo)2.348 E -.15(ve)-.15 G 2.598(\)o).15 G -2.598(rd)204.063 340.8 S .098(isable brace e)214.991 340.8 R .098 -(xpansion with the)-.15 F F2 .097(+o braceexpand)2.598 F F0 .097(option to the) -2.597 F F2(set)2.597 E F0 .097(command \(see)2.597 F F3(SHELL B)108 352.8 Q -(UIL)-.09 E(TIN COMMANDS)-.828 E F0(belo)2.25 E(w\).)-.25 E F2 -.18(Ti)87 369.6 -S(lde Expansion).18 E F0 .432(If a w)108 381.6 R .432(ord be)-.1 F .432 -(gins with a tilde character \(`)-.15 F F2(~)A F0 .433 -('\), all of the characters preceding the \214rst slash \(or all characters,)B -.986(if there is no slash\) are treated as a possible)108 393.6 R F1(lo)3.486 E -.985(gin name)-.1 F F0 3.485(.I)C 3.485(ft)348.85 393.6 S(his)358.445 393.6 Q -F1(lo)3.485 E .985(gin name)-.1 F F0 .985(is the null string, the tilde is) -3.485 F .353(replaced with the v)108 405.6 R .353(alue of the parameter)-.25 F -F3(HOME)2.853 E/F4 9/Times-Roman@0 SF(.)A F0(If)4.853 E F3(HOME)2.854 E F0 .354 -(is unset, the home directory of the user e)2.604 F -.15(xe)-.15 G(cut-).15 E -(ing the shell is substituted instead.)108 417.6 Q .638(If a `+' follo)108 -434.4 R .638(ws the tilde, the v)-.25 F .638(alue of)-.25 F F3(PWD)3.138 E F0 -.638(replaces the tilde and `+'.)2.888 F .638(If a `\255' follo)5.638 F .638 -(ws, the v)-.25 F .637(alue of)-.25 F F3(OLD-)3.137 E(PWD)108 446.4 Q F0 1.345 -(is substituted.)3.595 F 1.345(If the v)6.345 F 1.345(alue follo)-.25 F 1.345 -(wing the tilde is a v)-.25 F(alid)-.25 E F1(lo)3.846 E 1.346(gin name)-.1 F F0 -3.846(,t)C 1.346(he tilde and)424.78 446.4 R F1(lo)3.846 E 1.346(gin name)-.1 F -F0(are)3.846 E .659 -(replaced with the home directory associated with that name.)108 458.4 R .659 -(If the name is in)5.659 F -.25(va)-.4 G .658(lid, or the tilde e).25 F -(xpansion)-.15 E -.1(fa)108 470.4 S(ils, the w).1 E(ord is unchanged.)-.1 E -1.162(Each v)108 487.2 R 1.162(ariable assignment is check)-.25 F 1.162 -(ed for unquoted instances of tildes follo)-.1 F 1.162(wing a)-.25 F F2(:)3.663 -E F0(or)3.663 E F2(=)3.663 E F0 6.163(.I)C 3.663(nt)483.524 487.2 S 1.163 -(hese cases,)494.967 487.2 R 1.043(tilde substitution is also performed.)108 -499.2 R(Consequently)6.043 E 3.543(,o)-.65 G 1.043 -(ne may use pathnames with tildes in assignments to)324.998 499.2 R F3 -.666 -(PA)108 511.2 S(TH)-.189 E F4(,)A F3(MAILP)2.25 E -.855(AT)-.666 G(H).855 E F4 -(,)A F0(and)2.25 E F3(CDP)2.5 E -.855(AT)-.666 G(H).855 E F4(,)A F0 -(and the shell assigns the e)2.25 E(xpanded v)-.15 E(alue.)-.25 E F2 -.1(Pa)87 -528 S(rameter Expansion).1 E F0 1.605(The `)108 540 R F2($)A F0 4.105('c)C -1.605(haracter introduces parameter e)147.86 540 R 1.606 -(xpansion, command substitution, or arithmetic e)-.15 F 4.106(xpansion. The) --.15 F .407(parameter name or symbol to be e)108 552 R .407 -(xpanded may be enclosed in braces, which are optional b)-.15 F .406(ut serv) --.2 F 2.906(et)-.15 G 2.906(op)515.434 552 S(ro-)528.34 552 Q .032(tect the v) -108 564 R .032(ariable to be e)-.25 F .032 -(xpanded from characters immediately follo)-.15 F .033 -(wing it which could be interpreted as part)-.25 F(of the name.)108 576 Q(${) -108 592.8 Q F1(par)A(ameter)-.15 E F0(})A 1.346(The v)144 604.8 R 1.346 -(alue of)-.25 F F1(par)3.846 E(ameter)-.15 E F0 1.346(is substituted.)3.846 F -1.346(The braces are required when)6.346 F F1(par)3.845 E(ameter)-.15 E F0 -1.345(is a positional)3.845 F .38(parameter with more than one digit, or when) -144 616.8 R F1(par)2.881 E(ameter)-.15 E F0 .381(is follo)2.881 F .381 -(wed by a character which is not to)-.25 F(be interpreted as part of its name.) -144 628.8 Q .334(In each of the cases belo)108 645.6 R -.65(w,)-.25 G F1(wor) -3.484 E(d)-.37 E F0 .334(is subject to tilde e)2.834 F .334 -(xpansion, parameter e)-.15 F .334(xpansion, command substitution,)-.15 F .861 -(and arithmetic e)108 657.6 R(xpansion.)-.15 E F2(Bash)5.861 E F0 .862 -(tests for a parameter that is unset or null; omitting the colon results in a) -3.361 F(test only for a parameter that is unset.)108 669.6 Q(${)108 686.4 Q F1 -(par)A(ameter)-.15 E F2<3aad>A F1(wor)A(d)-.37 E F0(})A F2 .929(Use Default V) -144 698.4 R(alues)-.92 E F0 5.929(.I)C(f)237.797 698.4 Q F1(par)3.429 E(ameter) --.15 E F0 .929(is unset or null, the e)3.429 F .928(xpansion of)-.15 F F1(wor) -3.428 E(d)-.37 E F0 .928(is substituted.)3.428 F(Other)5.928 E(-)-.2 E -(wise, the v)144 710.4 Q(alue of)-.25 E F1(par)2.5 E(ameter)-.15 E F0 -(is substituted.)2.5 E 185.675(GNU 1995)72 768 R(May 5)2.5 E(9)535 768 Q EP -%%Page: 10 10 -%%BeginPageSetup -BP -%%EndPageSetup -/F0 10/Times-Roman@0 SF -.35(BA)72 48 S 389.54(SH\(1\) B).35 F(ASH\(1\))-.35 E -(${)108 84 Q/F1 10/Times-Italic@0 SF(par)A(ameter)-.15 E/F2 10/Times-Bold@0 SF -(:=)A F1(wor)A(d)-.37 E F0(})A F2 .085(Assign Default V)144 96 R(alues)-.92 E -F0 5.085(.I)C(f)248.055 96 Q F1(par)2.585 E(ameter)-.15 E F0 .086 -(is unset or null, the e)2.585 F .086(xpansion of)-.15 F F1(wor)2.586 E(d)-.37 -E F0 .086(is assigned to)2.586 F F1(par)2.586 E(am-)-.15 E(eter)144 108 Q F0 -6.311(.T).73 G 1.311(he v)175.201 108 R 1.311(alue of)-.25 F F1(par)3.811 E -(ameter)-.15 E F0 1.311(is then substituted.)3.811 F 1.311 -(Positional parameters and special parameters)6.311 F -(may not be assigned to in this w)144 120 Q(ay)-.1 E(.)-.65 E(${)108 132 Q F1 -(par)A(ameter)-.15 E F2(:?)A F1(wor)A(d)-.37 E F0(})A F2 .645(Display Err)144 -144 R .645(or if Null or Unset)-.18 F F0 5.645(.I)C(f)286.57 144 Q F1(par)3.145 -E(ameter)-.15 E F0 .645(is null or unset, the e)3.145 F .645(xpansion of)-.15 F -F1(wor)3.145 E(d)-.37 E F0 .645(\(or a mes-)3.145 F .715(sage to that ef)144 -156 R .715(fect if)-.25 F F1(wor)3.215 E(d)-.37 E F0 .714 -(is not present\) is written to the standard error and the shell, if it is not) -3.215 F(interacti)144 168 Q -.15(ve)-.25 G 2.5(,e).15 G 2.5(xits. Otherwise,) -195.1 168 R(the v)2.5 E(alue of)-.25 E F1(par)2.5 E(ameter)-.15 E F0 -(is substituted.)2.5 E(${)108 180 Q F1(par)A(ameter)-.15 E F2(:+)A F1(wor)A(d) --.37 E F0(})A F2 .886(Use Alter)144 192 R .886(nate V)-.15 F(alue)-.92 E F0 -5.886(.I)C(f)242.508 192 Q F1(par)3.386 E(ameter)-.15 E F0 .887 -(is null or unset, nothing is substituted, otherwise the e)3.386 F(xpan-)-.15 E -(sion of)144 204 Q F1(wor)2.5 E(d)-.37 E F0(is substituted.)2.5 E(${)108 216 Q -F2(#)A F1(par)A(ameter)-.15 E F0(})A 1.509(The length in characters of the v) -144 228 R 1.508(alue of)-.25 F F1(par)4.008 E(ameter)-.15 E F0 1.508 -(is substituted.)4.008 F(If)6.508 E F1(par)4.008 E(ameter)-.15 E F0(is)4.008 E -F2(*)4.008 E F0(or)4.008 E F2(@)4.008 E F0 4.008(,t)C(he)530.56 228 Q -(length substituted is the length of)144 240 Q F2(*)2.5 E F0 -.15(ex)2.5 G -(panded within double quotes.).15 E(${)108 252 Q F1(par)A(ameter)-.15 E F2(#)A -F1(wor)A(d)-.37 E F0(})A(${)108 264 Q F1(par)A(ameter)-.15 E F2(##)A F1(wor)A -(d)-.37 E F0(})A(The)144 276 Q F1(wor)3.06 E(d)-.37 E F0 .56(is e)3.06 F .56 -(xpanded to produce a pattern just as in pathname e)-.15 F 3.06(xpansion. If) --.15 F .56(the pattern matches)3.06 F 1.183(the be)144 288 R 1.183 -(ginning of the v)-.15 F 1.183(alue of)-.25 F F1(par)3.683 E(ameter)-.15 E F0 -3.683(,t).73 G 1.183(hen the e)319.661 288 R 1.182(xpansion is the v)-.15 F -1.182(alue of)-.25 F F1(par)3.682 E(ameter)-.15 E F0 1.182(with the)3.682 F .17 -(shortest matching pattern deleted \(the `)144 300 R(`)-.74 E F2(#)A F0 1.651 --.74('' c)D .171(ase\) or the longest matching pattern deleted \(the `).74 F(`) --.74 E F2(##)A F0 -.74('')C(case\).)144 312 Q(${)108 328.8 Q F1(par)A(ameter) --.15 E F2(%)A F1(wor)A(d)-.37 E F0(})A(${)108 340.8 Q F1(par)A(ameter)-.15 E F2 -(%%)A F1(wor)A(d)-.37 E F0(})A(The)144 352.8 Q F1(wor)2.619 E(d)-.37 E F0 .119 -(is e)2.619 F .119(xpanded to produce a pattern just as in pathname e)-.15 F -2.619(xpansion. If)-.15 F .118(the pattern matches a)2.619 F .825 -(trailing portion of the v)144 364.8 R .825(alue of)-.25 F F1(par)3.325 E -(ameter)-.15 E F0 3.326(,t).73 G .826(hen the e)322.866 364.8 R .826 -(xpansion is the v)-.15 F .826(alue of)-.25 F F1(par)3.326 E(ameter)-.15 E F0 -.826(with the)3.326 F 1.672(shortest matching pattern deleted \(the `)144 376.8 -R(`)-.74 E F2(%)A F0 3.152 -.74('' c)D 1.671 -(ase\) or the longest matching pattern deleted \(the).74 F -.74(``)144 388.8 S -F2(%%).74 E F0 1.48 -.74('' c)D(ase\).).74 E F2(Command Substitution)87 405.6 Q -F1 1.697(Command substitution)108 417.6 R F0(allo)4.197 E 1.697 -(ws the output of a command to replace the command name.)-.25 F 1.698 -(There are tw)6.698 F(o)-.1 E(forms:)108 429.6 Q F2($\()144 451.2 Q F1(command) -A F2(\))1.666 E F0(or)108 463.2 Q F2(`)144 475.2 Q F1(command)A F2(`)A(Bash)108 -492 Q F0 .02(performs the e)2.52 F .02(xpansion by e)-.15 F -.15(xe)-.15 G -(cuting).15 E F1(command)2.519 E F0 .019 -(and replacing the command substitution with the stan-)2.519 F -(dard output of the command, with an)108 504 Q 2.5(yt)-.15 G(railing ne)266.17 -504 Q(wlines deleted.)-.25 E 1.559(When the old\255style backquote form of sub\ -stitution is used, backslash retains its literal meaning e)108 520.8 R(xcept) --.15 E 1.259(when follo)108 532.8 R 1.259(wed by)-.25 F F2($)3.759 E F0(,)A F2 -(`)3.758 E F0 3.758(,o)C(r)212.083 532.8 Q F2(\\)3.758 E F0 6.258(.W)C 1.258 -(hen using the $\()240.149 532.8 R F1(command).833 E F0 3.758(\)f)1.666 G 1.258 -(orm, all characters between the parentheses)359.88 532.8 R(mak)108 544.8 Q 2.5 -(eu)-.1 G 2.5(pt)137.06 544.8 S(he command; none are treated specially)147.34 -544.8 Q(.)-.65 E .229(Command substitutions may be nested.)108 561.6 R 1.829 --.8(To n)5.229 H .23 -(est when using the old form, escape the inner backquotes with).8 F -(backslashes.)108 573.6 Q .422 -(If the substitution appears within double quotes, w)108 590.4 R .422 -(ord splitting and pathname e)-.1 F .422(xpansion are not performed)-.15 F -(on the results.)108 602.4 Q F2(Arithmetic Expansion)87 619.2 Q F0 1.034 -(Arithmetic e)108 631.2 R 1.034(xpansion allo)-.15 F 1.034(ws the e)-.25 F -.25 -(va)-.25 G 1.034(luation of an arithmetic e).25 F 1.035 -(xpression and the substitution of the result.)-.15 F(There are tw)108 643.2 Q -2.5(of)-.1 G(ormats for arithmetic e)169.26 643.2 Q(xpansion:)-.15 E F2($[)144 -660 Q F1 -.2(ex)C(pr).2 E(ession)-.37 E F2(])A($\(\()144 676.8 Q F1 -.2(ex)C -(pr).2 E(ession)-.37 E F2(\)\))A F0(The)108 693.6 Q F1 -.2(ex)3.03 G(pr).2 E -(ession)-.37 E F0 .53(is treated as if it were within double quotes, b)3.03 F -.53(ut a double quote inside the braces or paren-)-.2 F .215 -(theses is not treated specially)108 705.6 R 5.215(.A)-.65 G .215(ll tok) -239.795 705.6 R .215(ens in the e)-.1 F .215(xpression under)-.15 F .215 -(go parameter e)-.18 F .215(xpansion, command substi-)-.15 F -(tution, and quote remo)108 717.6 Q -.25(va)-.15 G 2.5(l. Arithmetic).25 F -(substitutions may be nested.)2.5 E 185.675(GNU 1995)72 768 R(May 5)2.5 E(10) -530 768 Q EP -%%Page: 11 11 -%%BeginPageSetup -BP -%%EndPageSetup -/F0 10/Times-Roman@0 SF -.35(BA)72 48 S 389.54(SH\(1\) B).35 F(ASH\(1\))-.35 E -1.379(The e)108 84 R -.25(va)-.25 G 1.378 -(luation is performed according to the rules listed belo).25 F 3.878(wu)-.25 G -(nder)381.541 84 Q/F1 9/Times-Bold@0 SF 1.378(ARITHMETIC EV)3.878 F(ALU)-1.215 -E -.855(AT)-.54 G(ION).855 E/F2 9/Times-Roman@0 SF(.)A F0(If)5.878 E/F3 10 -/Times-Italic@0 SF -.2(ex)108 96 S(pr).2 E(ession)-.37 E F0(is in)2.5 E -.25 -(va)-.4 G(lid,).25 E/F4 10/Times-Bold@0 SF(bash)2.5 E F0 -(prints a message indicating f)2.5 E(ailure and no substitution occurs.)-.1 E -F4(Pr)87 112.8 Q(ocess Substitution)-.18 E F3(Pr)108 124.8 Q .97 -(ocess substitution)-.45 F F0 .971 -(is supported on systems that support named pipes \()3.47 F F3(FIFOs)A F0 3.471 -(\)o)C 3.471(rt)442.936 124.8 S(he)452.517 124.8 Q F4(/de)3.471 E(v/fd)-.15 E -F0 .971(method of)3.471 F .022(naming open \214les.)108 136.8 R .021(It tak) -5.022 F .021(es the form of)-.1 F F4(<\()2.521 E F3(list)A F4(\)).833 E F0(or) -2.521 E F4(>\()2.521 E F3(list)A F4(\)).833 E F0 5.021(.T)C .021(he process) -343.68 136.8 R F3(list)2.521 E F0 .021(is run with its input or output con-) -2.521 F .058(nected to a)108 148.8 R F3(FIFO)2.558 E F0 .058(or some \214le in) -2.558 F F4(/de)2.558 E(v/fd)-.15 E F0 5.058(.T)C .058 -(he name of this \214le is passed as an ar)282.522 148.8 R .059 -(gument to the current com-)-.18 F .131(mand as the result of the e)108 160.8 R -2.631(xpansion. If)-.15 F(the)2.63 E F4(>\()2.63 E F3(list)A F4(\)).833 E F0 -.13(form is used, writing to the \214le will pro)2.63 F .13(vide input for)-.15 -F F3(list)2.63 E F0(.)A(If the)108 172.8 Q F4(<\()2.5 E F3(list)A F4(\)).833 E -F0(form is used, the \214le passed as an ar)2.5 E -(gument should be read to obtain the output of)-.18 E F3(list)2.5 E F0(.)A .713 -(On systems that support it,)108 189.6 R F3(pr)3.213 E .713(ocess substitution) --.45 F F0 .713(is performed simultaneously with)3.213 F F3(par)3.213 E .713 -(ameter and variable)-.15 F -.2(ex)108 201.6 S(pansion).2 E F0(,).24 E F3 -(command substitution)2.5 E F0 2.5(,a).24 G(nd)251.33 201.6 Q F3(arithmetic e) -2.5 E(xpansion)-.2 E F0(.).24 E F4 -.75(Wo)87 218.4 S(rd Splitting).75 E F0 -1.143(The shell scans the results of parameter e)108 230.4 R 1.142 -(xpansion, command substitution, and arithmetic e)-.15 F 1.142(xpansion that) --.15 F(did not occur within double quotes for)108 242.4 Q F3(wor)2.5 E 2.5(ds) --.37 G(plitting)290.4 242.4 Q F0(.).22 E .063 -(The shell treats each character of)108 259.2 R F1(IFS)2.563 E F0 .063 -(as a delimiter)2.313 F 2.563(,a)-.4 G .063 -(nd splits the results of the other e)322.193 259.2 R .063(xpansions into w) --.15 F(ords)-.1 E .227(on these characters.)108 271.2 R .227(If the v)5.227 F -.227(alue of)-.25 F F1(IFS)2.726 E F0 .226(is e)2.476 F(xactly)-.15 E F4 -()2.726 E F0 2.726(,t)C .226(he def)421.326 271.2 R .226 -(ault, then an)-.1 F 2.726(ys)-.15 G(equence)507.24 271.2 Q(of)108 283.2 Q F1 -(IFS)3.211 E F0 .711(characters serv)2.961 F .711(es to delimit w)-.15 F 3.212 -(ords. If)-.1 F F1(IFS)3.212 E F0 .712(has a v)2.962 F .712 -(alue other than the def)-.25 F .712(ault, then sequences of the)-.1 F 1.628 -(whitespace characters)108 295.2 R F4(space)4.128 E F0(and)4.128 E F4(tab)4.128 -E F0 1.627(are ignored at the be)4.127 F 1.627(ginning and end of the w)-.15 F -1.627(ord, as long as the)-.1 F .563(whitespace character is in the v)108 307.2 -R .564(alue of)-.25 F F1(IFS)3.064 E F0(\(an)2.814 E F1(IFS)3.064 E F0 .564 -(whitespace character\).)2.814 F(An)5.564 E 3.064(yc)-.15 G .564(haracter in) -436.496 307.2 R F1(IFS)3.064 E F0 .564(that is not)2.814 F F1(IFS)108 319.2 Q -F0 1.29(whitespace, along with an)3.54 F 3.789(ya)-.15 G(djacent)246.362 319.2 -Q F1(IFS)3.789 E F0 1.289(whitespace characters, delimits a \214eld.)3.539 F -3.789(As)6.289 G 1.289(equence of)477.328 319.2 R F1(IFS)3.789 E F0 .04 -(whitespace characters is also treated as a delimiter)108 331.2 R 5.041(.I)-.55 -G 2.541(ft)319.931 331.2 S .041(he v)328.582 331.2 R .041(alue of)-.25 F F1 -(IFS)2.541 E F0 .041(is null, no w)2.291 F .041(ord splitting occurs.)-.1 F F1 -(IFS)5.041 E F0(cannot be unset.)108 343.2 Q .857(Explicit null ar)108 360 R -.857(guments \()-.18 F F4 .833("").833 G F0(or)2.524 E F4 .833('')4.19 G F0 -3.357(\)a)C .857(re retained.)258.207 360 R .857(Implicit null ar)5.857 F .857 -(guments, resulting from the e)-.18 F .857(xpansion of)-.15 F F3(par)108 372 Q -(ameter)-.15 E(s)-.1 E F0(that ha)2.5 E .3 -.15(ve n)-.2 H 2.5(ov).15 G -(alues, are remo)211.58 372 Q -.15(ve)-.15 G(d.).15 E(Note that if no e)108 -388.8 Q(xpansion occurs, no splitting is performed.)-.15 E F4 -.1(Pa)87 405.6 S -(thname Expansion).1 E F0 .383(After w)108 417.6 R .383 -(ord splitting, unless the)-.1 F F42.883 E F0 .383(option has been set,) -2.883 F F4(bash)2.883 E F0 .384(scans each)2.884 F F3(wor)2.884 E(d)-.37 E F0 -.384(for the characters)2.884 F F4(*)2.884 E F0(,)A F4(?)2.884 E F0 2.884(,a)C -(nd)521.286 417.6 Q F4([)2.884 E F0(.)A .678 -(If one of these characters appears, then the w)108 429.6 R .677(ord is re)-.1 -F -.05(ga)-.15 G .677(rded as a).05 F F3(pattern)3.177 E F0 3.177(,a).24 G .677 -(nd replaced with an alphabeti-)416.212 429.6 R .071 -(cally sorted list of pathnames matching the pattern.)108 441.6 R .071 -(If no matching pathnames are found, and the shell v)5.071 F(ari-)-.25 E(able) -108 453.6 Q F4(allo)2.516 E(w_null_glob_expansion)-.1 E F0 .016 -(is unset, the w)2.516 F .016(ord is left unchanged.)-.1 F .016(If the v)5.016 -F .015(ariable is set, and no matches)-.25 F .487(are found, the w)108 465.6 R -.487(ord is remo)-.1 F -.15(ve)-.15 G 2.988(d. When).15 F 2.988(ap)2.988 G .488 -(attern is used for pathname generation, the character)282.29 465.6 R F4 -.63 -(``)2.988 G -.55(.').63 G(')-.08 E F0 .488(at the)5.488 F 1.789 -(start of a name or immediately follo)108 477.6 R 1.789 -(wing a slash must be matched e)-.25 F(xplicitly)-.15 E 4.288(,u)-.65 G 1.788 -(nless the shell v)444.066 477.6 R(ariable)-.25 E F4(glob_dot_\214lenames)108 -489.6 Q F0 .418(is set.)2.918 F .418(The slash character must al)5.418 F -.1 -(wa)-.1 G .418(ys be matched e).1 F(xplicitly)-.15 E 5.418(.I)-.65 G 2.918(no) -452.948 489.6 S .418(ther cases, the)465.866 489.6 R F4 -.63(``)2.918 G -.55 -(.').63 G(')-.08 E F0(character is not treated specially)108 501.6 Q(.)-.65 E -(The special pattern characters ha)108 518.4 Q .3 -.15(ve t)-.2 H(he follo).15 -E(wing meanings:)-.25 E F4(*)108 535.2 Q F0(Matches an)144 535.2 Q 2.5(ys)-.15 -G(tring, including the null string.)201.06 535.2 Q F4(?)108 547.2 Q F0 -(Matches an)144 547.2 Q 2.5(ys)-.15 G(ingle character)201.06 547.2 Q(.)-.55 E -F4([...])108 559.2 Q F0 1.992(Matches an)144 559.2 R 4.492(yo)-.15 G 1.992 -(ne of the enclosed characters.)206.154 559.2 R 4.491(Ap)6.991 G 1.991 -(air of characters separated by a minus sign)355.833 559.2 R 1.113(denotes a) -144 571.2 R F3 -.15(ra)3.613 G(ng).15 E(e)-.1 E F0 3.613(;a).18 G 1.413 -.15 -(ny c)220.309 571.2 T 1.113(haracter le).15 F 1.113(xically between those tw) --.15 F 3.613(oc)-.1 G 1.113(haracters, inclusi)396.537 571.2 R -.15(ve)-.25 G -3.613(,i).15 G 3.613(sm)483.343 571.2 S 3.614(atched. If)498.626 571.2 R .15 -(the \214rst character follo)144 583.2 R .15(wing the)-.25 F F4([)2.65 E F0 .15 -(is a)2.65 F F4(!)2.65 E F0 .15(or a)5.15 F F4(^)2.65 E F0 .15(then an)2.65 F -2.65(yc)-.15 G .15(haracter not enclosed is matched.)368.7 583.2 R(A)5.15 E F4 -2.65 E F0(or)2.65 E F4(])2.65 E F0 -(may be matched by including it as the \214rst or last character in the set.) -144 595.2 Q F4(Quote Remo)87 612 Q -.1(va)-.1 G(l).1 E F0 -(After the preceding e)108 624 Q -(xpansions, all unquoted occurrences of the characters)-.15 E F4(\\)2.5 E F0(,) -A F4(`)2.5 E F0 2.5(,a)C(nd)429.14 624 Q F4(")3.333 E F0(are remo)3.333 E -.15 -(ve)-.15 G(d.).15 E F1(REDIRECTION)72 640.8 Q F0 .593(Before a command is e)108 -652.8 R -.15(xe)-.15 G .593(cuted, its input and output may be).15 F F3 -.37 -(re)3.093 G(dir).37 E(ected)-.37 E F0 .593 -(using a special notation interpreted)3.093 F .617(by the shell.)108 664.8 R -.617(Redirection may also be used to open and close \214les for the current sh\ -ell e)5.617 F -.15(xe)-.15 G .616(cution en).15 F(viron-)-.4 E 3.353(ment. The) -108 676.8 R(follo)3.353 E .853 -(wing redirection operators may precede or appear an)-.25 F .854 -(ywhere within a)-.15 F F3 .854(simple command)3.354 F F0(or)3.354 E(may follo) -108 688.8 Q 2.5(wa)-.25 G F3(command)A F0 5(.R).77 G -(edirections are processed in the order the)216.84 688.8 Q 2.5(ya)-.15 G(ppear) -392.47 688.8 Q 2.5(,f)-.4 G(rom left to right.)422.61 688.8 Q .448 -(In the follo)108 705.6 R .447(wing descriptions, if the \214le descriptor num\ -ber is omitted, and the \214rst character of the redirec-)-.25 F .365 -(tion operator is)108 717.6 R F4(<)2.865 E F0 2.865(,t)C .366 -(he redirection refers to the standard input \(\214le descriptor 0\).)185.99 -717.6 R .366(If the \214rst character of the)5.366 F(redirection operator is) -108 729.6 Q F4(>)2.5 E F0 2.5(,t)C -(he redirection refers to the standard output \(\214le descriptor 1\).)212.29 -729.6 Q 185.675(GNU 1995)72 768 R(May 5)2.5 E(11)530 768 Q EP -%%Page: 12 12 -%%BeginPageSetup -BP -%%EndPageSetup -/F0 10/Times-Roman@0 SF -.35(BA)72 48 S 389.54(SH\(1\) B).35 F(ASH\(1\))-.35 E -.077(The w)108 84 R .077(ord that follo)-.1 F .077 -(ws the redirection operator in the follo)-.25 F .076 -(wing descriptions is subjected to brace e)-.25 F(xpansion,)-.15 E 1.984 -(tilde e)108 96 R 1.984(xpansion, parameter e)-.15 F 1.984 -(xpansion, command substitution, arithmetic e)-.15 F 1.984 -(xpansion, quote remo)-.15 F -.25(va)-.15 G 1.984(l, and).25 F(pathname e)108 -108 Q 2.5(xpansion. If)-.15 F(it e)2.5 E(xpands to more than one w)-.15 E(ord,) --.1 E/F1 10/Times-Bold@0 SF(bash)2.5 E F0(reports an error)2.5 E(.)-.55 E -(Note that the order of redirections is signi\214cant.)108 124.8 Q -.15(Fo)5 G -2.5(re).15 G(xample, the command)325.17 124.8 Q(ls)144 141.6 Q F1(>)2.5 E F0 -(dirlist 2)2.5 E F1(>&)A F0(1)A -(directs both standard output and standard error to the \214le)108 158.4 Q/F2 -10/Times-Italic@0 SF(dirlist)2.5 E F0 2.5(,w).68 G(hile the command)374.21 -158.4 Q(ls 2)144 175.2 Q F1(>&)A F0(1)A F1(>)2.5 E F0(dirlist)2.5 E .388 -(directs only the standard output to \214le)108 192 R F2(dirlist)2.888 E F0 -2.888(,b).68 G .387(ecause the standard error w)299.844 192 R .387 -(as duplicated as standard output)-.1 F(before the standard output w)108 204 Q -(as redirected to)-.1 E F2(dirlist)2.5 E F0(.).68 E F1(Redir)87 220.8 Q -(ecting Input)-.18 E F0 .453 -(Redirection of input causes the \214le whose name results from the e)108 232.8 -R .453(xpansion of)-.15 F F2(wor)2.953 E(d)-.37 E F0 .453 -(to be opened for read-)2.953 F(ing on \214le descriptor)108 244.8 Q F2(n)2.5 E -F0 2.5(,o).24 G 2.5(rt)208.79 244.8 S -(he standard input \(\214le descriptor 0\) if)217.4 244.8 Q F2(n)2.5 E F0 -(is not speci\214ed.)2.5 E(The general format for redirecting input is:)108 -261.6 Q([)144 278.4 Q F2(n)A F0(])A F1(<)A F2(wor)A(d)-.37 E F1(Redir)87 295.2 -Q(ecting Output)-.18 E F0 .236 -(Redirection of output causes the \214le whose name results from the e)108 -307.2 R .236(xpansion of)-.15 F F2(wor)2.736 E(d)-.37 E F0 .236 -(to be opened for writ-)2.736 F .852(ing on \214le descriptor)108 319.2 R F2(n) -3.353 E F0 3.353(,o).24 G 3.353(rt)213.052 319.2 S .853 -(he standard output \(\214le descriptor 1\) if)222.515 319.2 R F2(n)3.353 E F0 -.853(is not speci\214ed.)3.353 F .853(If the \214le does not)5.853 F -.15(ex) -108 331.2 S(ist it is created; if it does e).15 E -(xist it is truncated to zero size.)-.15 E -(The general format for redirecting output is:)108 348 Q([)144 364.8 Q F2(n)A -F0(])A F1(>)A F2(wor)A(d)-.37 E F0 .127(If the redirection operator is)108 -381.6 R F1(>|)2.627 E F0 2.627(,t)C .127(hen the v)239.132 381.6 R .127 -(alue of the)-.25 F F1(-C)2.627 E F0 .127(option to the)2.627 F F1(set)2.626 E -F0 -.2(bu)2.626 G .126(iltin command is not tested, and).2 F -(\214le creation is attempted.)108 393.6 Q(\(See also the description of)5 E F1 -(noclob)2.5 E(ber)-.1 E F0(under)2.5 E F1(Shell V)2.5 E(ariables)-.92 E F0(abo) -2.5 E -.15(ve)-.15 G(.\)).15 E F1 -.25(Ap)87 410.4 S(pending Redir).25 E -(ected Output)-.18 E F0 .703(Redirection of output in this f)108 422.4 R .703 -(ashion causes the \214le whose name results from the e)-.1 F .704(xpansion of) --.15 F F2(wor)3.204 E(d)-.37 E F0 .704(to be)3.204 F .506 -(opened for appending on \214le descriptor)108 434.4 R F2(n)3.005 E F0 3.005 -(,o).24 G 3.005(rt)286.75 434.4 S .505 -(he standard output \(\214le descriptor 1\) if)295.865 434.4 R F2(n)3.005 E F0 -.505(is not speci\214ed.)3.005 F(If)5.505 E(the \214le does not e)108 446.4 Q -(xist it is created.)-.15 E(The general format for appending output is:)108 -463.2 Q([)144 480 Q F2(n)A F0(])A F1(>>)A F2(wor)A(d)-.37 E F1(Redir)87 501.6 Q -(ecting Standard Output and Standard Err)-.18 E(or)-.18 E(Bash)108 513.6 Q F0 -(allo)3.141 E .642(ws both the standard output \(\214le descriptor 1\) and the\ - standard error output \(\214le descriptor 2\) to)-.25 F -(be redirected to the \214le whose name is the e)108 525.6 Q(xpansion of)-.15 E -F2(wor)2.5 E(d)-.37 E F0(with this construct.)2.5 E(There are tw)108 542.4 Q -2.5(of)-.1 G(ormats for redirecting standard output and standard error:)169.26 -542.4 Q F1(&>)144 559.2 Q F2(wor)A(d)-.37 E F0(and)108 571.2 Q F1(>&)144 583.2 -Q F2(wor)A(d)-.37 E F0(Of the tw)108 600 Q 2.5(of)-.1 G -(orms, the \214rst is preferred.)156.5 600 Q(This is semantically equi)5 E -.25 -(va)-.25 G(lent to).25 E F1(>)144 616.8 Q F2(wor)A(d)-.37 E F0(2)2.5 E F1(>&)A -F0(1)A F1(Her)87 633.6 Q 2.5(eD)-.18 G(ocuments)117.64 633.6 Q F0 .33(This typ\ -e of redirection instructs the shell to read input from the current source unt\ -il a line containing only)108 645.6 R F2(wor)108 657.6 Q(d)-.37 E F0 .736 -(\(with no trailing blanks\) is seen.)3.236 F .737 -(All of the lines read up to that point are then used as the standard)5.736 F -(input for a command.)108 669.6 Q(The format of here-documents is as follo)108 -686.4 Q(ws:)-.25 E F1(<<)144 703.2 Q F0([)A F1A F0(])A F2(wor)A(d)-.37 E -(her)164 715.2 Q(e-document)-.37 E(delimiter)144 727.2 Q F0 185.675(GNU 1995)72 -768 R(May 5)2.5 E(12)530 768 Q EP -%%Page: 13 13 -%%BeginPageSetup -BP -%%EndPageSetup -/F0 10/Times-Roman@0 SF -.35(BA)72 48 S 389.54(SH\(1\) B).35 F(ASH\(1\))-.35 E -.128(No parameter e)108 84 R .127(xpansion, command substitution, pathname e) --.15 F .127(xpansion, or arithmetic e)-.15 F .127(xpansion is performed)-.15 F -(on)108 96 Q/F1 10/Times-Italic@0 SF(wor)2.609 E(d)-.37 E F0 5.109(.I).77 G -2.609(fa)152.508 96 S .409 -.15(ny c)162.887 96 T .109(haracters in).15 F F1 -(wor)2.609 E(d)-.37 E F0 .109(are quoted, the)2.609 F F1(delimiter)2.609 E F0 -.109(is the result of quote remo)2.609 F -.25(va)-.15 G 2.609(lo).25 G(n) -477.053 96 Q F1(wor)2.609 E(d)-.37 E F0 2.609(,a).77 G .109(nd the)515.171 96 R -1.113(lines in the here-document are not e)108 108 R 3.613(xpanded. Otherwise,) --.15 F 1.112(all lines of the here-document are subjected to)3.613 F .769 -(parameter e)108 120 R .769(xpansion, command substitution, and arithmetic e) --.15 F 3.269(xpansion. In)-.15 F .769(the latter case, the pair)3.269 F/F2 10 -/Times-Bold@0 SF(\\)108 132 Q F0(is ignored, and)2.5 E F2(\\) -2.5 E F0(must be used to quote the characters)2.5 E F2(\\)2.5 E F0(,)A F2($)2.5 -E F0 2.5(,a)C(nd)368.39 132 Q F2(`)2.5 E F0(.)A .602 -(If the redirection operator is)108 148.8 R F2(<<\255)3.101 E F0 3.101(,t)C -.601(hen all leading tab characters are stripped from input lines and the line) -251.178 148.8 R(containing)108 160.8 Q F1(delimiter)2.5 E F0 5(.T).73 G -(his allo)203.17 160.8 Q -(ws here-documents within shell scripts to be indented in a natural f)-.25 E -(ashion.)-.1 E F2(Duplicating File Descriptors)87 177.6 Q F0 -(The redirection operator)108 189.6 Q([)144 206.4 Q F1(n)A F0(])A F2(<&)A F1 -(wor)A(d)-.37 E F0 .188(is used to duplicate input \214le descriptors.)108 -223.2 R(If)5.188 E F1(wor)2.688 E(d)-.37 E F0 -.15(ex)2.688 G .189 -(pands to one or more digits, the \214le descriptor denoted).15 F(by)108 235.2 -Q F1(n)3.095 E F0 .594(is made to be a cop)3.095 F 3.094(yo)-.1 G 3.094(ft) -222.086 235.2 S .594(hat \214le descriptor)231.29 235.2 R 5.594(.I)-.55 G(f) -313.342 235.2 Q F1(wor)3.094 E(d)-.37 E F0 -.25(eva)3.094 G .594(luates to).25 -F F23.094 E F0 3.094<2c8c>C .594(le descriptor)410.582 235.2 R F1(n)3.094 E -F0 .594(is closed.)3.094 F(If)5.594 E F1(n)3.094 E F0(is)3.094 E -(not speci\214ed, the standard input \(\214le descriptor 0\) is used.)108 247.2 -Q(The operator)108 264 Q([)144 280.8 Q F1(n)A F0(])A F2(>&)A F1(wor)A(d)-.37 E -F0 .021(is used similarly to duplicate output \214le descriptors.)108 297.6 R -(If)5.021 E F1(n)2.521 E F0 .021 -(is not speci\214ed, the standard output \(\214le descriptor)2.521 F .382 -(1\) is used.)108 309.6 R .382(As a special case, if)5.382 F F1(n)2.882 E F0 -.382(is omitted, and)2.882 F F1(wor)2.882 E(d)-.37 E F0 .382(does not e)2.882 F -.381(xpand to one or more digits, the standard)-.15 F -(output and standard error are redirected as described pre)108 321.6 Q(viously) --.25 E(.)-.65 E F2(Opening File Descriptors f)87 338.4 Q -(or Reading and Writing)-.25 E F0(The redirection operator)108 350.4 Q([)144 -367.2 Q F1(n)A F0(])A F2(<>)A F1(wor)A(d)-.37 E F0 1.407 -(causes the \214le whose name is the e)108 384 R 1.407(xpansion of)-.15 F F1 -(wor)3.907 E(d)-.37 E F0 1.408 -(to be opened for both reading and writing on \214le)3.907 F(descriptor)108 396 -Q F1(n)2.715 E F0 2.715(,o).24 G 2.715(ra)166.16 396 S 2.715(st)176.645 396 S -.215(he standard input and standard output if)186.03 396 R F1(n)2.715 E F0 .214 -(is not speci\214ed.)2.715 F .214(If the \214le does not e)5.214 F .214 -(xist, it is)-.15 F(created.)108 408 Q/F3 9/Times-Bold@0 SF(FUNCTIONS)72 424.8 -Q F0 3.467(As)108 436.8 S .967(hell function, de\214ned as described abo) -122.577 436.8 R 1.267 -.15(ve u)-.15 H(nder).15 E F3 .967(SHELL GRAMMAR)3.467 F -/F4 9/Times-Roman@0 SF(,)A F0 .968(stores a series of commands for)3.217 F -1.277(later e)108 448.8 R -.15(xe)-.15 G 3.777(cution. Functions).15 F 1.277 -(are e)3.777 F -.15(xe)-.15 G 1.277(cuted in the conte).15 F 1.276 -(xt of the current shell; no ne)-.15 F 3.776(wp)-.25 G 1.276 -(rocess is created to)460.362 448.8 R .952 -(interpret them \(contrast this with the e)108 460.8 R -.15(xe)-.15 G .952 -(cution of a shell script\).).15 F .953(When a function is e)5.952 F -.15(xe) --.15 G .953(cuted, the ar).15 F(gu-)-.18 E 1.102 -(ments to the function become the positional parameters during its e)108 472.8 -R -.15(xe)-.15 G 3.602(cution. The).15 F 1.102(special parameter)3.602 F F2(#) -3.602 E F0(is)3.602 E(updated to re\215ect the change.)108 484.8 Q -(Positional parameter 0 is unchanged.)5 E -1.11(Va)108 501.6 S .655 -(riables local to the function may be declared with the)1.11 F F2(local)3.155 E -F0 -.2(bu)3.156 G .656(iltin command.).2 F(Ordinarily)5.656 E 3.156(,v)-.65 G -.656(ariables and)491.304 501.6 R(their v)108 513.6 Q -(alues are shared between the function and its caller)-.25 E(.)-.55 E .044 -(If the b)108 530.4 R .043(uiltin command)-.2 F F2 -.18(re)2.543 G(tur).18 E(n) --.15 E F0 .043(is e)2.543 F -.15(xe)-.15 G .043 -(cuted in a function, the function completes and e).15 F -.15(xe)-.15 G .043 -(cution resumes with).15 F .311(the ne)108 542.4 R .311 -(xt command after the function call.)-.15 F .311 -(When a function completes, the v)5.311 F .312(alues of the positional parame-) --.25 F(ters and the special parameter)108 554.4 Q F2(#)2.5 E F0 -(are restored to the v)2.5 E(alues the)-.25 E 2.5(yh)-.15 G -(ad prior to function e)363.64 554.4 Q -.15(xe)-.15 G(cution.).15 E 1.359 -(Function names and de\214nitions may be listed with the)108 571.2 R F2 -3.858 E F0 1.358(option to the)3.858 F F2(declar)3.858 E(e)-.18 E F0(or)3.858 E -F2(typeset)3.858 E F0 -.2(bu)3.858 G 1.358(iltin com-).2 F 2.787 -(mands. Functions)108 583.2 R .287(may be e)2.787 F .287 -(xported so that subshells automatically ha)-.15 F .588 -.15(ve t)-.2 H .288 -(hem de\214ned with the).15 F F22.788 E F0 .288(option to)2.788 F(the)108 -595.2 Q F2(export)2.5 E F0 -.2(bu)2.5 G(iltin.).2 E(Functions may be recursi) -108 612 Q -.15(ve)-.25 G 5(.N).15 G 2.5(ol)232.58 612 S -(imit is imposed on the number of recursi)242.86 612 Q .3 -.15(ve c)-.25 H -(alls.).15 E F3(ALIASES)72 628.8 Q F0 .335(The shell maintains a list of)108 -640.8 R F1(aliases)2.835 E F0 .335(that may be set and unset with the)2.835 F -F2(alias)2.834 E F0(and)2.834 E F2(unalias)2.834 E F0 -.2(bu)2.834 G .334 -(iltin commands).2 F(\(see)108 652.8 Q F3 .763(SHELL B)3.263 F(UIL)-.09 E .763 -(TIN COMMANDS)-.828 F F0(belo)3.013 E 3.263(w\). The)-.25 F .763(\214rst w) -3.263 F .763(ord of each command, if unquoted, is check)-.1 F .764(ed to)-.1 F -.634(see if it has an alias.)108 664.8 R .634(If so, that w)5.634 F .633 -(ord is replaced by the te)-.1 F .633(xt of the alias.)-.15 F .633 -(The alias name and the replace-)5.633 F .58(ment te)108 676.8 R .58 -(xt may contain an)-.15 F 3.08(yv)-.15 G .581(alid shell input, including the) -223.95 676.8 R F1(metac)3.081 E(har)-.15 E(acter)-.15 E(s)-.1 E F0 .581 -(listed abo)3.081 F -.15(ve)-.15 G 3.081(,w).15 G .581(ith the e)472.328 676.8 -R(xception)-.15 E .997(that the alias name may not contain)108 688.8 R F1(=) -3.497 E F0 5.997(.T)C .997(he \214rst w)280.486 688.8 R .996 -(ord of the replacement te)-.1 F .996(xt is tested for aliases, b)-.15 F .996 -(ut a)-.2 F -.1(wo)108 700.8 S .494(rd that is identical to an alias being e).1 -F .495(xpanded is not e)-.15 F .495(xpanded a second time.)-.15 F .495 -(This means that one may)5.495 F(alias)108 712.8 Q F2(ls)3.02 E F0(to)3.02 E F2 -.52(ls \255F)3.02 F F0 3.02(,f)C .52(or instance, and)180.19 712.8 R F2(bash) -3.02 E F0 .519(does not try to recursi)3.02 F -.15(ve)-.25 G .519(ly e).15 F -.519(xpand the replacement te)-.15 F 3.019(xt. If)-.15 F .519(the last)3.019 F -.441(character of the alias v)108 724.8 R .441(alue is a)-.25 F F1(blank)2.941 -E F0 2.941(,t).67 G .441(hen the ne)267.738 724.8 R .441(xt command w)-.15 F -.441(ord follo)-.1 F .441(wing the alias is also check)-.25 F .442(ed for)-.1 F -185.675(GNU 1995)72 768 R(May 5)2.5 E(13)530 768 Q EP -%%Page: 14 14 -%%BeginPageSetup -BP -%%EndPageSetup -/F0 10/Times-Roman@0 SF -.35(BA)72 48 S 389.54(SH\(1\) B).35 F(ASH\(1\))-.35 E -(alias e)108 84 Q(xpansion.)-.15 E(Aliases are created and listed with the)108 -100.8 Q/F1 10/Times-Bold@0 SF(alias)2.5 E F0(command, and remo)2.5 E -.15(ve) --.15 G 2.5(dw).15 G(ith the)389.87 100.8 Q F1(unalias)2.5 E F0(command.)2.5 E -.546(There is no mechanism for using ar)108 117.6 R .546 -(guments in the replacement te)-.18 F .545(xt, as in)-.15 F F1(csh)3.045 E F0 -5.545(.I)C 3.045(fa)435.54 117.6 S -.18(rg)446.355 117.6 S .545 -(uments are needed, a).18 F(shell function should be used.)108 129.6 Q -(Aliases are not e)108 146.4 Q(xpanded when the shell is not interacti)-.15 E --.15(ve)-.25 G(.).15 E .435 -(The rules concerning the de\214nition and use of aliases are some)108 163.2 R -.436(what confusing.)-.25 F F1(Bash)5.436 E F0(al)2.936 E -.1(wa)-.1 G .436 -(ys reads at least).1 F .338(one complete line of input before e)108 175.2 R --.15(xe)-.15 G .338(cuting an).15 F 2.838(yo)-.15 G 2.838(ft)309.104 175.2 S -.338(he commands on that line.)318.052 175.2 R .337(Aliases are e)5.337 F .337 -(xpanded when)-.15 F 3.403(ac)108 187.2 S .904 -(ommand is read, not when it is e)120.283 187.2 R -.15(xe)-.15 G 3.404 -(cuted. Therefore,).15 F .904 -(an alias de\214nition appearing on the same line as)3.404 F .729 -(another command does not tak)108 199.2 R 3.229(ee)-.1 G -.25(ff)245.685 199.2 -S .728(ect until the ne).25 F .728(xt line of input is read.)-.15 F .728 -(This means that the commands)5.728 F(follo)108 211.2 Q .699 -(wing the alias de\214nition on that line are not af)-.25 F .699 -(fected by the ne)-.25 F 3.199(wa)-.25 G 3.199(lias. This)397.126 211.2 R(beha) -3.199 E .699(vior is also an issue)-.2 F .073(when functions are e)108 223.2 R --.15(xe)-.15 G 2.573(cuted. Aliases).15 F .073(are e)2.573 F .072 -(xpanded when the function de\214nition is read, not when the func-)-.15 F .88 -(tion is e)108 235.2 R -.15(xe)-.15 G .88 -(cuted, because a function de\214nition is itself a compound command.).15 F .88 -(As a consequence, aliases)5.88 F .085(de\214ned in a function are not a)108 -247.2 R -.25(va)-.2 G .085(ilable until after that function is e).25 F -.15(xe) --.15 G 2.585(cuted. T).15 F 2.585(ob)-.8 G 2.584(es)427.03 247.2 S .084 -(afe, al)437.944 247.2 R -.1(wa)-.1 G .084(ys put alias de\214-).1 F -(nitions on a separate line, and do not use)108 259.2 Q F1(alias)2.5 E F0 -(in compound commands.)2.5 E(Note that for almost e)108 276 Q -.15(ve)-.25 G -(ry purpose, aliases are superseded by shell functions.).15 E/F2 9/Times-Bold@0 -SF(JOB CONTR)72 292.8 Q(OL)-.27 E/F3 10/Times-Italic@0 SF -.25(Jo)108 304.8 S -4.601(bc).25 G(ontr)131.231 304.8 Q(ol)-.45 E F0 2.101 -(refers to the ability to selecti)4.601 F -.15(ve)-.25 G 2.101(ly stop \().15 F -F3(suspend)A F0 4.601(\)t)C 2.102(he e)373.44 304.8 R -.15(xe)-.15 G 2.102 -(cution of processes and continue).15 F(\()108 316.8 Q F3 -.37(re)C(sume).37 E -F0 3.202(\)t)C .702(heir e)149.152 316.8 R -.15(xe)-.15 G .702 -(cution at a later point.).15 F 3.202(Au)5.702 G .702(ser typically emplo) -292.906 316.8 R .702(ys this f)-.1 F .702(acility via an interacti)-.1 F 1.001 --.15(ve i)-.25 H(nterf).15 E(ace)-.1 E(supplied jointly by the system')108 -328.8 Q 2.5(st)-.55 G(erminal dri)239.96 328.8 Q -.15(ve)-.25 G 2.5(ra).15 G -(nd)303.43 328.8 Q F1(bash)2.5 E F0(.)A .893(The shell associates a)108 345.6 R -F3(job)3.394 E F0 .894(with each pipeline.)3.394 F .894(It k)5.894 F .894 -(eeps a table of currently e)-.1 F -.15(xe)-.15 G .894 -(cuting jobs, which may be).15 F .341(listed with the)108 357.6 R F1(jobs)2.841 -E F0 2.841(command. When)2.841 F F1(bash)2.841 E F0 .341 -(starts a job asynchronously \(in the)2.841 F F3(bac)2.84 E(kgr)-.2 E(ound)-.45 -E F0 .34(\), it prints a line).77 F(that looks lik)108 369.6 Q(e:)-.1 E -([1] 25647)144 386.4 Q .241(indicating that this job is job number 1 and that \ -the process ID of the last process in the pipeline associated)108 403.2 R .733 -(with this job is 25647.)108 415.2 R .732 -(All of the processes in a single pipeline are members of the same job)5.733 F -(.)-.4 E F1(Bash)5.732 E F0(uses)3.232 E(the)108 427.2 Q F3(job)2.5 E F0 -(abstraction as the basis for job control.)2.5 E 2.563 -.8(To f)108 444 T .963 -(acilitate the implementation of the user interf).7 F .964 -(ace to job control, the system maintains the notion of a)-.1 F F3(curr)108 456 -Q .723(ent terminal pr)-.37 F .723(ocess gr)-.45 F .723(oup ID)-.45 F F0 5.723 -(.M)C .723(embers of this process group \(processes whose process group ID is) -265.055 456 R .341(equal to the current terminal process group ID\) recei)108 -468 R .642 -.15(ve k)-.25 H -.15(ey).05 G .342(board-generated signals such as) -.15 F F2(SIGINT)2.842 E/F4 9/Times-Roman@0 SF(.)A F0(These)4.842 E .216 -(processes are said to be in the)108 480 R F3(for)2.716 E -.4(eg)-.37 G -.45 -(ro).4 G(und).45 E F0(.).77 E F3(Bac)5.216 E(kgr)-.2 E(ound)-.45 E F0 .215 -(processes are those whose process group ID dif)2.716 F(fers)-.25 E .3 -(from the terminal')108 492 R .3(s; such processes are immune to k)-.55 F -.15 -(ey)-.1 G .3(board-generated signals.).15 F .3(Only fore)5.3 F .3 -(ground processes)-.15 F .253(are allo)108 504 R .253 -(wed to read from or write to the terminal.)-.25 F .252 -(Background processes which attempt to read from \(write)5.252 F 1.03 -(to\) the terminal are sent a)108 516 R F2 1.031(SIGTTIN \(SIGTT)3.531 F(OU\)) --.162 E F0 1.031(signal by the terminal dri)3.281 F -.15(ve)-.25 G 1.831 -.4 -(r, w).15 H 1.031(hich, unless caught, sus-).4 F(pends the process.)108 528 Q -.679(If the operating system on which)108 544.8 R F1(bash)3.179 E F0 .678 -(is running supports job control,)3.178 F F1(bash)3.178 E F0(allo)3.178 E .678 -(ws you to use it.)-.25 F -.8(Ty)5.678 G(ping).8 E(the)108 556.8 Q F3(suspend) -2.681 E F0 .182(character \(typically)2.681 F F1(^Z)2.682 E F0 2.682(,C)C .182 -(ontrol-Z\) while a process is running causes that process to be stopped) -259.988 556.8 R .007(and returns you to)108 568.8 R F1(bash)2.507 E F0 5.007 -(.T)C .007(yping the)215.845 568.8 R F3 .007(delayed suspend)2.507 F F0 .007 -(character \(typically)2.507 F F1(^Y)2.506 E F0 2.506(,C)C .006 -(ontrol-Y\) causes the process)426.402 568.8 R .004(to be stopped when it atte\ -mpts to read input from the terminal, and control to be returned to)108 580.8 R -F1(bash)2.504 E F0 5.004(.Y)C .004(ou may)510.276 580.8 R .619 -(then manipulate the state of this job, using the)108 592.8 R F1(bg)3.118 E F0 -.618(command to continue it in the background, the)3.118 F F1(fg)3.118 E F0 -(com-)3.118 E .825(mand to continue it in the fore)108 604.8 R .825 -(ground, or the)-.15 F F1(kill)3.325 E F0 .825(command to kill it.)3.325 F(A) -5.825 E F1(^Z)3.326 E F0(tak)3.326 E .826(es ef)-.1 F .826(fect immediately) --.25 F 3.326(,a)-.65 G(nd)530 604.8 Q(has the additional side ef)108 616.8 Q -(fect of causing pending output and typeahead to be discarded.)-.25 E 1.098 -(There are a number of w)108 633.6 R 1.097(ays to refer to a job in the shell.) --.1 F 1.097(The character)6.097 F F1(%)3.597 E F0 1.097(introduces a job name.) -3.597 F(Job)6.097 E(number)108 645.6 Q F3(n)2.796 E F0 .296 -(may be referred to as)2.796 F F1(%n)2.796 E F0 5.296(.A)C .296 -(job may also be referred to using a pre\214x of the name used to start)270.904 -645.6 R .277(it, or using a substring that appears in its command line.)108 -657.6 R -.15(Fo)5.277 G 2.777(re).15 G(xample,)360.737 657.6 Q F1(%ce)2.777 E -F0 .277(refers to a stopped)2.777 F F1(ce)2.777 E F0(job)2.777 E 5.277(.I)-.4 G -2.777(fa)529.453 657.6 S .38(pre\214x matches more than one job,)108 669.6 R F1 -(bash)2.88 E F0 .38(reports an error)2.88 F 5.38(.U)-.55 G(sing)348.71 669.6 Q -F1(%?ce)2.88 E F0 2.88(,o)C 2.88(nt)402.52 669.6 S .38 -(he other hand, refers to an)413.18 669.6 R 2.88(yj)-.15 G(ob)530 669.6 Q .623 -(containing the string)108 681.6 R F1(ce)3.123 E F0 .622(in its command line.) -3.123 F .622(If the substring matches more than one job,)5.622 F F1(bash)3.122 -E F0 .622(reports an)3.122 F(error)108 693.6 Q 5.143(.T)-.55 G .143(he symbols) -140.633 693.6 R F1(%%)2.643 E F0(and)2.643 E F1(%+)2.643 E F0 .143 -(refer to the shell')2.643 F 2.643(sn)-.55 G .143(otion of the)326.77 693.6 R -F3(curr)2.643 E .143(ent job)-.37 F F0 2.643(,w).23 G .143 -(hich is the last job stopped)432.895 693.6 R .119(while it w)108 705.6 R .119 -(as in the fore)-.1 F 2.619(ground. The)-.15 F F3(pr)2.618 E -.15(ev)-.37 G -.118(ious job).15 F F0 .118(may be referenced using)2.618 F F1<25ad>2.618 E F0 -5.118(.I)C 2.618(no)433.968 705.6 S .118(utput pertaining to jobs)446.586 705.6 -R .076(\(e.g., the output of the)108 717.6 R F1(jobs)2.576 E F0 .076 -(command\), the current job is al)2.576 F -.1(wa)-.1 G .076 -(ys \215agged with a).1 F F1(+)2.576 E F0 2.576(,a)C .076(nd the pre)442.726 -717.6 R .076(vious job with)-.25 F(a)108 729.6 Q F12.5 E F0(.)A 185.675 -(GNU 1995)72 768 R(May 5)2.5 E(14)530 768 Q EP -%%Page: 15 15 -%%BeginPageSetup -BP -%%EndPageSetup -/F0 10/Times-Roman@0 SF -.35(BA)72 48 S 389.54(SH\(1\) B).35 F(ASH\(1\))-.35 E -.444(Simply naming a job can be used to bring it into the fore)108 84 R -(ground:)-.15 E/F1 10/Times-Bold@0 SF(%1)2.943 E F0 .443(is a synon)2.943 F -.443(ym for)-.15 F F1 -.63(``)2.943 G .443(fg %1').63 F(')-.63 E F0 2.943(,b)C -(ringing)511.11 84 Q 1.472(job 1 from the background into the fore)108 96 R -3.972(ground. Similarly)-.15 F(,)-.65 E F1 -.63(``)3.973 G 1.473(%1 &').63 F(') --.63 E F0 1.473(resumes job 1 in the background,)3.973 F(equi)108 108 Q -.25 -(va)-.25 G(lent to).25 E F1 -.63(``)2.5 G(bg %1').63 E(')-.63 E F0(.)A .131 -(The shell learns immediately whene)108 124.8 R -.15(ve)-.25 G 2.631(raj).15 G -.131(ob changes state.)277.796 124.8 R(Normally)5.131 E(,)-.65 E F1(bash)2.631 -E F0 -.1(wa)2.63 G .13(its until it is about to print a).1 F .276 -(prompt before reporting changes in a job')108 136.8 R 2.776(ss)-.55 G .276 -(tatus so as to not interrupt an)286.292 136.8 R 2.776(yo)-.15 G .276 -(ther output.)416.124 136.8 R .276(If the)5.276 F F1(-b)2.776 E F0 .276 -(option to)2.776 F(the)108 148.8 Q F1(set)2.872 E F0 -.2(bu)2.872 G .372 -(iltin command is set,).2 F F1(bash)2.871 E F0 .371 -(reports such changes immediately)2.871 F 5.371(.\()-.65 G .371 -(See also the description of)405.105 148.8 R F1(notify)2.871 E F0 -.25(va)108 -160.8 S(riable under).25 E F1(Shell V)2.5 E(ariables)-.92 E F0(abo)2.5 E -.15 -(ve)-.15 G(.\)).15 E .529(If you attempt to e)108 177.6 R(xit)-.15 E F1(bash) -3.029 E F0 .529(while jobs are stopped, the shell prints a message w)3.029 F -.529(arning you.)-.1 F -1.1(Yo)5.529 G 3.029(um)1.1 G .529(ay then)510.311 -177.6 R .644(use the)108 189.6 R F1(jobs)3.144 E F0 .644 -(command to inspect their status.)3.144 F .644(If you do this, or try to e) -5.644 F .644(xit ag)-.15 F .644(ain immediately)-.05 F 3.144(,y)-.65 G .644 -(ou are not)498.722 189.6 R -.1(wa)108 201.6 S(rned ag).1 E -(ain, and the stopped jobs are terminated.)-.05 E/F2 9/Times-Bold@0 SF(SIGN)72 -218.4 Q(ALS)-.18 E F0(When)108 230.4 Q F1(bash)2.632 E F0 .132(is interacti) -2.632 F -.15(ve)-.25 G 2.632(,i).15 G 2.632(ti)216.178 230.4 S(gnores)224.37 -230.4 Q F2(SIGTERM)2.632 E F0 .132(\(so that)2.382 F F1 .132(kill 0)2.632 F F0 -.133(does not kill an interacti)2.633 F .433 -.15(ve s)-.25 H .133(hell\), and) -.15 F F2(SIGINT)2.633 E F0 .331(is caught and handled \(so that the)108 242.4 R -F1(wait)2.831 E F0 -.2(bu)2.831 G .331(iltin is interruptible\).).2 F .33 -(In all cases,)5.33 F F1(bash)2.83 E F0(ignores)2.83 E F2(SIGQ)2.83 E(UIT)-.09 -E/F3 9/Times-Roman@0 SF(.)A F0 .33(If job)4.83 F(control is in ef)108 254.4 Q -(fect,)-.25 E F1(bash)2.5 E F0(ignores)2.5 E F2(SIGTTIN)2.5 E F3(,)A F2(SIGTT) -2.25 E(OU)-.162 E F3(,)A F0(and)2.25 E F2(SIGTSTP)2.5 E F3(.)A F0 1.657 -(Synchronous jobs started by)108 271.2 R F1(bash)4.157 E F0(ha)4.157 E 1.957 --.15(ve s)-.2 H 1.658(ignals set to the v).15 F 1.658 -(alues inherited by the shell from its parent.)-.25 F 1.43 -(When job control is not in ef)108 283.2 R 1.429 -(fect, background jobs \(jobs started with)-.25 F F1(&)3.929 E F0 3.929(\)i)C -(gnore)419.073 283.2 Q F2(SIGINT)3.929 E F0(and)3.679 E F2(SIGQ)3.929 E(UIT) --.09 E F3(.)A F0 1.95 -(Commands run as a result of command substitution ignore the k)108 295.2 R -.15 -(ey)-.1 G 1.95(board-generated job control signals).15 F F2(SIGTTIN)108 307.2 Q -F3(,)A F2(SIGTT)2.25 E(OU)-.162 E F3(,)A F0(and)2.25 E F2(SIGTSTP)2.5 E F3(.)A -F2(COMMAND EXECUTION)72 324 Q F0 .547(After a command has been split into w)108 -336 R .546(ords, if it results in a simple command and an optional list of ar) --.1 F(gu-)-.18 E(ments, the follo)108 348 Q(wing actions are tak)-.25 E(en.)-.1 -E .379 -(If the command name contains no slashes, the shell attempts to locate it.)108 -364.8 R .379(If there e)5.379 F .379(xists a shell function by)-.15 F .246 -(that name, that function is in)108 376.8 R -.2(vo)-.4 G -.1(ke).2 G 2.746(da) -.1 G 2.746(sd)254.597 376.8 S .246(escribed abo)266.233 376.8 R .546 -.15(ve i) --.15 H(n).15 E F2(FUNCTIONS)2.746 E F3(.)A F0 .246 -(If the name does not match a func-)4.746 F -(tion, the shell searches for it in the list of shell b)108 388.8 Q 2.5 -(uiltins. If)-.2 F 2.5(am)2.5 G(atch is found, that b)356.4 388.8 Q -(uiltin is in)-.2 E -.2(vo)-.4 G -.1(ke).2 G(d.).1 E .309 -(If the name is neither a shell function nor a b)108 405.6 R .31 -(uiltin, and contains no slashes,)-.2 F F1(bash)2.81 E F0 .31 -(searches each element of)2.81 F(the)108 417.6 Q F2 -.666(PA)2.778 G(TH)-.189 E -F0 .277(for a directory containing an e)2.528 F -.15(xe)-.15 G .277 -(cutable \214le by that name.).15 F .277 -(If the search is unsuccessful, the shell)5.277 F -(prints an error message and returns a nonzero e)108 429.6 Q(xit status.)-.15 E -1.089(If the search is successful, or if the command name contains one or more\ - slashes, the shell e)108 446.4 R -.15(xe)-.15 G 1.09(cutes the).15 F .049 -(named program.)108 458.4 R(Ar)5.049 E .049(gument 0 is set to the name gi)-.18 -F -.15(ve)-.25 G .049(n, and the remaining ar).15 F .049 -(guments to the command are set)-.18 F(to the ar)108 470.4 Q(guments gi)-.18 E --.15(ve)-.25 G(n, if an).15 E -.65(y.)-.15 G 1.809(If this e)108 487.2 R -.15 -(xe)-.15 G 1.809(cution f).15 F 1.809(ails because the \214le is not in e)-.1 F --.15(xe)-.15 G 1.809(cutable format, and the \214le is not a directory).15 F -4.309(,i)-.65 G 4.309(ti)526.241 487.2 S(s)536.11 487.2 Q .678(assumed to be a) -108 499.2 R/F4 10/Times-Italic@0 SF .678(shell script)3.178 F F0 3.178(,a\214)C -.678(le containing shell commands.)240.516 499.2 R 3.178(As)5.678 G .678 -(ubshell is spa)384.176 499.2 R .677(wned to e)-.15 F -.15(xe)-.15 G .677 -(cute it.).15 F(This)5.677 E .329 -(subshell reinitializes itself, so that the ef)108 511.2 R .329 -(fect is as if a ne)-.25 F 2.83(ws)-.25 G .33(hell had been in)348.36 511.2 R --.2(vo)-.4 G -.1(ke).2 G 2.83(dt).1 G 2.83(oh)442.3 511.2 S .33 -(andle the script, with)455.13 511.2 R 1.219(the e)108 523.2 R 1.219 -(xception that the locations of commands remembered by the parent \(see)-.15 F -F1(hash)3.719 E F0(belo)3.719 E 3.719(wu)-.25 G(nder)488.496 523.2 Q F2(SHELL) -3.719 E -.09(BU)108 535.2 S(IL).09 E(TIN COMMANDS)-.828 E F3(\))A F0 -(are retained by the child.)2.25 E .347(If the program is a \214le be)108 552 R -.347(ginning with)-.15 F F1(#!)2.847 E F0 2.847(,t)C .348 -(he remainder of the \214rst line speci\214es an interpreter for the pro-) -281.513 552 R 3.178(gram. The)108 564 R .678(shell e)3.178 F -.15(xe)-.15 G -.678(cutes the speci\214ed interpreter on operating systems that do not handle\ - this e).15 F -.15(xe)-.15 G(cutable).15 E 1.192(format themselv)108 576 R -3.692(es. The)-.15 F(ar)3.693 E 1.193 -(guments to the interpreter consist of a single optional ar)-.18 F 1.193 -(gument follo)-.18 F 1.193(wing the)-.25 F 1.131 -(interpreter name on the \214rst line of the program, follo)108 588 R 1.13 -(wed by the name of the program, follo)-.25 F 1.13(wed by the)-.25 F -(command ar)108 600 Q(guments, if an)-.18 E -.65(y.)-.15 G F2(ENVIR)72 616.8 Q -(ONMENT)-.27 E F0 2.353(When a program is in)108 628.8 R -.2(vo)-.4 G -.1(ke).2 -G 4.853(di).1 G 4.853(ti)235.435 628.8 S 4.853(sg)245.848 628.8 S -2.15 -.25 -(iv e)259.591 628.8 T 4.853(na).25 G 4.853(na)285.704 628.8 S 2.353 -(rray of strings called the)299.997 628.8 R F4(en)4.853 E(vir)-.4 E(onment)-.45 -E F0 7.353(.T).68 G 2.354(his is a list of)477.245 628.8 R F4(name)108 640.8 Q -F0A F4(value)A F0(pairs, of the form)2.5 E F4(name)2.5 E F0(=)A F4(value)A -F0(.).18 E .173(The shell allo)108 657.6 R .173(ws you to manipulate the en) --.25 F .172(vironment in se)-.4 F -.15(ve)-.25 G .172(ral w).15 F 2.672 -(ays. On)-.1 F(in)2.672 E -.2(vo)-.4 G .172(cation, the shell scans its o).2 F -(wn)-.25 E(en)108 669.6 Q .186(vironment and creates a parameter for each name\ - found, automatically marking it for)-.4 F F4 -.2(ex)2.687 G(port).2 E F0 .187 -(to child pro-)2.687 F 2.704(cesses. Ex)108 681.6 R .203 -(ecuted commands inherit the en)-.15 F 2.703(vironment. The)-.4 F F1(export) -2.703 E F0(and)2.703 E F1(declar)2.703 E 2.703<65ad>-.18 G(x)433.271 681.6 Q F0 -.203(commands allo)2.703 F 2.703(wp)-.25 G(aram-)516.68 681.6 Q 1.153 -(eters and functions to be added to and deleted from the en)108 693.6 R 3.653 -(vironment. If)-.4 F 1.153(the v)3.653 F 1.154(alue of a parameter in the)-.25 -F(en)108 705.6 Q .64(vironment is modi\214ed, the ne)-.4 F 3.14(wv)-.25 G .64 -(alue becomes part of the en)251.96 705.6 R .64(vironment, replacing the old.) --.4 F .64(The en)5.64 F(viron-)-.4 E .58(ment inherited by an)108 717.6 R 3.08 -(ye)-.15 G -.15(xe)204.45 717.6 S .58(cuted command consists of the shell').15 -F 3.08(si)-.55 G .58(nitial en)373.88 717.6 R .58(vironment, whose v)-.4 F .58 -(alues may be)-.25 F .301(modi\214ed in the shell, less an)108 729.6 R 2.801 -(yp)-.15 G .301(airs remo)236.046 729.6 R -.15(ve)-.15 G 2.801(db).15 G 2.801 -(yt)295.778 729.6 S(he)306.359 729.6 Q F1(unset)2.801 E F0 .3(command, plus an) -2.8 F 2.8(ya)-.15 G .3(dditions via the)429.92 729.6 R F1(export)2.8 E F0(and) -2.8 E 185.675(GNU 1995)72 768 R(May 5)2.5 E(15)530 768 Q EP -%%Page: 16 16 -%%BeginPageSetup -BP -%%EndPageSetup -/F0 10/Times-Roman@0 SF -.35(BA)72 48 S 389.54(SH\(1\) B).35 F(ASH\(1\))-.35 E -/F1 10/Times-Bold@0 SF(declar)108 84 Q 2.5<65ad>-.18 G(x)147.12 84 Q F0 -(commands.)2.5 E .636(The en)108 100.8 R .636(vironment for an)-.4 F(y)-.15 E -/F2 10/Times-Italic@0 SF .636(simple command)3.136 F F0 .637 -(or function may be augmented temporarily by pre\214xing it with)3.137 F .203 -(parameter assignments, as described abo)108 112.8 R .502 -.15(ve i)-.15 H(n) -.15 E/F3 9/Times-Bold@0 SF -.666(PA)2.702 G(RAMETERS).666 E/F4 9/Times-Roman@0 -SF(.)A F0 .202(These assignment statements af)4.702 F .202(fect only the)-.25 F -(en)108 124.8 Q(vironment seen by that command.)-.4 E .592(If the)108 141.6 R -F13.092 E F0 .592(\215ag is set \(see the)3.092 F F1(set)3.093 E F0 -.2 -(bu)3.093 G .593(iltin command belo).2 F .593(w\), then)-.25 F F2(all)3.093 E -F0 .593(parameter assignments are placed in the)3.093 F(en)108 153.6 Q -(vironment for a command, not just those that precede the command name.)-.4 E -(When)108 170.4 Q F1(bash)3.164 E F0(in)3.164 E -.2(vo)-.4 G -.1(ke).2 G 3.164 -(sa).1 G 3.163(ne)196.232 170.4 S .663(xternal command, the v)208.685 170.4 R -(ariable)-.25 E F1(_)3.163 E F0 .663 -(is set to the full path name of the command and)3.163 F -(passed to that command in its en)108 182.4 Q(vironment.)-.4 E F3(EXIT ST)72 -199.2 Q -.855(AT)-.81 G(US).855 E F0 -.15(Fo)108 211.2 S 2.903(rt).15 G .403 -(he purposes of the shell, a command which e)127.423 211.2 R .403 -(xits with a zero e)-.15 F .403(xit status has succeeded.)-.15 F .404(An e) -5.404 F .404(xit status)-.15 F .322(of zero indicates success.)108 223.2 R -2.821(An)5.322 G .321(on\255zero e)230.409 223.2 R .321(xit status indicates f) --.15 F 2.821(ailure. When)-.1 F 2.821(ac)2.821 G .321(ommand terminates on a f) -419.946 223.2 R(atal)-.1 E(signal,)108 235.2 Q F1(bash)2.5 E F0(uses the v)2.5 -E(alue of 128+)-.25 E F1(signal)A F0(as the e)2.5 E(xit status.)-.15 E .404 -(If a command is not found, the child process created to e)108 252 R -.15(xe) --.15 G .404(cute it returns a status of 127.).15 F .405(If a command is)5.405 F -(found b)108 264 Q(ut is not e)-.2 E -.15(xe)-.15 G -(cutable, the return status is 126.).15 E F1(Bash)108 280.8 Q F0 .202 -(itself returns the e)2.702 F .202(xit status of the last command e)-.15 F -.15 -(xe)-.15 G .201(cuted, unless a syntax error occurs, in which case).15 F(it e) -108 292.8 Q(xits with a non\255zero v)-.15 E 2.5(alue. See)-.25 F(also the)2.5 -E F1(exit)2.5 E F0 -.2(bu)2.5 G(iltin command belo).2 E -.65(w.)-.25 G F3(PR)72 -309.6 Q(OMPTING)-.27 E F0 .644(When e)108 321.6 R -.15(xe)-.15 G .644 -(cuting interacti).15 F -.15(ve)-.25 G(ly).15 E(,)-.65 E F1(bash)3.144 E F0 -.645(displays the primary prompt)3.145 F F3(PS1)3.145 E F0 .645 -(when it is ready to read a command,)2.895 F 1.826(and the secondary prompt)108 -333.6 R F3(PS2)4.326 E F0 1.825 -(when it needs more input to complete a command.)4.076 F F1(Bash)6.825 E F0 -(allo)4.325 E 1.825(ws these)-.25 F 1.499(prompt strings to be customized by i\ -nserting a number of backslash-escaped special characters that are)108 345.6 R -(decoded as follo)108 357.6 Q(ws:)-.25 E F1(\\t)144 369.6 Q F0 -(the current time in HH:MM:SS format)180 369.6 Q F1(\\d)144 381.6 Q F0 -(the date in "W)180 381.6 Q(eekday Month Date" format \(e.g., "T)-.8 E -(ue May 26"\))-.45 E F1(\\n)144 393.6 Q F0(ne)180 393.6 Q(wline)-.25 E F1(\\s) -144 405.6 Q F0(the name of the shell, the basename of)180 405.6 Q F1($0)2.5 E -F0(\(the portion follo)2.5 E(wing the \214nal slash\))-.25 E F1(\\w)144 417.6 Q -F0(the current w)180 417.6 Q(orking directory)-.1 E F1(\\W)144 429.6 Q F0 -(the basename of the current w)180 429.6 Q(orking directory)-.1 E F1(\\u)144 -441.6 Q F0(the username of the current user)180 441.6 Q F1(\\h)144 453.6 Q F0 -(the hostname)180 453.6 Q F1(\\#)144 465.6 Q F0 -(the command number of this command)180 465.6 Q F1(\\!)144 477.6 Q F0 -(the history number of this command)180 477.6 Q F1(\\$)144 489.6 Q F0 -(if the ef)180 489.6 Q(fecti)-.25 E .3 -.15(ve U)-.25 H(ID is 0, a).15 E F1(#) -2.5 E F0 2.5(,o)C(therwise a)301.54 489.6 Q F1($)2.5 E(\\nnn)144 501.6 Q F0 -(the character corresponding to the octal number)180 501.6 Q F1(nnn)2.5 E(\\\\) -144 513.6 Q F0 2.5(ab)180 513.6 S(ackslash)191.94 513.6 Q F1(\\[)144 525.6 Q F0 -(be)180 525.6 Q 1.257(gin a sequence of non-printing characters, which could b\ -e used to embed a terminal)-.15 F(control sequence into the prompt)180 537.6 Q -F1(\\])144 549.6 Q F0(end a sequence of non-printing characters)180 549.6 Q -.119(The command number and the history number are usually dif)108 566.4 R .12 -(ferent: the history number of a command is its)-.25 F 1.585(position in the h\ -istory list, which may include commands restored from the history \214le \(see) -108 578.4 R F3(HIST)4.084 E(OR)-.162 E(Y)-.315 E F0(belo)108 590.4 Q .541 -(w\), while the command number is the position in the sequence of commands e) --.25 F -.15(xe)-.15 G .541(cuted during the cur).15 F(-)-.2 E .546 -(rent shell session.)108 602.4 R .546(After the string is decoded, it is e) -5.546 F .546(xpanded via parameter e)-.15 F .546(xpansion, command substitu-) --.15 F(tion, arithmetic e)108 614.4 Q(xpansion, and w)-.15 E(ord splitting.)-.1 -E F3(READLINE)72 631.2 Q F0 1.374 -(This is the library that handles reading input when using an interacti)108 -643.2 R 1.674 -.15(ve s)-.25 H 1.374(hell, unless the).15 F F1 -(\255nolineediting)3.874 E F0 .033(option is gi)108 655.2 R -.15(ve)-.25 G -2.533(n. By).15 F(def)2.533 E .032 -(ault, the line editing commands are similar to those of emacs.)-.1 F 2.532(Av) -5.032 G .032(i-style line editing)467.156 655.2 R(interf)108 667.2 Q -(ace is also a)-.1 E -.25(va)-.2 G(ilable.).25 E .567 -(In this section, the emacs-style notation is used to denote k)108 684 R -.15 -(ey)-.1 G(strok).15 E 3.068(es. Control)-.1 F -.1(ke)3.068 G .568 -(ys are denoted by C\255)-.05 F F2 -.1(ke)C(y)-.2 E F0(,)A 1.196 -(e.g., C\255n means Control\255N.)108 696 R(Similarly)6.196 E(,)-.65 E F2(meta) -3.696 E F0 -.1(ke)3.695 G 1.195(ys are denoted by M\255)-.05 F F2 -.1(ke)C(y) --.2 E F0 3.695(,s)C 3.695(oM)421.18 696 S 1.195(\255x means Meta\255X.)438.765 -696 R(\(On)6.195 E -.1(ke)108 708 S .932(yboards without a)-.05 F F2(meta)3.432 -E F0 -.1(ke)3.432 G 2.232 -.65(y, M)-.05 H.65 E F2(x)A F0 .932(means ESC) -3.432 F F2(x)3.433 E F0 3.433(,i)C .933(.e., press the Escape k)322.8 708 R -1.233 -.15(ey t)-.1 H .933(hen the).15 F F2(x)3.433 E F0 -.1(ke)3.433 G 4.733 --.65(y. T)-.05 H .933(his mak).65 F(es)-.1 E .6(ESC the)108 720 R F2 .6 -(meta pr)3.1 F(e\214x)-.37 E F0 5.6(.T)C .6(he combination M\255C\255)203.91 -720 R F2(x)A F0 .599(means ESC\255Control\255)3.099 F F2(x)A F0 3.099(,o)C -3.099(rp)407.796 720 S .599(ress the Escape k)419.225 720 R .899 -.15(ey t)-.1 -H .599(hen hold).15 F 185.675(GNU 1995)72 768 R(May 5)2.5 E(16)530 768 Q EP -%%Page: 17 17 -%%BeginPageSetup -BP -%%EndPageSetup -/F0 10/Times-Roman@0 SF -.35(BA)72 48 S 389.54(SH\(1\) B).35 F(ASH\(1\))-.35 E -(the Control k)108 84 Q .3 -.15(ey w)-.1 H(hile pressing the).15 E/F1 10 -/Times-Italic@0 SF(x)2.5 E F0 -.1(ke)2.5 G -.65(y.)-.05 G(\)).65 E 1.125 -(The def)108 100.8 R 1.126(ault k)-.1 F -.15(ey)-.1 G 1.126 -(-bindings may be changed with an).15 F F1(~/.inputr)5.292 E(c)-.37 E F0 3.626 -(\214le. The)5.292 F -.25(va)3.626 G 1.126(lue of the shell v).25 F(ariable) --.25 E/F2 9/Times-Bold@0 SF(INPU-)3.626 E(TRC)108 112.8 Q/F3 9/Times-Roman@0 SF -(,)A F0 .106(if set, is used instead of)2.357 F F1(~/.inputr)2.606 E(c)-.37 E -F0 5.106(.O).31 G .106(ther programs that use this library may add their o) -280.89 112.8 R .106(wn commands)-.25 F(and bindings.)108 124.8 Q -.15(Fo)108 -141.6 S 2.5(re).15 G(xample, placing)128.53 141.6 Q(M\255Control\255u: uni)144 -158.4 Q -.15(ve)-.25 G(rsal\255ar).15 E(gument)-.18 E(or)108 170.4 Q -(C\255Meta\255u: uni)144 182.4 Q -.15(ve)-.25 G(rsal\255ar).15 E(gument)-.18 E -(into the)108 194.4 Q F1(~/.inputr)4.166 E(c)-.37 E F0 -.1(wo)4.166 G(uld mak) -.1 E 2.5(eM)-.1 G(\255C\255u e)244.092 194.4 Q -.15(xe)-.15 G -(cute the readline command).15 E F1(univer)2.5 E(sal\255ar)-.1 E(gument)-.37 E -F0(.).68 E 1.26(The follo)108 211.2 R 1.261 -(wing symbolic character names are recognized:)-.25 F F1 -.4(RU)3.761 G(BOUT).4 -E F0(,)1.27 E F1(DEL)3.761 E F0(,).53 E F1(ESC)3.761 E F0(,).72 E F1(LFD)3.761 -E F0(,).28 E F1(NEWLINE)3.761 E F0(,).73 E F1(RET)3.761 E F0(,)1.27 E F1 -(RETURN)108 223.2 Q F0(,)1.1 E F1(SPC)3.155 E F0(,).72 E F1(SP)3.155 E -.3(AC) --.9 G(E).3 E F0 3.155(,a).73 G(nd)216.315 223.2 Q F1 -.5(TA)3.155 G(B).5 E F0 -5.655(.I).27 G 3.155(na)258.505 223.2 S .655 -(ddition to command names, readline allo)271.1 223.2 R .655(ws k)-.25 F -.15 -(ey)-.1 G 3.154(st).15 G 3.154(ob)475.724 223.2 S 3.154(eb)488.878 223.2 S .654 -(ound to a)501.472 223.2 R(string that is inserted when the k)108 235.2 Q .3 --.15(ey i)-.1 H 2.5(sp).15 G(ressed \(a)263.85 235.2 Q F1(macr)2.5 E(o)-.45 E -F0(\).)A .827 -(Readline is customized by putting commands in an initialization \214le.)108 -252 R .827(The name of this \214le is tak)5.827 F .828(en from)-.1 F 1.325 -(the v)108 264 R 1.325(alue of the)-.25 F F2(INPUTRC)3.825 E F0 -.25(va)3.575 G -3.825(riable. If).25 F 1.324(that v)3.825 F 1.324(ariable is unset, the def) --.25 F 1.324(ault is)-.1 F F1(~/.inputr)3.824 E(c)-.37 E F0 6.324(.W).31 G -1.324(hen a program)479.592 264 R 1.158 -(which uses the readline library starts up, the init \214le is read, and the k) -108 276 R 1.459 -.15(ey b)-.1 H 1.159(indings and v).15 F 1.159 -(ariables are set.)-.25 F .029(There are only a fe)108 288 R 2.529(wb)-.25 G -.029(asic constructs allo)198.135 288 R .028(wed in the readline init \214le.) --.25 F .028(Blank lines are ignored.)5.028 F .028(Lines be)5.028 F(gin-)-.15 E -.553(ning with a)108 300 R/F4 10/Times-Bold@0 SF(#)3.053 E F0 .554 -(are comments.)3.053 F .554(Lines be)5.554 F .554(ginning with a)-.15 F F4($) -3.054 E F0 .554(indicate conditional constructs.)3.054 F .554 -(Other lines denote)5.554 F -.1(ke)108 312 S 2.5(yb)-.05 G(indings and v)129.69 -312 Q(ariable settings.)-.25 E .724(The syntax for controlling k)108 328.8 R -1.024 -.15(ey b)-.1 H .724(indings in the).15 F F1(~/.inputr)3.224 E(c)-.37 E -F0 .724(\214le is simple.)3.224 F .723(All that is required is the name of) -5.724 F .938(the command or the te)108 340.8 R .938(xt of a macro and a k)-.15 -F 1.238 -.15(ey s)-.1 H .938 -(equence to which it should be bound. The name may be).15 F .168 -(speci\214ed in one of tw)108 352.8 R 2.668(ow)-.1 G .168(ays: as a symbolic k) -209.46 352.8 R .468 -.15(ey n)-.1 H .167(ame, possibly with).15 F F1(Meta-) -2.667 E F0(or)2.667 E F1(Contr)2.667 E(ol-)-.45 E F0(pre\214x)2.667 E .167 -(es, or as a k)-.15 F -.15(ey)-.1 G 3.2(sequence. When)108 364.8 R .7 -(using the form)3.2 F F4 -.1(ke)3.2 G(yname).1 E F0(:)A F1(function-name)A F0 -(or)3.201 E F1(macr)3.201 E(o)-.45 E F0(,)A F1 -.1(ke)3.201 G(yname)-.2 E F0 -.701(is the name of a k)3.201 F 1.001 -.15(ey s)-.1 H(pelled).15 E -(out in English.)108 376.8 Q -.15(Fo)5 G 2.5(re).15 G(xample:)192.15 376.8 Q -(Control-u: uni)144 400.8 Q -.15(ve)-.25 G(rsal\255ar).15 E(gument)-.18 E -(Meta-Rubout: backw)144 412.8 Q(ard-kill-w)-.1 E(ord)-.1 E -(Control-o: ">&output")144 424.8 Q .443(In the abo)108 441.6 R .743 -.15(ve ex) --.15 H(ample,).15 E F1(C-u)2.943 E F0 .443(is bound to the function)2.943 F F4 -(uni)2.942 E -.1(ve)-.1 G(rsal\255ar).1 E(gument)-.1 E F0(,)A F1(M-DEL)2.942 E -F0 .442(is bound to the function)2.942 F F4(backward\255kill\255w)108 453.6 Q -(ord)-.1 E F0 2.579(,a)C(nd)207.719 453.6 Q F1(C-o)2.579 E F0 .079 -(is bound to run the macro e)2.579 F .08 -(xpressed on the right hand side \(that is, to insert)-.15 F(the te)108 465.6 Q -(xt)-.15 E F1(>&output)2.5 E F0(into the line\).)2.5 E .36(In the second form,) -108 482.4 R F4("k)2.86 E(eyseq")-.1 E F0(:)A F1(function-name)A F0(or)2.859 E -F1(macr)2.859 E(o)-.45 E F0(,)A F4 -.1(ke)2.859 G(yseq).1 E F0(dif)2.859 E .359 -(fers from)-.25 F F4 -.1(ke)2.859 G(yname).1 E F0(abo)2.859 E .659 -.15(ve i) --.15 H 2.859(nt).15 G .359(hat strings)498.251 482.4 R 1.284 -(denoting an entire k)108 494.4 R 1.584 -.15(ey s)-.1 H 1.284 -(equence may be speci\214ed by placing the sequence within double quotes.).15 F -(Some)6.284 E(GNU Emacs style k)108 506.4 Q .3 -.15(ey e)-.1 H -(scapes can be used, as in the follo).15 E(wing e)-.25 E(xample.)-.15 E -("\\C-u": uni)144 530.4 Q -.15(ve)-.25 G(rsal\255ar).15 E(gument)-.18 E -("\\C-x\\C-r": re\255read\255init\255\214le)144 542.4 Q("\\e[11~": "Function K) -144 554.4 Q .3 -.15(ey 1)-.25 H(").15 E .238(In this e)108 571.2 R(xample,)-.15 -E F1(C-u)2.738 E F0 .238(is ag)2.738 F .238(ain bound to the function)-.05 F F4 -(uni)2.738 E -.1(ve)-.1 G(rsal\255ar).1 E(gument)-.1 E F0(.)A F1 .237(C-x C-r) -5.238 F F0 .237(is bound to the function)2.737 F F4 -.18(re)108 583.2 S -.18 E(ead\255init\255\214le)-.18 E F0 3.909(,a)C(nd)191.139 583.2 Q F1 1.409 -(ESC [ 1 1 ~)3.909 F F0 1.409(is bound to insert the te)3.909 F(xt)-.15 E F4 -1.41(Function K)3.91 F 1.41(ey 1)-.25 F F0 6.41(.T)C 1.41 -(he full set of escape)454.94 583.2 R(sequences is)108 595.2 Q F4<5c43ad>144 -612 Q F0(control pre\214x)180 612 Q F4(\\M-)144 628.8 Q F0(meta pre\214x)180 -628.8 Q F4(\\e)144 645.6 Q F0(an escape character)180 645.6 Q F4(\\\\)144 662.4 -Q F0(backslash)180 662.4 Q F4(\\")144 679.2 Q F0(literal ")180 679.2 Q F4(\\') -144 696 Q F0(literal ')180 696 Q .74(When entering the te)108 712.8 R .74(xt o\ -f a macro, single or double quotes should be used to indicate a macro de\214ni\ -tion.)-.15 F 1.226(Unquoted te)108 724.8 R 1.226 -(xt is assumed to be a function name.)-.15 F 1.227(Backslash will quote an) -6.226 F 3.727(yc)-.15 G 1.227(haracter in the macro te)430.552 724.8 R(xt,)-.15 -E 185.675(GNU 1995)72 768 R(May 5)2.5 E(17)530 768 Q EP -%%Page: 18 18 -%%BeginPageSetup -BP -%%EndPageSetup -/F0 10/Times-Roman@0 SF -.35(BA)72 48 S 389.54(SH\(1\) B).35 F(ASH\(1\))-.35 E -(including " and '.)108 84 Q/F1 10/Times-Bold@0 SF(Bash)108 100.8 Q F0(allo) -2.93 E .43(ws the current readline k)-.25 F .73 -.15(ey b)-.1 H .429 -(indings to be displayed or modi\214ed with the).15 F F1(bind)2.929 E F0 -.2 -(bu)2.929 G .429(iltin command.).2 F .045 -(The editing mode may be switched during interacti)108 112.8 R .345 -.15(ve u) --.25 H .046(se by using the).15 F F12.546 E F0 .046(option to the)2.546 F -F1(set)2.546 E F0 -.2(bu)2.546 G .046(iltin command).2 F(\(see)108 124.8 Q/F2 9 -/Times-Bold@0 SF(SHELL B)2.5 E(UIL)-.09 E(TIN COMMANDS)-.828 E F0(belo)2.25 E -(w\).)-.25 E .044(Readline has v)108 141.6 R .044 -(ariables that can be used to further customize its beha)-.25 F(vior)-.2 E -5.044(.A)-.55 G -.25(va)413.902 141.6 S .043(riable may be set in the).25 F/F3 -10/Times-Italic@0 SF(inpu-)2.543 E(tr)108 153.6 Q(c)-.37 E F0 -(\214le with a statement of the form)2.5 E F1(set)144 170.4 Q F3 -(variable\255name value)2.5 E F0 .488(Except where noted, readline v)108 187.2 -R .489(ariables can tak)-.25 F 2.989(et)-.1 G .489(he v)307.12 187.2 R(alues) --.25 E F1(On)2.989 E F0(or)2.989 E F1(Off)2.989 E F0 5.489(.T)C .489(he v) -404.025 187.2 R .489(ariables and their def)-.25 F .489(ault v)-.1 F(al-)-.25 E -(ues are:)108 199.2 Q F1(horizontal\255scr)108 216 Q(oll\255mode \(Off\))-.18 E -F0 .449(When set to)144 228 R F1(On)2.949 E F0 2.949(,m)C(ak)222.186 228 Q .448 -(es readline use a single line for display)-.1 F 2.948(,s)-.65 G .448 -(crolling the input horizontally on a)398.6 228 R 1.194(single screen line whe\ -n it becomes longer than the screen width rather than wrapping to a ne)144 240 -R(w)-.25 E(line.)144 252 Q F1(editing\255mode \(emacs\))108 264 Q F0 .253 -(Controls whether readline be)144 276 R .253(gins with a set of k)-.15 F .553 --.15(ey b)-.1 H .253(indings similar to).15 F F3(emacs)2.752 E F0(or)2.752 E F3 -(vi)2.752 E F0(.)A F1(editing\255mode)5.252 E F0(can be set to either)144 288 Q -F1(emacs)2.5 E F0(or)2.5 E F1(vi)2.5 E F0(.)A F1 -(mark\255modi\214ed\255lines \(Off\))108 300 Q F0(If set to)144 312 Q F1(On)2.5 -E F0 2.5(,h)C(istory lines that ha)200.39 312 Q .3 -.15(ve b)-.2 H -(een modi\214ed are displayed with a preceding asterisk \().15 E F1(*)A F0(\).) -A F1(bell\255style \(audible\))108 324 Q F0 .01 -(Controls what happens when readline w)144 336 R .011 -(ants to ring the terminal bell.)-.1 F .011(If set to)5.011 F F1(none)2.511 E -F0 2.511(,r)C .011(eadline ne)486.799 336 R -.15(ve)-.25 G(r).15 E .94 -(rings the bell.)144 348 R .94(If set to)5.94 F F1(visible)3.44 E F0 3.44(,r)C -.94(eadline uses a visible bell if one is a)278.91 348 R -.25(va)-.2 G 3.44 -(ilable. If).25 F .94(set to)3.44 F F1(audible)3.44 E F0(,)A -(readline attempts to ring the terminal')144 360 Q 2.5(sb)-.55 G(ell.)306.21 -360 Q F1(comment\255begin \(`)108 372 Q(`#')-.63 E('\))-.63 E F0 -(The string that is inserted in)144 384 Q F1(vi)2.5 E F0(mode when the)2.5 E F1 -(vi\255comment)2.5 E F0(command is e)2.5 E -.15(xe)-.15 G(cuted.).15 E F1 -(meta\255\215ag \(Off\))108 396 Q F0 .227(If set to)144 408 R F1(On)2.727 E F0 -2.727(,r)C .228(eadline will enable eight-bit input \(that is, it will not str\ -ip the high bit from the char)199.628 408 R(-)-.2 E(acters it reads\), re)144 -420 Q -.05(ga)-.15 G(rdless of what the terminal claims it can support.).05 E -F1(con)108 432 Q -.1(ve)-.4 G(rt\255meta \(On\)).1 E F0 .613(If set to)144 444 -R F1(On)3.113 E F0 3.113(,r)C .613(eadline will con)201.172 444 R -.15(ve)-.4 G -.613(rt characters with the eighth bit set to an ASCII k).15 F .912 -.15(ey s) --.1 H .612(equence by).15 F 1.238 -(stripping the eighth bit and prepending an escape character \(in ef)144 456 R -1.238(fect, using escape as the)-.25 F F3(meta)3.738 E(pr)144 468 Q(e\214x)-.37 -E F0(\).)A F1(output\255meta \(Off\))108 480 Q F0 .507(If set to)144 492 R F1 -(On)3.007 E F0 3.007(,r)C .507(eadline will display characters with the eighth\ - bit set directly rather than as a meta-)200.748 492 R(pre\214x)144 504 Q -(ed escape sequence.)-.15 E F1(completion\255query\255items \(100\))108 516 Q -F0 .529(This determines when the user is queried about vie)144 528 R .53 -(wing the number of possible completions gen-)-.25 F .561(erated by the)144 540 -R F1(possible\255completions)3.061 E F0 3.061(command. It)3.061 F .561 -(may be set to an)3.061 F 3.06(yi)-.15 G(nte)428.2 540 Q .56(ger v)-.15 F .56 -(alue greater than or)-.25 F .782(equal to zero.)144 552 R .783 -(If the number of possible completions is greater than or equal to the v)5.782 -F .783(alue of this)-.25 F -.25(va)144 564 S .237(riable, the user is ask).25 F -.237(ed whether or not he wishes to vie)-.1 F 2.737(wt)-.25 G .237 -(hem; otherwise the)389.255 564 R 2.737(ya)-.15 G .237(re simply listed)477.856 -564 R(on the terminal.)144 576 Q F1 -.1(ke)108 588 S(ymap \(emacs\)).1 E F0 -2.323(Set the current readline k)144 600 R -.15(ey)-.1 G 4.823(map. The).15 F -2.323(set of le)4.823 F -.05(ga)-.15 G 4.823(lk).05 G -.15(ey)368.477 600 S -2.323(map names is).15 F F3 2.324(emacs, emacs-standar)4.823 F(d,)-.37 E .809 -(emacs-meta, emacs-ctlx, vi, vi-mo)144 612 R(ve)-.1 E 3.308(,v)-.1 G(i-command) -300.864 612 Q F0 3.308(,a)C(nd)356.102 612 Q F3(vi-insert)3.308 E F0(.).68 E F3 -(vi)5.808 E F0 .808(is equi)3.308 F -.25(va)-.25 G .808(lent to).25 F F3 -(vi-command)3.308 E F0(;)A F3(emacs)144 624 Q F0 1.123(is equi)3.623 F -.25(va) --.25 G 1.124(lent to).25 F F3(emacs-standar)3.624 E(d)-.37 E F0 6.124(.T)C -1.124(he def)317.338 624 R 1.124(ault v)-.1 F 1.124(alue is)-.25 F F3(emacs) -3.624 E F0 3.624(;t).27 G 1.124(he v)431.468 624 R 1.124(alue of)-.25 F F1 -(editing\255mode)3.624 E F0(also af)144 636 Q(fects the def)-.25 E(ault k)-.1 E --.15(ey)-.1 G(map.).15 E F1(sho)108 648 Q(w\255all\255if\255ambiguous \(Off\)) --.1 E F0 .478(This alters the def)144 660 R .478(ault beha)-.1 F .478 -(vior of the completion functions.)-.2 F .477(If set to)5.477 F F1(on)2.977 E -F0 2.977(,w)C .477(ords which ha)450.329 660 R .777 -.15(ve m)-.2 H(ore).15 E -1.264(than one possible completion cause the matches to be listed immediately \ -instead of ringing the)144 672 R(bell.)144 684 Q F1(expand\255tilde \(Off\))108 -696 Q F0(If set to)144 708 Q F1(on)2.5 E F0 2.5(,t)C(ilde e)195.39 708 Q -(xpansion is performed when readline attempts w)-.15 E(ord completion.)-.1 E -.05(Readline implements a f)108 724.8 R .05(acility similar in spirit to the c\ -onditional compilation features of the C preprocessor)-.1 F 185.675(GNU 1995)72 -768 R(May 5)2.5 E(18)530 768 Q EP -%%Page: 19 19 -%%BeginPageSetup -BP -%%EndPageSetup -/F0 10/Times-Roman@0 SF -.35(BA)72 48 S 389.54(SH\(1\) B).35 F(ASH\(1\))-.35 E -1.49(which allo)108 84 R 1.49(ws k)-.25 F 1.79 -.15(ey b)-.1 H 1.49 -(indings and v).15 F 1.49 -(ariable settings to be performed as the result of tests.)-.25 F 1.49 -(There are three)6.49 F(parser directi)108 96 Q -.15(ve)-.25 G 2.5(su).15 G -(sed.)180.91 96 Q/F1 10/Times-Bold@0 SF($if)108 112.8 Q F0(The)144 112.8 Q F1 -($if)2.963 E F0 .463(construct allo)2.963 F .462 -(ws bindings to be made based on the editing mode, the terminal being used,) --.25 F .477(or the application using readline.)144 124.8 R .477(The te)5.477 F -.477(xt of the test e)-.15 F .477(xtends to the end of the line; no characters) --.15 F(are required to isolate it.)144 136.8 Q F1(mode)144 153.6 Q F0(The)180 -153.6 Q F1(mode=)3.712 E F0 1.212(form of the)3.712 F F1($if)3.711 E F0 -(directi)3.711 E 1.511 -.15(ve i)-.25 H 3.711(su).15 G 1.211 -(sed to test whether readline is in emacs or vi)351.631 153.6 R 3.065 -(mode. This)180 165.6 R .565(may be used in conjunction with the)3.065 F F1 -.565(set k)3.065 F(eymap)-.1 E F0 .565(command, for instance, to)3.065 F .03 -(set bindings in the)180 177.6 R/F2 10/Times-Italic@0 SF(emacs-standar)2.529 E -(d)-.37 E F0(and)2.529 E F2(emacs-ctlx)2.529 E F0 -.1(ke)2.529 G .029 -(ymaps only if readline is starting out)-.05 F(in emacs mode.)180 189.6 Q F1 -(term)144 206.4 Q F0(The)180 206.4 Q F1(term=)3.196 E F0 .696 -(form may be used to include terminal-speci\214c k)3.196 F .996 -.15(ey b)-.1 H -.697(indings, perhaps to bind).15 F .654(the k)180 218.4 R .954 -.15(ey s)-.1 H -.654(equences output by the terminal').15 F 3.154(sf)-.55 G .654(unction k) -360.138 218.4 R -.15(ey)-.1 G 3.154(s. The).15 F -.1(wo)3.154 G .654 -(rd on the right side of).1 F(the)180 230.4 Q F1(=)3.003 E F0 .503 -(is tested ag)3.003 F .504 -(ainst the full name of the terminal and the portion of the terminal name)-.05 -F(before the \214rst)180 242.4 Q F12.5 E F0 5(.T)C(his allo)260.13 242.4 Q -(ws)-.25 E F2(sun)2.5 E F0(to match both)2.5 E F2(sun)2.5 E F0(and)2.5 E F2 -(sun\255cmd)2.5 E F0 2.5(,f).77 G(or instance.)456.28 242.4 Q F1(application) -144 259.2 Q F0(The)180 271.2 Q F1(application)2.772 E F0 .272 -(construct is used to include application\255speci\214c settings.)2.772 F .272 -(Each program)5.272 F .114(using the readline library sets the)180 283.2 R F2 -.114(application name)2.614 F F0 2.614(,a)C .114 -(nd an initialization \214le can test for a)395.052 283.2 R .501(particular v) -180 295.2 R 3.001(alue. This)-.25 F .501(could be used to bind k)3.001 F .801 --.15(ey s)-.1 H .5(equences to functions useful for a spe-).15 F .396 -(ci\214c program.)180 307.2 R -.15(Fo)5.396 G 2.896(ri).15 G .396 -(nstance, the follo)261.308 307.2 R .396(wing command adds a k)-.25 F .696 -.15 -(ey s)-.1 H .397(equence that quotes the).15 F(current or pre)180 319.2 Q -(vious w)-.25 E(ord in Bash:)-.1 E F1($if)180 331.2 Q F0(Bash)2.5 E 2.5(#Q)180 -343.2 S(uote the current or pre)194.72 343.2 Q(vious w)-.25 E(ord)-.1 E -("\\C-xq": "\\eb\\"\\ef\\"")180 355.2 Q F1($endif)180 367.2 Q($endif)108 384 Q -F0(This command, as you sa)9.33 E 2.5(wi)-.15 G 2.5(nt)257.73 384 S(he pre) -268.01 384 Q(vious e)-.25 E(xample, terminates an)-.15 E F1($if)2.5 E F0 -(command.)2.5 E F1($else)108 400.8 Q F0(Commands in this branch of the)144 -400.8 Q F1($if)2.5 E F0(directi)2.5 E .3 -.15(ve a)-.25 H(re e).15 E -.15(xe) --.15 G(cuted if the test f).15 E(ails.)-.1 E .62(Readline commands may be gi) -108 417.6 R -.15(ve)-.25 G 3.119(nn).15 G(umeric)255.959 417.6 Q F2(ar)3.119 E -(guments)-.37 E F0 3.119(,w).27 G .619(hich normally act as a repeat count.) -341.807 417.6 R(Sometimes,)5.619 E(ho)108 429.6 Q(we)-.25 E -.15(ve)-.25 G -1.418 -.4(r, i).15 H 3.118(ti).4 G 3.119(st)158.456 429.6 S .619 -(he sign of the ar)168.245 429.6 R .619(gument that is signi\214cant.)-.18 F --.15(Pa)5.619 G .619(ssing a ne).15 F -.05(ga)-.15 G(ti).05 E .919 -.15(ve a) --.25 H -.18(rg).15 G .619(ument to a command that).18 F 1.019(acts in the forw) -108 441.6 R 1.018(ard direction \(e.g.,)-.1 F F1(kill\255line)3.518 E F0 3.518 -(\)c)C 1.018(auses that command to act in a backw)298.478 441.6 R 1.018 -(ard direction.)-.1 F(Com-)6.018 E(mands whose beha)108 453.6 Q(vior with ar) --.2 E(guments de)-.18 E(viates from this are noted.)-.25 E .811 -(When a command is described as)108 470.4 R F2(killing)3.311 E F0(te)3.311 E -.811(xt, the te)-.15 F .811(xt deleted is sa)-.15 F -.15(ve)-.2 G 3.311(df).15 -G .812(or possible future retrie)403.403 470.4 R -.25(va)-.25 G 3.312(l\().25 G -F2(yank-)517.79 470.4 Q(ing)108 482.4 Q F0 3.439(\). The)B .939(killed te)3.439 -F .939(xt is sa)-.15 F -.15(ve)-.2 G 3.439(di).15 G 3.438(na)234.794 482.4 S F2 -(kill\255ring)A F0 5.938(.C)C(onsecuti)302.418 482.4 Q 1.238 -.15(ve k)-.25 H -.938(ills cause the te).15 F .938(xt to be accumulated into one)-.15 F .331 -(unit, which can be yank)108 494.4 R .331(ed all at once.)-.1 F .331 -(Commands which do not kill te)5.331 F .331(xt separate the chunks of te)-.15 F -.331(xt on the)-.15 F(kill\255ring.)108 506.4 Q 1.392(The follo)108 523.2 R -1.391(wing is a list of the names of the commands and the def)-.25 F 1.391 -(ault k)-.1 F 1.691 -.15(ey s)-.1 H 1.391(equences to which the).15 F 3.891(ya) --.15 G(re)532.23 523.2 Q(bound.)108 535.2 Q F1(Commands f)87 552 Q(or Mo)-.25 E -(ving)-.1 E(beginning\255of\255line \(C\255a\))108 564 Q F0(Mo)144 576 Q .3 --.15(ve t)-.15 H 2.5(ot).15 G(he start of the current line.)182.59 576 Q F1 -(end\255of\255line \(C\255e\))108 588 Q F0(Mo)144 600 Q .3 -.15(ve t)-.15 H 2.5 -(ot).15 G(he end of the line.)182.59 600 Q F1 -.25(fo)108 612 S -(rward\255char \(C\255f\)).25 E F0(Mo)144 624 Q .3 -.15(ve f)-.15 H(orw).15 E -(ard a character)-.1 E(.)-.55 E F1(backward\255char \(C\255b\))108 636 Q F0(Mo) -144 648 Q .3 -.15(ve b)-.15 H(ack a character).15 E(.)-.55 E F1 -.25(fo)108 660 -S(rward\255w).25 E(ord \(M\255f\))-.1 E F0(Mo)144 672 Q .822 -.15(ve f)-.15 H -(orw).15 E .522(ard to the end of the ne)-.1 F .523(xt w)-.15 F 3.023(ord. W) --.1 F .523(ords are composed of alphanumeric characters \(let-)-.8 F -(ters and digits\).)144 684 Q F1(backward\255w)108 696 Q(ord \(M\255b\))-.1 E -F0(Mo)144 708 Q .749 -.15(ve b)-.15 H .449 -(ack to the start of this, or the pre).15 F .449(vious, w)-.25 F 2.949(ord. W) --.1 F .448(ords are composed of alphanumeric char)-.8 F(-)-.2 E -(acters \(letters and digits\).)144 720 Q 185.675(GNU 1995)72 768 R(May 5)2.5 E -(19)530 768 Q EP -%%Page: 20 20 -%%BeginPageSetup -BP -%%EndPageSetup -/F0 10/Times-Roman@0 SF -.35(BA)72 48 S 389.54(SH\(1\) B).35 F(ASH\(1\))-.35 E -/F1 10/Times-Bold@0 SF(clear\255scr)108 84 Q(een \(C\255l\))-.18 E F0 .993 -(Clear the screen lea)144 96 R .993 -(ving the current line at the top of the screen.)-.2 F -.4(Wi)5.993 G .993 -(th an ar).4 F .993(gument, refresh the)-.18 F -(current line without clearing the screen.)144 108 Q F1 -.18(re)108 120 S -(draw\255curr).18 E(ent\255line)-.18 E F0(Refresh the current line.)144 132 Q -(By def)5 E(ault, this is unbound.)-.1 E F1(Commands f)87 148.8 Q -(or Manipulating the History)-.25 E(accept\255line \(Newline, Retur)108 160.8 Q -(n\))-.15 E F0 .037(Accept the line re)144 172.8 R -.05(ga)-.15 G .037 -(rdless of where the cursor is.).05 F .037(If this line is non\255empty)5.037 F -2.537(,a)-.65 G .036(dd it to the history list)451.748 172.8 R .699 -(according to the state of the)144 184.8 R/F2 9/Times-Bold@0 SF(HISTCONTR)3.199 -E(OL)-.27 E F0 -.25(va)2.949 G 3.199(riable. If).25 F .699 -(the line is a modi\214ed history line, then)3.199 F -(restore the history line to its original state.)144 196.8 Q F1(pr)108 208.8 Q --.15(ev)-.18 G(ious\255history \(C\255p\)).15 E F0(Fetch the pre)144 220.8 Q -(vious command from the history list, mo)-.25 E(ving back in the list.)-.15 E -F1(next\255history \(C\255n\))108 232.8 Q F0(Fetch the ne)144 244.8 Q -(xt command from the history list, mo)-.15 E(ving forw)-.15 E(ard in the list.) --.1 E F1(beginning\255of\255history \(M\255<\))108 256.8 Q F0(Mo)144 268.8 Q .3 --.15(ve t)-.15 H 2.5(ot).15 G(he \214rst line in the history)182.59 268.8 Q(.) --.65 E F1(end\255of\255history \(M\255>\))108 280.8 Q F0(Mo)144 292.8 Q .3 -.15 -(ve t)-.15 H 2.5(ot).15 G(he end of the input history)182.59 292.8 Q 2.5(,i) --.65 G(.e., the line currently being entered.)294.99 292.8 Q F1 -2.29 -.18 -(re v)108 304.8 T(erse\255sear).08 E(ch\255history \(C\255r\))-.18 E F0 1.471 -(Search backw)144 316.8 R 1.471(ard starting at the current line and mo)-.1 F -1.47(ving `up' through the history as necessary)-.15 F(.)-.65 E -(This is an incremental search.)144 328.8 Q F1 -.25(fo)108 340.8 S -(rward\255sear).25 E(ch\255history \(C\255s\))-.18 E F0 1.131(Search forw)144 -352.8 R 1.131(ard starting at the current line and mo)-.1 F 1.132(ving `do)-.15 -F 1.132(wn' through the history as necessary)-.25 F(.)-.65 E -(This is an incremental search.)144 364.8 Q F1(non\255incr)108 376.8 Q -(emental\255r)-.18 E -2.3 -.15(ev e)-.18 H(rse\255sear).15 E -(ch\255history \(M\255p\))-.18 E F0 1.089(Search backw)144 388.8 R 1.088(ard t\ -hrough the history starting at the current line using a non\255incremental sea\ -rch)-.1 F(for a string supplied by the user)144 400.8 Q(.)-.55 E F1 -(non\255incr)108 412.8 Q(emental\255f)-.18 E(orward\255sear)-.25 E -(ch\255history \(M\255n\))-.18 E F0 1.188(Search forw)144 424.8 R 1.189(ard th\ -rough the history using a non\255incremental search for a string supplied by t\ -he)-.1 F(user)144 436.8 Q(.)-.55 E F1(history\255sear)108 448.8 Q(ch\255f)-.18 -E(orward)-.25 E F0 .249(Search forw)144 460.8 R .249(ard through the history f\ -or the string of characters between the start of the current line)-.1 F -(and the current point.)144 472.8 Q(This is a non-incremental search.)5 E -(By def)5 E(ault, this command is unbound.)-.1 E F1(history\255sear)108 484.8 Q -(ch\255backward)-.18 E F0 .95(Search backw)144 496.8 R .951(ard through the hi\ -story for the string of characters between the start of the current)-.1 F 2.721 -(line and the current point.)144 508.8 R 2.721 -(This is a non-incremental search.)7.721 F 2.72(By def)7.721 F 2.72 -(ault, this command is)-.1 F(unbound.)144 520.8 Q F1(yank\255nth\255ar)108 -532.8 Q 2.5(g\()-.1 G<4dad43ad7929>175.14 532.8 Q F0 .622 -(Insert the \214rst ar)144 544.8 R .622(gument to the pre)-.18 F .622 -(vious command \(usually the second w)-.25 F .622(ord on the pre)-.1 F .622 -(vious line\))-.25 F .682(at point \(the current cursor position\).)144 556.8 R --.4(Wi)5.682 G .682(th an ar).4 F(gument)-.18 E/F3 10/Times-Italic@0 SF(n)3.182 -E F0 3.182(,i).24 G .682(nsert the)390.17 556.8 R F3(n)3.182 E F0 .682(th w)B -.681(ord from the pre)-.1 F(vious)-.25 E .729(command \(the w)144 568.8 R .729 -(ords in the pre)-.1 F .729(vious command be)-.25 F .729(gin with w)-.15 F .729 -(ord 0\).)-.1 F 3.23(An)5.73 G -2.25 -.15(eg a)441.56 568.8 T(ti).15 E 1.03 --.15(ve a)-.25 H -.18(rg).15 G .73(ument inserts).18 F(the)144 580.8 Q F3(n)2.5 -E F0(th w)A(ord from the end of the pre)-.1 E(vious command.)-.25 E F1 -(yank\255last\255ar)108 592.8 Q 2.5(g\()-.1 G -1.667(M\255. ,)175.69 592.8 R --1.667(M\255_ \))2.5 F F0 1.077(Insert the last ar)144 604.8 R 1.077 -(gument to the pre)-.18 F 1.077(vious command \(the last w)-.25 F 1.077 -(ord on the pre)-.1 F 1.077(vious line\).)-.25 F -.4(Wi)6.076 G 1.076(th an).4 -F(ar)144 616.8 Q(gument, beha)-.18 E .3 -.15(ve ex)-.2 H(actly lik).15 E(e)-.1 -E F1(yank-nth-ar)2.5 E(g)-.1 E F0(.)A F1 -(shell\255expand\255line \(M\255C\255e\))108 628.8 Q F0 .223 -(Expand the line the w)144 640.8 R .223(ay the shell does when it reads it.)-.1 -F .224(This performs alias and history e)5.224 F(xpansion)-.15 E .161 -(as well as all of the shell w)144 652.8 R .161(ord e)-.1 F 2.661 -(xpansions. See)-.15 F F2(HIST)2.661 E(OR)-.162 E 2.411(YE)-.315 G(XP)387.555 -652.8 Q(ANSION)-.666 E F0(belo)2.411 E 2.661(wf)-.25 G .16(or a description of) -466.479 652.8 R(history e)144 664.8 Q(xpansion.)-.15 E F1 -(history\255expand\255line \(M\255^\))108 676.8 Q F0 .938(Perform history e)144 -688.8 R .939(xpansion on the current line.)-.15 F(See)5.939 E F2(HIST)3.439 E -(OR)-.162 E 3.189(YE)-.315 G(XP)407.662 688.8 Q(ANSION)-.666 E F0(belo)3.189 E -3.439(wf)-.25 G .939(or a descrip-)488.142 688.8 R(tion of history e)144 700.8 -Q(xpansion.)-.15 E 185.675(GNU 1995)72 768 R(May 5)2.5 E(20)530 768 Q EP -%%Page: 21 21 -%%BeginPageSetup -BP -%%EndPageSetup -/F0 10/Times-Roman@0 SF -.35(BA)72 48 S 389.54(SH\(1\) B).35 F(ASH\(1\))-.35 E -/F1 10/Times-Bold@0 SF(insert\255last\255ar)108 84 Q(gument \(M\255.)-.1 E 2.5 -(,M).833 G -1.667(\255_ \))239.143 84 R F0 2.5(As)144 96 S(ynon)157.61 96 Q -(ym for)-.15 E F1(yank\255last\255ar)2.5 E(g)-.1 E F0(.)A F1 -(operate-and-get-next \(C\255o\))108 108 Q F0 .948 -(Accept the current line for e)144 120 R -.15(xe)-.15 G .948 -(cution and fetch the ne).15 F .948(xt line relati)-.15 F 1.247 -.15(ve t)-.25 -H 3.447(ot).15 G .947(he current line from the)441.792 120 R -(history for editing.)144 132 Q(An)5 E 2.5(ya)-.15 G -.18(rg)247.73 132 S -(ument is ignored.).18 E F1(Commands f)87 148.8 Q(or Changing T)-.25 E(ext)-.92 -E(delete\255char \(C\255d\))108 160.8 Q F0 .486 -(Delete the character under the cursor)144 172.8 R 5.486(.I)-.55 G 2.987(fp) -304.636 172.8 S .487(oint is at the be)315.953 172.8 R .487 -(ginning of the line, there are no charac-)-.15 F -(ters in the line, and the last character typed w)144 184.8 Q(as not)-.1 E F1 -(C\255d)2.5 E F0 2.5(,t)C(hen return)377.34 184.8 Q/F2 9/Times-Bold@0 SF(EOF) -2.5 E/F3 9/Times-Roman@0 SF(.)A F1(backward\255delete\255char \(Rubout\))108 -196.8 Q F0 .553(Delete the character behind the cursor)144 208.8 R 5.553(.W) --.55 G .553(hen gi)315.598 208.8 R -.15(ve)-.25 G 3.053(nan).15 G .553 -(umeric ar)370.457 208.8 R .552(gument, sa)-.18 F .852 -.15(ve t)-.2 H .552 -(he deleted te).15 F .552(xt on)-.15 F(the kill\255ring.)144 220.8 Q F1 -(quoted\255insert \(C\255q, C\255v\))108 232.8 Q F0 1.228(Add the ne)144 244.8 -R 1.228(xt character that you type to the line v)-.15 F 3.728(erbatim. This) --.15 F 1.228(is ho)3.728 F 3.729(wt)-.25 G 3.729(oi)446.163 244.8 S 1.229 -(nsert characters lik)457.672 244.8 R(e)-.1 E F1(C\255q)144 256.8 Q F0 2.5(,f)C -(or e)170.81 256.8 Q(xample.)-.15 E F1(tab\255insert \(C-v T)108 268.8 Q(AB\)) --.9 E F0(Insert a tab character)144 280.8 Q(.)-.55 E F1 -(self\255insert \(a, b, A, 1, !, ...\))108 292.8 Q F0 -(Insert the character typed.)144 304.8 Q F1(transpose\255chars \(C\255t\))108 -316.8 Q F0 .424(Drag the character before point forw)144 328.8 R .424(ard o)-.1 -F -.15(ve)-.15 G 2.924(rt).15 G .424(he character at point.)331.218 328.8 R -.424(Point mo)5.424 F -.15(ve)-.15 G 2.924(sf).15 G(orw)477.882 328.8 Q .424 -(ard as well.)-.1 F 1.03 -(If point is at the end of the line, then transpose the tw)144 340.8 R 3.531 -(oc)-.1 G 1.031(haracters before point.)382.266 340.8 R(Ne)6.031 E -.05(ga)-.15 -G(ti).05 E 1.331 -.15(ve a)-.25 H -.18(rg).15 G(u-).18 E(ments don')144 352.8 Q -2.5(tw)-.18 G(ork.)200.94 352.8 Q F1(transpose\255w)108 364.8 Q -(ords \(M\255t\))-.1 E F0 .683(Drag the w)144 376.8 R .682 -(ord behind the cursor past the w)-.1 F .682(ord in front of the cursor mo)-.1 -F .682(ving the cursor o)-.15 F -.15(ve)-.15 G 3.182(rt).15 G(hat)527.78 376.8 -Q -.1(wo)144 388.8 S(rd as well.).1 E F1(upcase\255w)108 400.8 Q -(ord \(M\255u\))-.1 E F0 .702(Uppercase the current \(or follo)144 412.8 R .702 -(wing\) w)-.25 F 3.202(ord. W)-.1 F .702(ith a ne)-.4 F -.05(ga)-.15 G(ti).05 E -1.002 -.15(ve a)-.25 H -.18(rg).15 G .702(ument, do the pre).18 F .703(vious w) --.25 F .703(ord, b)-.1 F(ut)-.2 E(do not mo)144 424.8 Q .3 -.15(ve p)-.15 H -(oint.).15 E F1(do)108 436.8 Q(wncase\255w)-.1 E(ord \(M\255l\))-.1 E F0(Lo)144 -448.8 Q .641(wercase the current \(or follo)-.25 F .641(wing\) w)-.25 F 3.141 -(ord. W)-.1 F .641(ith a ne)-.4 F -.05(ga)-.15 G(ti).05 E .941 -.15(ve a)-.25 H --.18(rg).15 G .64(ument, do the pre).18 F .64(vious w)-.25 F .64(ord, b)-.1 F -(ut)-.2 E(do not mo)144 460.8 Q .3 -.15(ve p)-.15 H(oint.).15 E F1 -(capitalize\255w)108 472.8 Q(ord \(M\255c\))-.1 E F0 .82 -(Capitalize the current \(or follo)144 484.8 R .82(wing\) w)-.25 F 3.32(ord. W) --.1 F .82(ith a ne)-.4 F -.05(ga)-.15 G(ti).05 E 1.12 -.15(ve a)-.25 H -.18(rg) -.15 G .82(ument, do the pre).18 F .82(vious w)-.25 F .82(ord, b)-.1 F(ut)-.2 E -(do not mo)144 496.8 Q .3 -.15(ve p)-.15 H(oint.).15 E F1(Killing and Y)87 -513.6 Q(anking)-.85 E(kill\255line \(C\255k\))108 525.6 Q F0(Kill the te)144 -537.6 Q(xt from the current cursor position to the end of the line.)-.15 E F1 -(backward\255kill\255line \(C\255x C\255Rubout\))108 549.6 Q F0(Kill backw)144 -561.6 Q(ard to the be)-.1 E(ginning of the line.)-.15 E F1 -(unix\255line\255discard \(C\255u\))108 573.6 Q F0(Kill backw)144 585.6 Q -(ard from point to the be)-.1 E(ginning of the line.)-.15 E F1 -(kill\255whole\255line)108 597.6 Q F0 -(Kill all characters on the current line, no matter where the cursor is.)144 -609.6 Q(By def)5 E(ault, this is unbound.)-.1 E F1(kill\255w)108 621.6 Q -(ord \(M\255d\))-.1 E F0 1.044 -(Kill from the cursor to the end of the current w)144 633.6 R 1.043 -(ord, or if between w)-.1 F 1.043(ords, to the end of the ne)-.1 F(xt)-.15 E --.1(wo)144 645.6 S 2.5(rd. W).1 F(ord boundaries are the same as those used by) --.8 E F1 -.25(fo)2.5 G(rward\255w).25 E(ord)-.1 E F0(.)A F1 -(backward\255kill\255w)108 657.6 Q(ord \(M\255Rubout\))-.1 E F0 3.26 -(Kill the w)144 669.6 R 3.26(ord behind the cursor)-.1 F 8.26(.W)-.55 G 3.26 -(ord boundaries are the same as those used by)304.31 669.6 R F1(back-)5.76 E -(ward\255w)144 681.6 Q(ord)-.1 E F0(.)A F1(unix\255w)108 693.6 Q -(ord\255rubout \(C\255w\))-.1 E F0 .482(Kill the w)144 705.6 R .482 -(ord behind the cursor)-.1 F 2.982(,u)-.4 G .482(sing white space as a w) -281.652 705.6 R .482(ord boundary)-.1 F 5.482(.T)-.65 G .482(he w)445.076 705.6 -R .481(ord boundaries are)-.1 F(dif)144 717.6 Q(ferent from backw)-.25 E -(ard\255kill\255w)-.1 E(ord.)-.1 E 185.675(GNU 1995)72 768 R(May 5)2.5 E(21)530 -768 Q EP -%%Page: 22 22 -%%BeginPageSetup -BP -%%EndPageSetup -/F0 10/Times-Roman@0 SF -.35(BA)72 48 S 389.54(SH\(1\) B).35 F(ASH\(1\))-.35 E -/F1 10/Times-Bold@0 SF(delete\255horizontal\255space)108 84 Q F0 -(Delete all spaces and tabs around point.)144 96 Q(By def)5 E -(ault, this is unbound.)-.1 E F1(yank \(C\255y\))108 108 Q F0 -1(Ya)144 120 S -(nk the top of the kill ring into the b)1 E(uf)-.2 E(fer at the cursor)-.25 E -(.)-.55 E F1(yank\255pop \(M\255y\))108 132 Q F0 -(Rotate the kill\255ring, and yank the ne)144 144 Q 2.5(wt)-.25 G 2.5(op. Only) -302.71 144 R -.1(wo)2.5 G(rks follo).1 E(wing)-.25 E F1(yank)2.5 E F0(or)2.5 E -F1(yank\255pop)2.5 E F0(.)A F1(Numeric Ar)87 160.8 Q(guments)-.1 E(digit\255ar) -108 172.8 Q(gument \(M\2550, M\2551, ..., M\255\255\))-.1 E F0 .641 -(Add this digit to the ar)144 184.8 R .641 -(gument already accumulating, or start a ne)-.18 F 3.141(wa)-.25 G -.18(rg) -425.942 184.8 S 3.142(ument. M\255\255).18 F .642(starts a ne)3.142 F(g-)-.15 E -(ati)144 196.8 Q .3 -.15(ve a)-.25 H -.18(rg).15 G(ument.).18 E F1(uni)108 -208.8 Q -.1(ve)-.1 G(rsal\255ar).1 E(gument)-.1 E F0 .783(Each time this is e) -144 220.8 R -.15(xe)-.15 G .783(cuted, the ar).15 F .782 -(gument count is multiplied by four)-.18 F 5.782(.T)-.55 G .782(he ar)437.062 -220.8 R .782(gument count is ini-)-.18 F .175(tially one, so e)144 232.8 R -.15 -(xe)-.15 G .175(cuting this function the \214rst time mak).15 F .176(es the ar) --.1 F .176(gument count four)-.18 F 5.176(.B)-.55 G 2.676(yd)485.028 232.8 S -(ef)497.704 232.8 Q .176(ault, this)-.1 F(is not bound to a k)144 244.8 Q -.15 -(ey)-.1 G(.)-.5 E F1(Completing)87 261.6 Q(complete \(T)108 273.6 Q(AB\))-.9 E -F0 1.137(Attempt to perform completion on the te)144 285.6 R 1.137 -(xt before point.)-.15 F F1(Bash)6.137 E F0 1.137 -(attempts completion treating the)3.637 F(te)144 297.6 Q .532(xt as a v)-.15 F -.532(ariable \(if the te)-.25 F .532(xt be)-.15 F .533(gins with)-.15 F F1($) -3.033 E F0 .533(\), username \(if the te)B .533(xt be)-.15 F .533(gins with) --.15 F F1(~)3.033 E F0 .533(\), hostname \(if the)B(te)144 309.6 Q .702(xt be) --.15 F .702(gins with)-.15 F F1(@)3.202 E F0 .701 -(\), or command \(including aliases and functions\) in turn.)B .701 -(If none of these pro-)5.701 F -(duces a match, \214lename completion is attempted.)144 321.6 Q F1 -(possible\255completions \(M-?\))108 333.6 Q F0 -(List the possible completions of the te)144 345.6 Q(xt before point.)-.15 E F1 -(insert\255completions)108 357.6 Q F0 3.372(Insert all completions of the te) -144 369.6 R 3.372(xt before point that w)-.15 F 3.372(ould ha)-.1 F 3.672 -.15 -(ve b)-.2 H 3.372(een generated by).15 F F1(possi-)5.873 E(ble\255completions) -144 381.6 Q F0 5(.B)C 2.5(yd)227.76 381.6 S(ef)240.26 381.6 Q -(ault, this is not bound to a k)-.1 E -.15(ey)-.1 G(.)-.5 E F1 -(complete\255\214lename \(M\255/\))108 393.6 Q F0 -(Attempt \214lename completion on the te)144 405.6 Q(xt before point.)-.15 E F1 -(possible\255\214lename\255completions \(C\255x /\))108 417.6 Q F0 -(List the possible completions of the te)144 429.6 Q -(xt before point, treating it as a \214lename.)-.15 E F1(complete\255user)108 -441.6 Q(name \(M\255~\))-.15 E F0(Attempt completion on the te)144 453.6 Q -(xt before point, treating it as a username.)-.15 E F1(possible\255user)108 -465.6 Q(name\255completions \(C\255x ~\))-.15 E F0 -(List the possible completions of the te)144 477.6 Q -(xt before point, treating it as a username.)-.15 E F1(complete\255v)108 489.6 -Q(ariable \(M\255$\))-.1 E F0(Attempt completion on the te)144 501.6 Q -(xt before point, treating it as a shell v)-.15 E(ariable.)-.25 E F1 -(possible\255v)108 513.6 Q(ariable\255completions \(C\255x $\))-.1 E F0 -(List the possible completions of the te)144 525.6 Q -(xt before point, treating it as a shell v)-.15 E(ariable.)-.25 E F1 -(complete\255hostname \(M\255@\))108 537.6 Q F0(Attempt completion on the te) -144 549.6 Q(xt before point, treating it as a hostname.)-.15 E F1 -(possible\255hostname\255completions \(C\255x @\))108 561.6 Q F0 -(List the possible completions of the te)144 573.6 Q -(xt before point, treating it as a hostname.)-.15 E F1 -(complete\255command \(M\255!\))108 585.6 Q F0 .581 -(Attempt completion on the te)144 597.6 R .581 -(xt before point, treating it as a command name.)-.15 F .58(Command comple-) -5.58 F .238(tion attempts to match the te)144 609.6 R .238(xt ag)-.15 F .239 -(ainst aliases, reserv)-.05 F .239(ed w)-.15 F .239(ords, shell functions, b) --.1 F .239(uiltins, and \214nally)-.2 F -.15(exe)144 621.6 S -(cutable \214lenames, in that order).15 E(.)-.55 E F1 -(possible\255command\255completions \(C\255x !\))108 633.6 Q F0 -(List the possible completions of the te)144 645.6 Q -(xt before point, treating it as a command name.)-.15 E F1 -(dynamic\255complete\255history \(M-T)108 657.6 Q(AB\))-.9 E F0 .425 -(Attempt completion on the te)144 669.6 R .425 -(xt before point, comparing the te)-.15 F .425(xt ag)-.15 F .424 -(ainst lines from the history list)-.05 F(for possible completion matches.)144 -681.6 Q F1(complete\255into\255braces \(M\255{\))108 693.6 Q F0 .272(Perform \ -\214lename completion and return the list of possible completions enclosed wit\ -hin braces so)144 705.6 R(the list is a)144 717.6 Q -.25(va)-.2 G -(ilable to the shell \(see).25 E F1(Brace Expansion)2.5 E F0(abo)2.5 E -.15(ve) --.15 G(\).).15 E 185.675(GNU 1995)72 768 R(May 5)2.5 E(22)530 768 Q EP -%%Page: 23 23 -%%BeginPageSetup -BP -%%EndPageSetup -/F0 10/Times-Roman@0 SF -.35(BA)72 48 S 389.54(SH\(1\) B).35 F(ASH\(1\))-.35 E -/F1 10/Times-Bold@0 SF -.25(Ke)87 84 S(yboard Macr).25 E(os)-.18 E -(start\255kbd\255macr)108 96 Q 2.5(o\()-.18 G(C-x \()188.93 96 Q(\)).833 E F0 -(Be)144 108 Q(gin sa)-.15 E(ving the characters typed into the current k)-.2 E --.15(ey)-.1 G(board macro.).15 E F1(end\255kbd\255macr)108 120 Q 2.5(o\()-.18 G -(C-x \))184.5 120 Q(\)).833 E F0(Stop sa)144 132 Q -(ving the characters typed into the current k)-.2 E -.15(ey)-.1 G -(board macro and sa).15 E .3 -.15(ve t)-.2 H(he de\214nition.).15 E F1 -(call\255last\255kbd\255macr)108 144 Q 2.5(o\()-.18 G(C-x e\))204.64 144 Q F0 -(Re-e)144 156 Q -.15(xe)-.15 G 1(cute the last k).15 F -.15(ey)-.1 G .999 -(board macro de\214ned, by making the characters in the macro appear as if).15 -F(typed at the k)144 168 Q -.15(ey)-.1 G(board.).15 E F1(Miscellaneous)87 184.8 -Q -.18(re)108 196.8 S.18 E(ead\255init\255\214le \(C\255x C\255r\))-.18 E -F0 .54(Read in the contents of your init \214le, and incorporate an)144 208.8 R -3.041(yb)-.15 G .541(indings or v)385.876 208.8 R .541 -(ariable assignments found)-.25 F(there.)144 220.8 Q F1(abort \(C\255g\))108 -232.8 Q F0 3.249(Abort the current editing command and ring the terminal')144 -244.8 R 5.748(sb)-.55 G 3.248(ell \(subject to the setting of)414.6 244.8 R F1 -(bell\255style)144 256.8 Q F0(\).)A F1(do\255upper)108 268.8 Q(case\255v)-.18 E -(ersion \(M\255a, M\255b, ...\))-.1 E F0 -(Run the command that is bound to the corresponding uppercase character)144 -280.8 Q(.)-.55 E F1(pr)108 292.8 Q(e\214x\255meta \(ESC\))-.18 E F0 -(Metafy the ne)144 304.8 Q(xt character typed.)-.15 E/F2 9/Times-Bold@0 SF(ESC) -5 E F1(f)2.25 E F0(is equi)2.5 E -.25(va)-.25 G(lent to).25 E F1(Meta\255f)2.5 -E F0(.)A F1(undo \(C\255_, C\255x C\255u\))108 316.8 Q F0 -(Incremental undo, separately remembered for each line.)144 328.8 Q F1 -2.29 --.18(re v)108 340.8 T(ert\255line \(M\255r\)).08 E F0 .244 -(Undo all changes made to this line.)144 352.8 R .245(This is lik)5.245 F 2.745 -(et)-.1 G .245(yping the)341.895 352.8 R F1(undo)2.745 E F0 .245 -(command enough times to return)2.745 F(the line to its initial state.)144 -364.8 Q F1(tilde\255expand \(M\255~\))108 376.8 Q F0(Perform tilde e)144 388.8 -Q(xpansion on the current w)-.15 E(ord.)-.1 E F1(dump\255functions)108 400.8 Q -F0 .627(Print all of the functions and their k)144 412.8 R .927 -.15(ey b)-.1 H -.626(indings to the readline output stream.).15 F .626(If a numeric ar)5.626 F -(gu-)-.18 E(ment is supplied, the output is formatted in such a w)144 424.8 Q -(ay that it can be made part of an)-.1 E/F3 10/Times-Italic@0 SF(inputr)2.5 E -(c)-.37 E F0(\214le.)2.5 E F1(display\255shell\255v)108 436.8 Q -(ersion \(C\255x C\255v\))-.1 E F0(Display v)144 448.8 Q -(ersion information about the current instance of)-.15 E F1(bash)2.5 E F0(.)A -F2(HIST)72 465.6 Q(OR)-.162 E(Y)-.315 E F0 .227(When interacti)108 477.6 R -.15 -(ve)-.25 G 2.727(,t).15 G .227(he shell pro)184.424 477.6 R .227 -(vides access to the)-.15 F F3 .227(command history)2.727 F F0 2.727(,t)C .228 -(he list of commands pre)386.34 477.6 R .228(viously typed.)-.25 F .12(The te) -108 489.6 R .12(xt of the last)-.15 F F2(HISTSIZE)2.62 E F0 .12(commands \(def) -2.37 F .119(ault 500\) is sa)-.1 F -.15(ve)-.2 G 2.619(di).15 G 2.619(nah) -367.958 489.6 S .119(istory list.)387.636 489.6 R .119 -(The shell stores each com-)5.119 F .124 -(mand in the history list prior to parameter and v)108 501.6 R .125(ariable e) --.25 F .125(xpansion \(see)-.15 F F2(EXP)2.625 E(ANSION)-.666 E F0(abo)2.375 E --.15(ve)-.15 G 2.625(\)b).15 G .125(ut after history)480.87 501.6 R -.15(ex)108 -513.6 S .267(pansion is performed, subject to the v).15 F .267 -(alues of the shell v)-.25 F(ariables)-.25 E F1(command_oriented_history)2.767 -E F0(and)2.767 E F2(HIST)2.767 E(-)-.828 E(CONTR)108 525.6 Q(OL)-.27 E/F4 9 -/Times-Roman@0 SF(.)A F0 1.191 -(On startup, the history is initialized from the \214le named by the v)5.69 F -(ariable)-.25 E F2(HISTFILE)3.691 E F0(\(def)3.441 E(ault)-.1 E F3 -(~/.bash_history)108 537.6 Q F0(\).)A F2(HISTFILE)5.632 E F0 .632 -(is truncated, if necessary)2.882 F 3.131(,t)-.65 G 3.131(oc)333.656 537.6 S -.631(ontain no more than)346.227 537.6 R F2(HISTFILESIZE)3.131 E F0 3.131 -(lines. The)2.881 F -.2(bu)108 549.6 S .168(iltin command).2 F F1(fc)2.668 E F0 -(\(see)2.668 E F2 .168(SHELL B)2.668 F(UIL)-.09 E .168(TIN COMMANDS)-.828 F F0 -(belo)2.418 E .168(w\) may be used to list or edit and re-e)-.25 F -.15(xe)-.15 -G .168(cute a).15 F .102(portion of the history list.)108 561.6 R(The)5.102 E -F1(history)2.602 E F0 -.2(bu)2.602 G .101 -(iltin can be used to display the history list and manipulate the his-).2 F -.464(tory \214le.)108 573.6 R .464 -(When using the command-line editing, search commands are a)5.464 F -.25(va)-.2 -G .464(ilable in each editing mode that).25 F(pro)108 585.6 Q .483 -(vide access to the history list.)-.15 F .483(When an interacti)5.483 F .783 --.15(ve s)-.25 H .483(hell e).15 F .483(xits, the last)-.15 F F2(HISTSIZE)2.983 -E F0 .482(lines are copied from)2.733 F 1.047(the history list to)108 597.6 R -F2(HISTFILE)3.547 E F4(.)A F0(If)5.548 E F2(HISTFILE)3.548 E F0 1.048 -(is unset, or if the history \214le is unwritable, the history is not)3.298 F -(sa)108 609.6 Q -.15(ve)-.2 G(d.).15 E F2(HIST)72 626.4 Q(OR)-.162 E 2.25(YE) --.315 G(XP)121.284 626.4 Q(ANSION)-.666 E F0 .611 -(The shell supports a history e)108 638.4 R .611 -(xpansion feature that is similar to the history e)-.15 F .61(xpansion in)-.15 -F F1(csh.)3.11 E F0 .61(This section)5.61 F .87 -(describes what syntax features are a)108 650.4 R -.25(va)-.2 G 3.371 -(ilable. This).25 F .871(feature is enabled by def)3.371 F .871 -(ault for interacti)-.1 F 1.171 -.15(ve s)-.25 H .871(hells, and).15 F 2.014 -(can be disabled using the)108 662.4 R F1(+H)4.514 E F0 2.014(option to the) -4.514 F F1(set)4.514 E F0 -.2(bu)4.514 G 2.014(iltin command \(see).2 F F2 -2.013(SHELL B)4.513 F(UIL)-.09 E 2.013(TIN COMMANDS)-.828 F F0(belo)108 674.4 Q -2.5(w\). Non-interacti)-.25 F .3 -.15(ve s)-.25 H -(hells do not perform history e).15 E(xpansion.)-.15 E 1.163(History e)108 -691.2 R 1.163(xpansion is performed immediately after a complete line is read,\ - before the shell breaks it into)-.15 F -.1(wo)108 703.2 S 2.585(rds. It).1 F -(tak)2.585 E .085(es place in tw)-.1 F 2.585(op)-.1 G 2.585(arts. The)228.19 -703.2 R .084(\214rst is to determine which line from the pre)2.585 F .084 -(vious history to use dur)-.25 F(-)-.2 E .915(ing substitution.)108 715.2 R -.915(The second is to select portions of that line for inclusion into the curr\ -ent one.)5.915 F .915(The line)5.915 F .603(selected from the pre)108 727.2 R -.603(vious history is the)-.25 F F3 -.15(ev)3.103 G(ent).15 E F0 3.103(,a)C -.602(nd the portions of that line that are acted upon are)305.444 727.2 R F3 -(wor)3.102 E(ds)-.37 E F0(.)A 185.675(GNU 1995)72 768 R(May 5)2.5 E(23)530 768 -Q EP -%%Page: 24 24 -%%BeginPageSetup -BP -%%EndPageSetup -/F0 10/Times-Roman@0 SF -.35(BA)72 48 S 389.54(SH\(1\) B).35 F(ASH\(1\))-.35 E -1.748(The line is brok)108 84 R 1.749(en into w)-.1 F 1.749(ords in the same f) --.1 F 1.749(ashion as when reading input, so that se)-.1 F -.15(ve)-.25 G(ral) -.15 E/F1 10/Times-Italic@0 SF(metac)4.249 E(har)-.15 E(ac-)-.15 E(ter)108 96 Q -F0 1.785(\255separated w)B 1.785 -(ords surrounded by quotes are considered as one w)-.1 F 4.284(ord. Only)-.1 F -1.784(backslash \()4.284 F/F2 10/Times-Bold@0 SF(\\).833 E F0 4.284(\)a).833 G -1.784(nd single)501.826 96 R(quotes can quote the history escape character)108 -108 Q 2.5(,w)-.4 G(hich is)300.32 108 Q F2(!)3.333 E F0(by def)3.333 E(ault.) --.1 E 2.2(The shell allo)108 124.8 R 2.2(ws control of the v)-.25 F 2.2 -(arious characters used by the history e)-.25 F 2.2 -(xpansion mechanism \(see the)-.15 F(description of)108 136.8 Q F2(histchars) -2.5 E F0(abo)2.5 E .3 -.15(ve u)-.15 H(nder).15 E F2(Shell V)2.5 E(ariables) --.92 E F0(\).)A F2(Ev)87 153.6 Q(ent Designators)-.1 E F0(An e)108 165.6 Q -.15 -(ve)-.25 G -(nt designator is a reference to a command line entry in the history list.).15 -E F2(!)108 182.4 Q F0(Start a history substitution, e)144 182.4 Q -(xcept when follo)-.15 E(wed by a)-.25 E F2(blank)2.5 E F0 2.5(,n)C -.25(ew) -398.6 182.4 S(line, = or \(.).25 E F2(!!)108 194.4 Q F0(Refer to the pre)144 -194.4 Q(vious command.)-.25 E(This is a synon)5 E(ym for `!\2551'.)-.15 E F2(!) -108 206.4 Q F1(n)A F0(Refer to command line)144 206.4 Q F1(n)2.5 E F0(.).24 E -F2<21ad>108 218.4 Q F1(n)A F0(Refer to the current command line minus)144 218.4 -Q F1(n)2.5 E F0(.).24 E F2(!)108 230.4 Q F1(string)A F0 -(Refer to the most recent command starting with)9.33 E F1(string)2.5 E F0(.).22 -E F2(!?)108 242.4 Q F1(string)A F2([?])A F0 -(Refer to the most recent command containing)144 254.4 Q F1(string)2.5 E F0(.) -.22 E/F3 12/Times-Bold@0 SF(^)108 271.4 Q F1(string1)111.996 266.4 Q F3(^) -140.336 271.4 Q F1(string2)144.332 266.4 Q F3(^)172.672 271.4 Q F0 2.66 -(Quick substitution.)144 278.4 R 2.66(Repeat the last command, replacing)7.66 F -F1(string1)5.16 E F0(with)5.16 E F1(string2)5.16 E F0 7.66(.E).02 G(qui)490.34 -278.4 Q -.25(va)-.25 G 2.66(lent to).25 F -.74(``)144 290.4 S(!!:s/).74 E F1 -(string1)A F0(/)A F1(string2)A F0(/')A 2.5('\()-.74 G(see)240.02 290.4 Q F2 -(Modi\214ers)2.5 E F0(belo)2.5 E(w\).)-.25 E F2(!#)108 302.4 Q F0 -(The entire command line typed so f)144 302.4 Q(ar)-.1 E(.)-.55 E F2 -.75(Wo)87 -319.2 S(rd Designators).75 E F0(A)108 331.2 Q F2(:)3.654 E F0 1.154 -(separates the e)3.654 F -.15(ve)-.25 G 1.154(nt speci\214cation from the w).15 -F 1.154(ord designator)-.1 F 6.154(.I)-.55 G 3.654(tc)377.32 331.2 S 1.154 -(an be omitted if the w)388.194 331.2 R 1.155(ord designator)-.1 F(be)108 343.2 -Q .539(gins with a)-.15 F F2(^)3.039 E F0(,)A F2($)3.039 E F0(,)A F2(*)3.039 E -F0 3.039(,o)C(r)200.244 343.2 Q F2(%)3.039 E F0 5.539(.W)C .539 -(ords are numbered from the be)233.292 343.2 R .538 -(ginning of the line, with the \214rst w)-.15 F .538(ord being)-.1 F -(denoted by a 0 \(zero\).)108 355.2 Q F2 2.5(0\()108 372 S(zer)118.83 372 Q -(o\))-.18 E F0(The zeroth w)144 384 Q 2.5(ord. F)-.1 F -(or the shell, this is the command w)-.15 E(ord.)-.1 E F1(n)108 396 Q F0(The) -144 396 Q F1(n)2.5 E F0(th w)A(ord.)-.1 E F2(^)108 408 Q F0(The \214rst ar)144 -408 Q 2.5(gument. That)-.18 F(is, w)2.5 E(ord 1.)-.1 E F2($)108 420 Q F0 -(The last ar)144 420 Q(gument.)-.18 E F2(%)108 432 Q F0(The w)144 432 Q -(ord matched by the most recent `?)-.1 E F1(string)A F0(?' search.)A F1(x)108 -444 Q F2A F1(y)A F0 2.5(Ar)144 444 S(ange of w)157.05 444 Q(ords; `\255)-.1 -E F1(y)A F0 2.5('a)C(bbre)242.56 444 Q(viates `0\255)-.25 E F1(y)A F0('.)A F2 -(*)108 456 Q F0 .315(All of the w)144 456 R .315(ords b)-.1 F .315 -(ut the zeroth.)-.2 F .315(This is a synon)5.315 F .315(ym for `)-.15 F F1 -(1\255$)A F0 2.815('. It)B .315(is not an error to use)2.815 F F2(*)2.816 E F0 -.316(if there is)2.816 F(just one w)144 468 Q(ord in the e)-.1 E -.15(ve)-.25 G -(nt; the empty string is returned in that case.).15 E F2(x*)108 480 Q F0(Abbre) -144 480 Q(viates)-.25 E F1(x\255$)2.5 E F0(.)A F2<78ad>108 492 Q F0(Abbre)144 -492 Q(viates)-.25 E F1(x\255$)2.5 E F0(lik)2.5 E(e)-.1 E F2(x*)2.5 E F0 2.5(,b) -C(ut omits the last w)250.46 492 Q(ord.)-.1 E F2(Modi\214ers)87 508.8 Q F0 .158 -(After the optional w)108 520.8 R .158(ord designator)-.1 F 2.658(,y)-.4 G .158 -(ou can add a sequence of one or more of the follo)256.6 520.8 R .157 -(wing modi\214ers, each)-.25 F(preceded by a `:'.)108 532.8 Q F2(h)108 549.6 Q -F0(Remo)144 549.6 Q .3 -.15(ve a t)-.15 H(railing pathname component, lea).15 E -(ving only the head.)-.2 E F2(r)108 561.6 Q F0(Remo)144 561.6 Q .3 -.15(ve a t) --.15 H(railing suf).15 E(\214x of the form)-.25 E F1(.xxx)2.5 E F0 2.5(,l)C(ea) -313.98 561.6 Q(ving the basename.)-.2 E F2(e)108 573.6 Q F0(Remo)144 573.6 Q .3 --.15(ve a)-.15 H(ll b).15 E(ut the trailing suf)-.2 E(\214x.)-.25 E F2(t)108 -585.6 Q F0(Remo)144 585.6 Q .3 -.15(ve a)-.15 H -(ll leading pathname components, lea).15 E(ving the tail.)-.2 E F2(p)108 597.6 -Q F0(Print the ne)144 597.6 Q 2.5(wc)-.25 G(ommand b)204.02 597.6 Q -(ut do not e)-.2 E -.15(xe)-.15 G(cute it.).15 E F2(q)108 609.6 Q F0 -(Quote the substituted w)144 609.6 Q(ords, escaping further substitutions.)-.1 -E F2(x)108 621.6 Q F0(Quote the substituted w)144 621.6 Q(ords as with)-.1 E F2 -(q)2.5 E F0 2.5(,b)C(ut break into w)304.81 621.6 Q(ords at)-.1 E F2(blanks)2.5 -E F0(and ne)2.5 E(wlines.)-.25 E F2(s/)108 633.6 Q F1(old)A F2(/)A F1(ne)A(w) --.15 E F2(/)A F0(Substitute)144 645.6 Q F1(ne)2.813 E(w)-.15 E F0 .314 -(for the \214rst occurrence of)2.813 F F1(old)2.814 E F0 .314(in the e)2.814 F --.15(ve)-.25 G .314(nt line.).15 F(An)5.314 E 2.814(yd)-.15 G .314 -(elimiter can be used in place)424.29 645.6 R .617(of /.)144 657.6 R .617 -(The \214nal delimiter is optional if it is the last character of the e)5.617 F --.15(ve)-.25 G .617(nt line.).15 F .616(The delimiter may)5.616 F .749 -(be quoted in)144 669.6 R F1(old)3.249 E F0(and)3.249 E F1(ne)3.249 E(w)-.15 E -F0 .749(with a single backslash.)3.249 F .75(If & appears in)5.749 F F1(ne)3.25 -E(w)-.15 E F0 3.25(,i).31 G 3.25(ti)444.66 669.6 S 3.25(sr)453.47 669.6 S .75 -(eplaced by)463.94 669.6 R F1(old)3.25 E F0 5.75(.A).77 G -(single backslash will quote the &.)144 681.6 Q F2(&)108 693.6 Q F0 -(Repeat the pre)144 693.6 Q(vious substitution.)-.25 E F2(g)108 705.6 Q F0 .398 -(Cause changes to be applied o)144 705.6 R -.15(ve)-.15 G 2.898(rt).15 G .398 -(he entire e)284.948 705.6 R -.15(ve)-.25 G .398(nt line.).15 F .397 -(This is used in conjunction with `)5.398 F F2(:s)A F0 2.897('\()C(e.g.,)523.06 -705.6 Q(`)144 717.6 Q F2(:gs/)A F1(old)A F2(/)A F1(ne)A(w)-.15 E F2(/)A F0 -1.218('\) or `)B F2(:&)A F0 3.718('. If)B 1.218(used with `)3.718 F F2(:s)A F0 -1.218(', an)B 3.718(yd)-.15 G 1.219 -(elimiter can be used in place of /, and the \214nal)343.124 717.6 R -(delimiter is optional if it is the last character of the e)144 729.6 Q -.15 -(ve)-.25 G(nt line.).15 E 185.675(GNU 1995)72 768 R(May 5)2.5 E(24)530 768 Q EP -%%Page: 25 25 -%%BeginPageSetup -BP -%%EndPageSetup -/F0 10/Times-Roman@0 SF -.35(BA)72 48 S 389.54(SH\(1\) B).35 F(ASH\(1\))-.35 E -/F1 9/Times-Bold@0 SF(ARITHMETIC EV)72 84 Q(ALU)-1.215 E -.855(AT)-.54 G(ION) -.855 E F0 1.478(The shell allo)108 96 R 1.477(ws arithmetic e)-.25 F 1.477 -(xpressions to be e)-.15 F -.25(va)-.25 G 1.477 -(luated, under certain circumstances \(see the).25 F/F2 10/Times-Bold@0 SF(let) -3.977 E F0 -.2(bu)3.977 G(iltin).2 E 1.232(command and)108 108 R F2 1.232 -(Arithmetic Expansion)3.732 F F0 3.732(\). Ev)B 1.232 -(aluation is done in long inte)-.25 F 1.232(gers with no check for o)-.15 F --.15(ve)-.15 G(r\215o).15 E -.65(w,)-.25 G .279(though di)108 120 R .279 -(vision by 0 is trapped and \215agged as an error)-.25 F 5.278(.T)-.55 G .278 -(he follo)341.626 120 R .278(wing list of operators is grouped into le)-.25 F -(v-)-.25 E(els of equal-precedence operators.)108 132 Q(The le)5 E -.15(ve)-.25 -G(ls are listed in order of decreasing precedence.).15 E F2 2.5108 148.8 -S F0(unary minus and plus)144 148.8 Q F2 2.5(!~)108 160.8 S F0 -(logical and bitwise ne)144 160.8 Q -.05(ga)-.15 G(tion).05 E F2 2.5(*/%)108 -172.8 S F0(multiplication, di)144 172.8 Q(vision, remainder)-.25 E F2 2.5<2bad> -108 184.8 S F0(addition, subtraction)144 184.8 Q F2(<< >>)108 196.8 Q F0 -(left and right bitwise shifts)144 196.8 Q F2(<= >= < >)108 208.8 Q F0 -(comparison)144 220.8 Q F2(== !=)108 232.8 Q F0(equality and inequality)144 -232.8 Q F2(&)108 244.8 Q F0(bitwise AND)144 244.8 Q F2(^)108 256.8 Q F0 -(bitwise e)144 256.8 Q(xclusi)-.15 E .3 -.15(ve O)-.25 H(R).15 E F2(|)108 268.8 -Q F0(bitwise OR)144 268.8 Q F2(&&)108 280.8 Q F0(logical AND)144 280.8 Q F2(||) -108 292.8 Q F0(logical OR)144 292.8 Q F2 2.5(=*)108 304.8 S 2.5(=/)121.2 304.8 -S 2.5(=%)132.18 304.8 S 2.5(=+)150.38 304.8 S 2.5<3dad>164.28 304.8 S 2.5(=<) -178.18 304.8 S(<= >>= &= ^= |=)192.08 304.8 Q F0(assignment)144 316.8 Q .68 -(Shell v)108 333.6 R .68(ariables are allo)-.25 F .68 -(wed as operands; parameter e)-.25 F .68(xpansion is performed before the e) --.15 F .68(xpression is e)-.15 F -.25(va)-.25 G(lu-).25 E 2.785(ated. The)108 -345.6 R -.25(va)2.785 G .284(lue of a parameter is coerced to a long inte).25 F -.284(ger within an e)-.15 F 2.784(xpression. A)-.15 F .284(shell v)2.784 F .284 -(ariable need not)-.25 F(ha)108 357.6 Q .3 -.15(ve i)-.2 H(ts inte).15 E -(ger attrib)-.15 E(ute turned on to be used in an e)-.2 E(xpression.)-.15 E -.049(Constants with a leading 0 are interpreted as octal numbers.)108 374.4 R -2.55(Al)5.049 G(eading)364.89 374.4 Q/F3 10/Times-Italic@0 SF(0x)2.55 E F0(or) -2.55 E F3(0X)2.55 E F0 .05(denotes he)2.55 F 2.55(xadecimal. Oth-)-.15 F .016 -(erwise, numbers tak)108 386.4 R 2.516(et)-.1 G .016(he form [)197.928 386.4 R -F3(base#)A F0 .015(]n, where)B F3(base)2.515 E F0 .015 -(is a decimal number between 2 and 36 representing the)2.515 F -(arithmetic base, and)108 398.4 Q F3(n)2.5 E F0(is a number in that base.)2.5 E -(If)5 E F3(base)2.5 E F0(is omitted, then base 10 is used.)2.5 E .234 -(Operators are e)108 415.2 R -.25(va)-.25 G .234 -(luated in order of precedence.).25 F(Sub-e)5.234 E .234 -(xpressions in parentheses are e)-.15 F -.25(va)-.25 G .235 -(luated \214rst and may).25 F -.15(ove)108 427.2 S -(rride the precedence rules abo).15 E -.15(ve)-.15 G(.).15 E F1(SHELL B)72 444 -Q(UIL)-.09 E(TIN COMMANDS)-.828 E F2(:)108 456 Q F0([)2.5 E F3(ar)A(guments) --.37 E F0(])A .502(No ef)144 468 R .502(fect; the command does nothing be)-.25 -F .502(yond e)-.15 F(xpanding)-.15 E F3(ar)3.002 E(guments)-.37 E F0 .501 -(and performing an)3.001 F 3.001(ys)-.15 G(peci\214ed)508.34 468 Q 2.5 -(redirections. A)144 480 R(zero e)2.5 E(xit code is returned.)-.15 E F2(.)110.5 -496.8 Q F3(\214lename)6.666 E F0([)2.5 E F3(ar)A(guments)-.37 E F0(])A F2(sour) -108 508.8 Q(ce)-.18 E F3(\214lename)2.5 E F0([)2.5 E F3(ar)A(guments)-.37 E F0 -(])A 1.169(Read and e)144 520.8 R -.15(xe)-.15 G 1.169(cute commands from).15 F -F3(\214lename)3.669 E F0 1.169(in the current shell en)3.669 F 1.17 -(vironment and return the e)-.4 F(xit)-.15 E 1.302 -(status of the last command e)144 532.8 R -.15(xe)-.15 G 1.301(cuted from).15 F -F3(\214lename)3.801 E F0 6.301(.I).18 G(f)368.143 532.8 Q F3(\214lename)3.801 E -F0 1.301(does not contain a slash, path-)3.801 F .608(names in)144 544.8 R F1 --.666(PA)3.108 G(TH)-.189 E F0 .608 -(are used to \214nd the directory containing)2.858 F F3(\214lename)3.108 E F0 -5.608(.T).18 G .608(he \214le searched for in)424.339 544.8 R F1 -.666(PA)3.108 -G(TH)-.189 E F0 .201(need not be e)144 556.8 R -.15(xe)-.15 G 2.701 -(cutable. The).15 F .201 -(current directory is searched if no \214le is found in)2.701 F F1 -.666(PA) -2.701 G(TH)-.189 E/F4 9/Times-Roman@0 SF(.)A F0 .201(If an)4.701 F(y)-.15 E F3 -(ar)2.701 E(gu-)-.37 E(ments)144 568.8 Q F0 1.057(are supplied, the)3.557 F -3.557(yb)-.15 G 1.058(ecome the positional parameters when)252.228 568.8 R F3 -(\214le)3.558 E F0 1.058(is e)3.558 F -.15(xe)-.15 G 3.558(cuted. Otherwise).15 -F(the)3.558 E 1.079(positional parameters are unchanged.)144 580.8 R 1.078 -(The return status is the status of the last command e)6.079 F(xited)-.15 E -(within the script \(0 if no commands are e)144 592.8 Q -.15(xe)-.15 G -(cuted\), and f).15 E(alse if)-.1 E F3(\214lename)2.5 E F0(is not found.)2.5 E -F2(alias)108 609.6 Q F0([)2.5 E F3(name)A F0([=)A F3(value)A F0 2.5(].)C(..]) -193.9 609.6 Q F2(Alias)144 621.6 Q F0 1.667(with no ar)4.167 F 1.667 -(guments prints the list of aliases in the form)-.18 F F3(name)4.168 E F0(=)A -F3(value)A F0 1.668(on standard output.)4.168 F .607(When ar)144 633.6 R .607 -(guments are supplied, an alias is de\214ned for each)-.18 F F3(name)3.107 E F0 -(whose)3.107 E F3(value)3.107 E F0 .607(is gi)3.107 F -.15(ve)-.25 G 3.106 -(n. A).15 F(trailing)3.106 E 2.692(space in)144 645.6 R F3(value)5.192 E F0 -2.692(causes the ne)5.192 F 2.692(xt w)-.15 F 2.692(ord to be check)-.1 F 2.693 -(ed for alias substitution when the alias is)-.1 F -.15(ex)144 657.6 S 2.868 -(panded. F).15 F .367(or each)-.15 F F3(name)2.867 E F0 .367(in the ar)2.867 F -.367(gument list for which no)-.18 F F3(value)2.867 E F0 .367 -(is supplied, the name and v)2.867 F(alue)-.25 E 1.716 -(of the alias is printed.)144 669.6 R F2(Alias)6.716 E F0 1.717 -(returns true unless a)4.216 F F3(name)4.217 E F0 1.717(is gi)4.217 F -.15(ve) --.25 G 4.217(nf).15 G 1.717(or which no alias has been)425.605 669.6 R -(de\214ned.)144 681.6 Q F2(bg)108 698.4 Q F0([)2.5 E F3(jobspec)A F0(])A(Place) -144 710.4 Q F3(jobspec)3.485 E F0 .985 -(in the background, as if it had been started with)3.485 F F2(&)3.485 E F0 -5.985(.I)C(f)425.645 710.4 Q F3(jobspec)3.485 E F0 .985(is not present, the) -3.485 F(shell')144 722.4 Q 4.166(sn)-.55 G 1.666(otion of the)178.726 722.4 R -F3(curr)4.166 E 1.666(ent job)-.37 F F0 1.666(is used.)4.166 F F2(bg)6.666 E F3 -(jobspec)4.166 E F0 1.667(returns 0 unless run when job control is)4.167 F -185.675(GNU 1995)72 768 R(May 5)2.5 E(25)530 768 Q EP -%%Page: 26 26 -%%BeginPageSetup -BP -%%EndPageSetup -/F0 10/Times-Roman@0 SF -.35(BA)72 48 S 389.54(SH\(1\) B).35 F(ASH\(1\))-.35 E -1.139(disabled or)144 84 R 3.639(,w)-.4 G 1.138 -(hen run with job control enabled, if)202.258 84 R/F1 10/Times-Italic@0 SF -(jobspec)3.638 E F0 -.1(wa)3.638 G 3.638(sn).1 G 1.138 -(ot found or started without job)412.37 84 R(control.)144 96 Q/F2 10 -/Times-Bold@0 SF(bind)108 112.8 Q F0([)2.5 E F2A F1 -.1(ke)2.5 G(ymap)-.2 -E F0 2.5(][)C F2(\255lvd)189.12 112.8 Q F0 2.5(][)C F2(-q)217.32 112.8 Q F1 -(name)2.5 E F0(])A F2(bind)108 124.8 Q F0([)2.5 E F2A F1 -.1(ke)2.5 G -(ymap)-.2 E F0(])A F2(-f)2.5 E F1(\214lename)2.5 E F2(bind)108 136.8 Q F0([)2.5 -E F2A F1 -.1(ke)2.5 G(ymap)-.2 E F0(])A F1 -.1(ke)2.5 G(yseq)-.2 E F0(:)A -F1(function-name)A F0 .238(Display current)144 148.8 R F2 -.18(re)2.738 G -(adline).18 E F0 -.1(ke)2.738 G 2.738(ya)-.05 G .239 -(nd function bindings, or bind a k)267.832 148.8 R .539 -.15(ey s)-.1 H .239 -(equence to a).15 F F2 -.18(re)2.739 G(adline).18 E F0(function)2.739 E .88 -(or macro.)144 160.8 R .88(The binding syntax accepted is identical to that of) -5.88 F F1(.inputr)3.38 E(c)-.37 E F0 3.38(,b).31 G .88(ut each binding must be) -440.93 160.8 R .38(passed as a separate ar)144 172.8 R .381 -(gument; e.g., '"\\C-x\\C-r": re\255read\255init\255\214le'.)-.18 F .381 -(Options, if supplied, ha)5.381 F .681 -.15(ve t)-.2 H(he).15 E(follo)144 184.8 -Q(wing meanings:)-.25 E F2144 196.8 Q F1 -.1(ke)2.5 G(ymap)-.2 E F0(Use) -180 208.8 Q F1 -.1(ke)5.175 G(ymap)-.2 E F0 2.674(as the k)5.175 F -.15(ey)-.1 -G 2.674(map to be af).15 F 2.674(fected by the subsequent bindings.)-.25 F -(Acceptable)7.674 E F1 -.1(ke)180 220.8 S(ymap)-.2 E F0 2.929(names are)5.428 F -F1 2.929(emacs, emacs-standar)5.429 F 2.929 -(d, emacs-meta, emacs-ctlx, vi, vi-mo)-.37 F(ve)-.1 E 5.429(,v)-.1 G(i-)533.89 -220.8 Q(command)180 232.8 Q F0 3.435(,a)C(nd)229.255 232.8 Q F1(vi-insert)3.435 -E F0(.).68 E F1(vi)5.934 E F0 .934(is equi)3.434 F -.25(va)-.25 G .934(lent to) -.25 F F1(vi-command)3.434 E F0(;)A F1(emacs)3.434 E F0 .934(is equi)3.434 F --.25(va)-.25 G .934(lent to).25 F F1(emacs-)3.434 E(standar)180 244.8 Q(d)-.37 -E F0(.)A F2144 256.8 Q F0(List the names of all)180 256.8 Q F2 -.18(re) -2.5 G(adline).18 E F0(functions)2.5 E F2144 268.8 Q F0 -(List current function names and bindings)180 268.8 Q F2144 280.8 Q F0 -(Dump function names and bindings in such a w)180 280.8 Q(ay that the)-.1 E 2.5 -(yc)-.15 G(an be re-read)423.89 280.8 Q F2144 292.8 Q F1(\214lename)2.5 E -F0(Read k)180 304.8 Q .3 -.15(ey b)-.1 H(indings from).15 E F1(\214lename)2.5 E -F2144 316.8 Q F1(function)2.5 E F0(Query about which k)180 328.8 Q -.15 -(ey)-.1 G 2.5(si).15 G -1.9 -.4(nv o)282.51 328.8 T .2 -.1(ke t).4 H(he named) -.1 E F1(function)2.5 E F0(The return v)144 345.6 Q -(alue is 0 unless an unrecognized option is gi)-.25 E -.15(ve)-.25 G 2.5(no).15 -G 2.5(ra)391.37 345.6 S 2.5(ne)401.64 345.6 S(rror occurred.)413.58 345.6 Q F2 -(br)108 362.4 Q(eak)-.18 E F0([)2.5 E F1(n)A F0(])A .075(Exit from within a)144 -374.4 R F2 -.25(fo)2.575 G(r).25 E F0(,)A F2(while)2.575 E F0 2.575(,o)C(r) -270.86 374.4 Q F2(until)2.575 E F0 2.576(loop. If)2.575 F F1(n)2.576 E F0 .076 -(is speci\214ed, break)2.576 F F1(n)2.576 E F0(le)2.576 E -.15(ve)-.25 G(ls.) -.15 E F1(n)5.076 E F0 .076(must be)2.576 F/F3 10/Symbol SF2.576 E F0 2.576 -(1. If)2.576 F F1(n)2.576 E F0(is)2.576 E .838 -(greater than the number of enclosing loops, all enclosing loops are e)144 -386.4 R 3.338(xited. The)-.15 F .838(return v)3.338 F .838(alue is 0)-.25 F -(unless the shell is not e)144 398.4 Q -.15(xe)-.15 G(cuting a loop when).15 E -F2(br)2.5 E(eak)-.18 E F0(is e)2.5 E -.15(xe)-.15 G(cuted.).15 E F2 -.2(bu)108 -415.2 S(iltin).2 E F1(shell\255b)2.5 E(uiltin)-.2 E F0([)2.5 E F1(ar)A(guments) --.37 E F0(])A(Ex)144 427.2 Q .792(ecute the speci\214ed shell b)-.15 F .792 -(uiltin, passing it)-.2 F F1(ar)3.293 E(guments)-.37 E F0 3.293(,a).27 G .793 -(nd return its e)382.099 427.2 R .793(xit status.)-.15 F .793(This is useful) -5.793 F .603 -(when you wish to de\214ne a function whose name is the same as a shell b)144 -439.2 R .602(uiltin, b)-.2 F .602(ut need the func-)-.2 F .772 -(tionality of the b)144 451.2 R .772(uiltin within the function itself.)-.2 F -(The)5.773 E F2(cd)3.273 E F0 -.2(bu)3.273 G .773 -(iltin is commonly rede\214ned this w).2 F(ay)-.1 E(.)-.65 E -(The return status is f)144 463.2 Q(alse if)-.1 E F1(shell\255b)2.5 E(uiltin) --.2 E F0(is not a shell b)2.5 E(uiltin command.)-.2 E F2(cd)108 480 Q F0([)2.5 -E F1(dir)A F0 5.17(]C)C .21(hange the current directory to)150.67 480 R F1(dir) -2.71 E F0 5.21(.T)C .21(he v)298.01 480 R(ariable)-.25 E/F4 9/Times-Bold@0 SF -(HOME)2.71 E F0 .21(is the def)2.46 F(ault)-.1 E F1(dir)2.71 E F0 5.21(.T).73 G -.21(he v)456.703 480 R(ariable)-.25 E F4(CDP)2.71 E -.855(AT)-.666 G(H).855 E -F0 .337(de\214nes the search path for the directory containing)144 492 R F1 -(dir)2.837 E F0 5.337(.A).73 G(lternati)379.662 492 Q .637 -.15(ve d)-.25 H -.337(irectory names are separated).15 F .31(by a colon \(:\).)144 504 R 2.809 -(An)5.309 G .309(ull directory name in)221.367 504 R F4(CDP)2.809 E -.855(AT) --.666 G(H).855 E F0 .309(is the same as the current directory)2.559 F 2.809(,i) --.65 G .309(.e., `)496.442 504 R(`)-.74 E F2(.)A F0 -.74('')C 5.309(.I).74 G(f) -536.67 504 Q F1(dir)144 516 Q F0(be)3.418 E .918(gins with a slash \(/\), then) --.15 F F4(CDP)3.418 E -.855(AT)-.666 G(H).855 E F0 .918(is not used.)3.168 F -.919(An ar)5.919 F .919(gument of)-.18 F F23.419 E F0 .919(is equi)3.419 F --.25(va)-.25 G .919(lent to).25 F F4($OLD-)3.419 E(PWD)144 528 Q/F5 9 -/Times-Roman@0 SF(.)A F0(The return v)4.5 E(alue is true if the directory w) --.25 E(as successfully changed; f)-.1 E(alse otherwise.)-.1 E F2(command)108 -544.8 Q F0([)2.5 E F2(-pVv)A F0(])A F1(command)2.5 E F0([)2.5 E F1(ar)A(g)-.37 -E F0(...])2.5 E(Run)144 556.8 Q F1(command)2.878 E F0(with)2.878 E F1(ar)2.878 -E(gs)-.37 E F0 .378(suppressing the normal shell function lookup. Only b)2.878 -F .377(uiltin commands or)-.2 F .558(commands found in the)144 568.8 R F4 -.666 -(PA)3.058 G(TH)-.189 E F0 .559(are e)2.809 F -.15(xe)-.15 G 3.059(cuted. If).15 -F(the)3.059 E F23.059 E F0 .559(option is gi)3.059 F -.15(ve)-.25 G .559 -(n, the search for).15 F F1(command)3.059 E F0(is)3.059 E .232 -(performed using a def)144 580.8 R .231(ault v)-.1 F .231(alue for)-.25 F F2 --.74(PA)2.731 G(TH)-.21 E F0 .231 -(that is guaranteed to \214nd all of the standard utilities.)2.731 F(If)5.231 E -.231(either the)144 592.8 R F22.731 E F0(or)2.731 E F22.731 E F0 -.232(option is supplied, a description of)2.732 F F1(command)2.732 E F0 .232 -(is printed.)2.732 F(The)5.232 E F22.732 E F0 .232(option causes)2.732 F -2.711(as)144 604.8 S .211(ingle w)155.041 604.8 R .211 -(ord indicating the command or pathname used to in)-.1 F -.2(vo)-.4 G -.1(ke).2 -G F1(command)2.81 E F0 .21(to be printed; the)2.71 F F22.71 E F0 .475 -(option produces a more v)144 616.8 R .476(erbose description.)-.15 F .476 -(An ar)5.476 F .476(gument of)-.18 F F22.976 E F0 .476 -(disables option checking for the)2.976 F 1.349(rest of the ar)144 628.8 R -3.849(guments. If)-.18 F(the)3.849 E F23.849 E F0(or)3.849 E F2 -3.849 E F0 1.348(option is supplied, the e)3.848 F 1.348(xit status is 0 if) --.15 F F1(command)3.848 E F0 -.1(wa)3.848 G(s).1 E 1.305(found, and 1 if not.) -144 640.8 R 1.305(If neither option is supplied and an error occurred or)6.305 -F F1(command)3.806 E F0 1.306(cannot be)3.806 F .093(found, the e)144 652.8 R -.093(xit status is 127.)-.15 F .092(Otherwise, the e)5.092 F .092 -(xit status of the)-.15 F F2(command)2.592 E F0 -.2(bu)2.592 G .092 -(iltin is the e).2 F .092(xit status of)-.15 F F1(command)144 664.8 Q F0(.).77 -E F2(continue)108 681.6 Q F0([)2.5 E F1(n)A F0(])A .064(Resume the ne)144 693.6 -R .064(xt iteration of the enclosing)-.15 F F2 -.25(fo)2.564 G(r).25 E F0(,)A -F2(while)2.564 E F0 2.564(,o)C(r)366.096 693.6 Q F2(until)2.564 E F0 2.565 -(loop. If)2.565 F F1(n)2.565 E F0 .065(is speci\214ed, resume at the)2.565 F F1 -(n)144 705.6 Q F0 1.169(th enclosing loop.)B F1(n)6.169 E F0 1.169(must be) -3.669 F F33.669 E F0 3.669(1. If)3.669 F F1(n)3.669 E F0 1.169 -(is greater than the number of enclosing loops, the last)3.669 F 1.593 -(enclosing loop \(the `top\255le)144 717.6 R -.15(ve)-.25 G 1.593 -(l' loop\) is resumed.).15 F 1.593(The return v)6.593 F 1.593 -(alue is 0 unless the shell is not)-.25 F -.15(exe)144 729.6 S -(cuting a loop when).15 E F2(continue)2.5 E F0(is e)2.5 E -.15(xe)-.15 G -(cuted.).15 E 185.675(GNU 1995)72 768 R(May 5)2.5 E(26)530 768 Q EP -%%Page: 27 27 -%%BeginPageSetup -BP -%%EndPageSetup -/F0 10/Times-Roman@0 SF -.35(BA)72 48 S 389.54(SH\(1\) B).35 F(ASH\(1\))-.35 E -/F1 10/Times-Bold@0 SF(declar)108 84 Q(e)-.18 E F0([)2.5 E F1(\255frxi)A F0 2.5 -(][)C/F2 10/Times-Italic@0 SF(name)175.16 84 Q F0([=)A F2(value)A F0(]])A F1 -(typeset)108 96 Q F0([)2.5 E F1(\255frxi)A F0 2.5(][)C F2(name)174.23 96 Q F0 -([=)A F2(value)A F0(]])A 1.098(Declare v)144 108 R 1.098(ariables and/or gi) --.25 F 1.398 -.15(ve t)-.25 H 1.098(hem attrib).15 F 3.598(utes. If)-.2 F(no) -3.598 E F2(name)3.598 E F0 3.598(sa)C 1.098(re gi)394.362 108 R -.15(ve)-.25 G -1.098(n, then display the v).15 F 1.098(alues of)-.25 F -.25(va)144 120 S 2.491 -(riables instead.).25 F 2.491(The options can be used to restrict output to v) -7.491 F 2.492(ariables with the speci\214ed)-.25 F(attrib)144 132 Q(ute.)-.2 E -F1144 144 Q F0(Use function names only)180 144 Q F1144 156 Q F0 -(Mak)180 156 Q(e)-.1 E F2(name)5.047 E F0 5.047(sr)C(eadonly)241.644 156 Q -7.547(.T)-.65 G 2.546(hese names cannot then be assigned v)288.811 156 R 2.546 -(alues by subsequent)-.25 F(assignment statements.)180 168 Q F1144 180 Q -F0(Mark)180 180 Q F2(name)2.5 E F0 2.5(sf)C(or e)235.54 180 Q -(xport to subsequent commands via the en)-.15 E(vironment.)-.4 E F1144 -192 Q F0 .557(The v)180 192 R .558(ariable is treated as an inte)-.25 F .558 -(ger; arithmetic e)-.15 F -.25(va)-.25 G .558(luation \(see).25 F/F3 9 -/Times-Bold@0 SF .558(ARITHMETIC EV)3.058 F(ALU)-1.215 E(A-)-.54 E(TION \))180 -204 Q F0(is performed when the v)2.25 E(ariable is assigned a v)-.25 E(alue.) --.25 E 1.219(Using `+' instead of `\255' turns of)144 220.8 R 3.719(ft)-.25 G -1.219(he attrib)289.373 220.8 R 1.219(ute instead.)-.2 F 1.218 -(When used in a function, mak)6.219 F(es)-.1 E F2(name)3.718 E F0(s)A .235 -(local, as with the)144 232.8 R F1(local)2.735 E F0 2.735(command. The)2.735 F -.235(return v)2.735 F .235(alue is 0 unless an ille)-.25 F -.05(ga)-.15 G 2.736 -(lo).05 G .236(ption is encountered, an)443.752 232.8 R .435 -(attempt is made to de\214ne a function using "-f foo=bar", one of the)144 -244.8 R F2(names)2.935 E F0 .434(is not a le)2.935 F -.05(ga)-.15 G 2.934(ls) -.05 G .434(hell v)503.436 244.8 R(ari-)-.25 E .519 -(able name, an attempt is made to turn of)144 256.8 R 3.019(fr)-.25 G .52 -(eadonly status for a readonly v)318.391 256.8 R .52(ariable, or an attempt is) --.25 F(made to display a non-e)144 268.8 Q(xistant function with -f.)-.15 E F1 -(dirs [-l] [+/\255n])108 285.6 Q F0 1.505 -(Display the list of currently remembered directories.)144 297.6 R 1.505 -(Directories are added to the list with the)6.505 F F1(pushd)144 309.6 Q F0 -(command; the)2.5 E F1(popd)2.5 E F0(command mo)2.5 E -.15(ve)-.15 G 2.5(sb).15 -G(ack up through the list.)331.5 309.6 Q F1(+n)144 321.6 Q F0 .13(displays the) -180 321.6 R F2(n)2.63 E F0 .13(th entry counting from the left of the list sho) -B .13(wn by)-.25 F F1(dirs)2.63 E F0 .13(when in)2.63 F -.2(vo)-.4 G -.1(ke).2 -G 2.63(dw).1 G(ith-)526.11 321.6 Q(out options, starting with zero.)180 333.6 Q -F1144 345.6 Q F0 1.342(displays the)180 345.6 R F2(n)3.842 E F0 1.342 -(th entry counting from the right of the list sho)B 1.342(wn by)-.25 F F1(dirs) -3.842 E F0 1.342(when in)3.842 F -.2(vo)-.4 G -.1(ke).2 G(d).1 E -(without options, starting with zero.)180 357.6 Q F1144 369.6 Q F0 .361 -(produces a longer listing; the def)180 369.6 R .361 -(ault listing format uses a tilde to denote the home direc-)-.1 F(tory)180 -381.6 Q(.)-.65 E .381(The return v)144 398.4 R .381(alue is 0 unless an ille) --.25 F -.05(ga)-.15 G 2.881(lo).05 G .381(ption is supplied or)303.798 398.4 R -F2(n)2.88 E F0(inde)2.88 E -.15(xe)-.15 G 2.88(sb).15 G -.15(ey)430.78 398.4 S -.38(ond the end of the direc-).15 F(tory stack.)144 410.4 Q F1(echo)108 427.2 Q -F0([)2.5 E F1(\255neE)A F0 2.5(][)C F2(ar)164.8 427.2 Q(g)-.37 E F0(...])2.5 E -.266(Output the)144 439.2 R F2(ar)2.766 E(g)-.37 E F0 .266 -(s, separated by spaces.)B .266(The return status is al)5.266 F -.1(wa)-.1 G -.267(ys 0.).1 F(If)5.267 E F12.767 E F0 .267 -(is speci\214ed, the trailing)2.767 F(ne)144 451.2 Q .311(wline is suppressed.) --.25 F .311(If the)5.311 F F12.811 E F0 .311(option is gi)2.811 F -.15 -(ve)-.25 G .311(n, interpretation of the follo).15 F .31 -(wing backslash-escaped)-.25 F .873(characters is enabled.)144 463.2 R(The) -5.874 E F13.374 E F0 .874 -(option disables the interpretation of these escape characters, e)3.374 F -.15 -(ve)-.25 G(n).15 E(on systems where the)144 475.2 Q 2.5(ya)-.15 G -(re interpreted by def)241.61 475.2 Q(ault.)-.1 E F1(\\a)144 487.2 Q F0 -(alert \(bell\))180 487.2 Q F1(\\b)144 499.2 Q F0(backspace)180 499.2 Q F1(\\c) -144 511.2 Q F0(suppress trailing ne)180 511.2 Q(wline)-.25 E F1(\\f)144 523.2 Q -F0(form feed)180 523.2 Q F1(\\n)144 535.2 Q F0(ne)180 535.2 Q 2.5(wl)-.25 G -(ine)201.69 535.2 Q F1(\\r)144 547.2 Q F0(carriage return)180 547.2 Q F1(\\t) -144 559.2 Q F0(horizontal tab)180 559.2 Q F1(\\v)144 571.2 Q F0 -.15(ve)180 -571.2 S(rtical tab).15 E F1(\\\\)144 583.2 Q F0(backslash)180 583.2 Q F1(\\nnn) -144 595.2 Q F0(the character whose ASCII code is)180 595.2 Q F2(nnn)2.5 E F0 -(\(octal\))2.5 E F1(enable)108 612 Q F0([)2.5 E F1A F0 2.5(][)C F1 -(\255all)162.03 612 Q F0 2.5(][)C F2(name)187.45 612 Q F0(...])2.5 E .683 -(Enable and disable b)144 624 R .683(uiltin shell commands.)-.2 F .683 -(This allo)5.683 F .683(ws the e)-.25 F -.15(xe)-.15 G .683 -(cution of a disk command which).15 F .324(has the same name as a shell b)144 -636 R .324(uiltin without specifying a full pathname.)-.2 F(If)5.324 E F1 -2.824 E F0 .324(is used, each)2.824 F F2(name)2.824 E F0 .181 -(is disabled; otherwise,)144 648 R F2(names)2.681 E F0 .181(are enabled.)2.681 -F -.15(Fo)5.181 G 2.681(re).15 G .181(xample, to use the)338.817 648 R F1(test) -2.68 E F0 .18(binary found via the)2.68 F F3 -.666(PA)2.68 G(TH)-.189 E F0 .748 -(instead of the shell b)144 660 R .748(uiltin v)-.2 F .748(ersion, type `)-.15 -F .748(`enable -n test')-.74 F 3.248('. If)-.74 F .748(no ar)3.248 F .749 -(guments are gi)-.18 F -.15(ve)-.25 G .749(n, a list of all).15 F .425 -(enabled shell b)144 672 R .425(uiltins is printed.)-.2 F .425(If only)5.425 F -F12.925 E F0 .424(is supplied, a list of all disabled b)2.925 F .424 -(uiltins is printed.)-.2 F(If)5.424 E(only)144 684 Q F1(\255all)2.546 E F0 .046 -(is supplied, the list printed includes all b)2.546 F .047 -(uiltins, with an indication of whether or not each)-.2 F .281(is enabled.)144 -696 R F1(enable)5.281 E F0(accepts)2.781 E F12.781 E F0 .281(as a synon) -2.781 F .281(ym for)-.15 F F1(\255all)2.781 E F0 5.281(.T)C .28(he return v) -370.81 696 R .28(alue is 0 unless a)-.25 F F2(name)2.78 E F0 .28(is not a)2.78 -F(shell b)144 708 Q(uiltin.)-.2 E 185.675(GNU 1995)72 768 R(May 5)2.5 E(27)530 -768 Q EP -%%Page: 28 28 -%%BeginPageSetup -BP -%%EndPageSetup -/F0 10/Times-Roman@0 SF -.35(BA)72 48 S 389.54(SH\(1\) B).35 F(ASH\(1\))-.35 E -/F1 10/Times-Bold@0 SF -2.3 -.15(ev a)108 84 T(l).15 E F0([)2.5 E/F2 10 -/Times-Italic@0 SF(ar)A(g)-.37 E F0(...])2.5 E(The)144 96 Q F2(ar)3.17 E(g)-.37 -E F0 3.17(sa)C .671(re read and concatenated together into a single command.) -187.74 96 R .671(This command is then read)5.671 F .165(and e)144 108 R -.15 -(xe)-.15 G .165(cuted by the shell, and its e).15 F .165 -(xit status is returned as the v)-.15 F .165(alue of the)-.25 F F1 -2.3 -.15 -(ev a)2.664 H(l).15 E F0 2.664(command. If)2.664 F(there)2.664 E(are no)144 120 -Q F2(ar)2.5 E(gs)-.37 E F0 2.5(,o).27 G 2.5(ro)198.89 120 S(nly null ar)209.72 -120 Q(guments,)-.18 E F1 -2.3 -.15(ev a)2.5 H(l).15 E F0(returns true.)2.5 E F1 -(exec)108 136.8 Q F0([[)2.5 E F1A F0(])A F2(command)2.5 E F0([)2.5 E F2(ar) -A(guments)-.37 E F0(]])A(If)144 148.8 Q F2(command)2.91 E F0 .41 -(is speci\214ed, it replaces the shell.)2.91 F .41(No ne)5.41 F 2.91(wp)-.25 G -.41(rocess is created.)371.42 148.8 R(The)5.41 E F2(ar)2.91 E(guments)-.37 E F0 -(become)2.91 E 1.239(the ar)144 160.8 R 1.239(guments to)-.18 F F2(command) -3.739 E F0 6.239(.I)C 3.739(ft)267.646 160.8 S 1.239(he \214rst ar)277.495 -160.8 R 1.238(gument is)-.18 F F13.738 E F0 3.738(,t)C 1.238 -(he shell places a dash in the zeroth ar)376.426 160.8 R(g)-.18 E 1.048 -(passed to)144 172.8 R F2(command)3.548 E F0 6.048(.T).77 G 1.048 -(his is what login does.)239.844 172.8 R 1.048(If the \214le cannot be e)6.048 -F -.15(xe)-.15 G 1.049(cuted for some reason, a).15 F(non-interacti)144 184.8 Q -.911 -.15(ve s)-.25 H .611(hell e).15 F .611(xits, unless the shell v)-.15 F -(ariable)-.25 E F1(no_exit_on_failed_exec)3.111 E F0 -.15(ex)3.111 G .611 -(ists, in which case).15 F .332(it returns f)144 196.8 R 2.832(ailure. An)-.1 F -(interacti)2.832 E .632 -.15(ve s)-.25 H .332(hell returns f).15 F .333 -(ailure if the \214le cannot be e)-.1 F -.15(xe)-.15 G 2.833(cuted. If).15 F F2 -(command)2.833 E F0(is)2.833 E(not speci\214ed, an)144 208.8 Q 2.5(yr)-.15 G -(edirections tak)219.95 208.8 Q 2.5(ee)-.1 G -.25(ff)289.83 208.8 S -(ect in the current shell, and the return status is 0.).25 E F1(exit)108 225.6 -Q F0([)2.5 E F2(n)A F0 6.29(]C)C .123(ause the shell to e)150.67 225.6 R .123 -(xit with a status of)-.15 F F2(n)2.623 E F0 5.123(.I)C(f)315.07 225.6 Q F2(n) -2.623 E F0 .123(is omitted, the e)2.623 F .122 -(xit status is that of the last command)-.15 F -.15(exe)144 237.6 S 2.5 -(cuted. A).15 F(trap on)2.5 E/F3 9/Times-Bold@0 SF(EXIT)2.5 E F0(is e)2.25 E --.15(xe)-.15 G(cuted before the shell terminates.).15 E F1(export)108 254.4 Q -F0([)2.5 E F1(\255nf)A F0 2.5(][).833 G F2(name)166.183 254.4 Q F0([=)A F2(wor) -A(d)-.37 E F0(]] ...)A F1(export \255p)108 266.4 Q F0 .305(The supplied)144 -278.4 R F2(names)2.805 E F0 .305(are mark)2.805 F .305(ed for automatic e)-.1 F -.306(xport to the en)-.15 F .306(vironment of subsequently e)-.4 F -.15(xe)-.15 -G(cuted).15 E 2.694(commands. If)144 290.4 R(the)2.694 E F12.694 E F0 -.193(option is gi)2.693 F -.15(ve)-.25 G .193(n, the).15 F F2(names)2.693 E F0 -.193(refer to functions.)2.693 F .193(If no)5.193 F F2(names)2.693 E F0 .193 -(are gi)2.693 F -.15(ve)-.25 G .193(n, or if the).15 F F1144 302.4 Q F0 -.659(option is supplied, a list of all names that are e)3.159 F .66 -(xported in this shell is printed.)-.15 F(The)5.66 E F13.16 E F0(option) -3.16 E .538(causes the e)144 314.4 R .538(xport property to be remo)-.15 F -.15 -(ve)-.15 G 3.037(df).15 G .537(rom the named v)318.104 314.4 R 3.037 -(ariables. An)-.25 F(ar)3.037 E .537(gument of)-.18 F F13.037 E F0 -(disables)3.037 E .665(option checking for the rest of the ar)144 326.4 R -(guments.)-.18 E F1(export)5.665 E F0 .665(returns an e)3.165 F .666 -(xit status of 0 unless an ille)-.15 F -.05(ga)-.15 G(l).05 E .32 -(option is encountered, one of the)144 338.4 R F2(names)2.82 E F0 .32 -(is not a le)2.82 F -.05(ga)-.15 G 2.82(ls).05 G .32(hell v)366.18 338.4 R .32 -(ariable name, or)-.25 F F12.82 E F0 .32(is supplied with a)2.82 F F2 -(name)144 350.4 Q F0(that is not a function.)2.5 E F1(fc)108 367.2 Q F0([)2.5 E -F1A F2(ename)2.5 E F0 2.5(][)C F1(\255nlr)169.5 367.2 Q F0 2.5(][)C F2 -<8c72>197.14 367.2 Q(st)-.1 E F0 2.5(][)C F2(last)221.76 367.2 Q F0(])A F1 -(fc \255s)108 379.2 Q F0([)2.5 E F2(pat)A F0(=)A F2 -.37(re)C(p).37 E F0 2.5 -(][)C F2(cmd)174.23 379.2 Q F0(])A .664(Fix Command.)144 391.2 R .664 -(In the \214rst form, a range of commands from)5.664 F F2<8c72>3.165 E(st)-.1 E -F0(to)3.165 E F2(last)3.165 E F0 .665(is selected from the his-)3.165 F .968 -(tory list.)144 403.2 R F2 -.45(Fi)5.967 G -.1(rs).45 G(t).1 E F0(and)3.467 E -F2(last)3.467 E F0 .967 -(may be speci\214ed as a string \(to locate the last command be)3.467 F .967 -(ginning with)-.15 F .797(that string\) or as a number \(an inde)144 415.2 R -3.297(xi)-.15 G .797(nto the history list, where a ne)300.753 415.2 R -.05(ga) --.15 G(ti).05 E 1.097 -.15(ve n)-.25 H .797(umber is used as an).15 F(of)144 -427.2 Q .322(fset from the current command number\).)-.25 F(If)5.322 E F2(last) -2.822 E F0 .322(is not speci\214ed it is set to the current command)2.822 F -.019(for listing \(so that)144 439.2 R F1 .019(fc \255l \25510)2.519 F F0 .019 -(prints the last 10 commands\) and to)2.519 F F2<8c72>2.519 E(st)-.1 E F0 2.519 -(otherwise. If)2.519 F F2<8c72>2.519 E(st)-.1 E F0 .019(is not spec-)2.519 F -(i\214ed it is set to the pre)144 451.2 Q -(vious command for editing and \25516 for listing.)-.25 E(The)144 475.2 Q F1 -2.921 E F0 .421(\215ag suppresses the command numbers when listing.)2.921 -F(The)5.421 E F12.921 E F0 .42(\215ag re)2.92 F -.15(ve)-.25 G .42 -(rses the order of the).15 F 3.642(commands. If)144 487.2 R(the)3.642 E F1 -3.642 E F0 1.142(\215ag is gi)3.642 F -.15(ve)-.25 G 1.142 -(n, the commands are listed on standard output.).15 F 1.142(Otherwise, the) -6.142 F .379(editor gi)144 499.2 R -.15(ve)-.25 G 2.879(nb).15 G(y)199.908 -499.2 Q F2(ename)2.879 E F0 .378(is in)2.879 F -.2(vo)-.4 G -.1(ke).2 G 2.878 -(do).1 G 2.878(na\214)285.712 499.2 S .378(le containing those commands.) -306.468 499.2 R(If)5.378 E F2(ename)2.878 E F0 .378(is not gi)2.878 F -.15(ve) --.25 G .378(n, the).15 F -.25(va)144 511.2 S .804(lue of the).25 F F3(FCEDIT) -3.304 E F0 -.25(va)3.054 G .804(riable is used, and the v).25 F .805(alue of) --.25 F F3(EDIT)3.305 E(OR)-.162 E F0(if)3.055 E F3(FCEDIT)3.305 E F0 .805 -(is not set.)3.055 F .805(If neither)5.805 F -.25(va)144 523.2 S 2.218 -(riable is set,).25 F F2(vi)6.384 E F0 2.217(is used.)6.383 F 2.217 -(When editing is complete, the edited commands are echoed and)7.217 F -.15(exe) -144 535.2 S(cuted.).15 E .039(In the second form,)144 559.2 R F2(command)2.539 -E F0 .039(is re-e)2.539 F -.15(xe)-.15 G .039(cuted after each instance of).15 -F F2(pat)2.54 E F0 .04(is replaced by)2.54 F F2 -.37(re)2.54 G(p).37 E F0 5.04 -(.A)C(useful)515.56 559.2 Q 1.009(alias to use with this is `)144 571.2 R 1.008 -(`r=fc \255s')-.74 F 1.008(', so that typing `)-.74 F 1.008(`r cc')-.74 F 3.508 -('r)-.74 G 1.008(uns the last command be)385.39 571.2 R 1.008(ginning with)-.15 -F -.74(``)144 583.2 S(cc').74 E 2.5('a)-.74 G(nd typing `)171.66 583.2 Q(`r') --.74 E 2.5('r)-.74 G(e-e)233.22 583.2 Q -.15(xe)-.15 G(cutes the last command.) -.15 E .426(If the \214rst form is used, the return v)144 607.2 R .427 -(alue is 0 unless an ille)-.25 F -.05(ga)-.15 G 2.927(lo).05 G .427 -(ption is encountered or)399.768 607.2 R F2<8c72>2.927 E(st)-.1 E F0(or)2.927 E -F2(last)2.927 E F0 .455(specify history lines out of range.)144 619.2 R .454 -(If the)5.454 F F12.954 E F0 .454(option is supplied, the return v)2.954 -F .454(alue is the v)-.25 F .454(alue of the)-.25 F .787(last command e)144 -631.2 R -.15(xe)-.15 G .787(cuted or f).15 F .788 -(ailure if an error occurs with the temporary \214le of commands.)-.1 F .788 -(If the)5.788 F 1.196 -(second form is used, the return status is that of the command re-e)144 643.2 R --.15(xe)-.15 G 1.196(cuted, unless).15 F F2(cmd)3.696 E F0 1.196(does not)3.696 -F(specify a v)144 655.2 Q(alid history line, in which case)-.25 E F1(fc)2.5 E -F0(returns f)2.5 E(ailure.)-.1 E F1(fg)108 672 Q F0([)2.5 E F2(jobspec)A F0(])A -(Place)144 684 Q F2(jobspec)3.041 E F0 .541(in the fore)3.041 F .542 -(ground, and mak)-.15 F 3.042(ei)-.1 G 3.042(tt)323.06 684 S .542 -(he current job)331.662 684 R 5.542(.I)-.4 G(f)399.258 684 Q F2(jobspec)3.042 E -F0 .542(is not present, the shell')3.042 F(s)-.55 E .958(notion of the)144 696 -R F2(curr)3.458 E .958(ent job)-.37 F F0 .957(is used.)3.457 F .957 -(The return v)5.957 F .957(alue is that of the command placed into the fore-) --.25 F .194(ground, or f)144 708 R .194 -(ailure if run when job control is disabled or)-.1 F 2.695(,w)-.4 G .195 -(hen run with job control enabled, if)378.655 708 R F2(job-)2.695 E(spec)144 -720 Q F0(does not specify a v)2.5 E(alid job or)-.25 E F2(jobspec)2.5 E F0 -(speci\214es a job that w)2.5 E(as started without job control.)-.1 E 185.675 -(GNU 1995)72 768 R(May 5)2.5 E(28)530 768 Q EP -%%Page: 29 29 -%%BeginPageSetup -BP -%%EndPageSetup -/F0 10/Times-Roman@0 SF -.35(BA)72 48 S 389.54(SH\(1\) B).35 F(ASH\(1\))-.35 E -/F1 10/Times-Bold@0 SF(getopts)108 84 Q/F2 10/Times-Italic@0 SF(optstring name) -2.5 E F0([)2.5 E F2(ar)A(gs)-.37 E F0(])A F1(getopts)144 96 Q F0 .828 -(is used by shell procedures to parse positional parameters.)3.328 F F2 -(optstring)5.827 E F0 .827(contains the option)3.327 F .602 -(letters to be recognized; if a letter is follo)144 108 R .603 -(wed by a colon, the option is e)-.25 F .603(xpected to ha)-.15 F .903 -.15 -(ve a)-.2 H 3.103(na).15 G -.18(rg)523.52 108 S(u-).18 E .7 -(ment, which should be separated from it by white space.)144 120 R .7 -(Each time it is in)5.7 F -.2(vo)-.4 G -.1(ke).2 G(d,).1 E F1(getopts)3.2 E F0 -(places)3.2 E .008(the ne)144 132 R .008(xt option in the shell v)-.15 F -(ariable)-.25 E F2(name)2.508 E F0 2.508(,i).18 G(nitializing)316.884 132 Q F2 -(name)2.508 E F0 .009(if it does not e)2.508 F .009(xist, and the inde)-.15 F -2.509(xo)-.15 G 2.509(ft)521.941 132 S(he)530.56 132 Q(ne)144 144 Q .199(xt ar) --.15 F .199(gument to be processed into the v)-.18 F(ariable)-.25 E/F3 9 -/Times-Bold@0 SF(OPTIND)2.699 E/F4 9/Times-Roman@0 SF(.)A F3(OPTIND)4.699 E F0 -.198(is initialized to 1 each time the)2.449 F .497 -(shell or a shell script is in)144 156 R -.2(vo)-.4 G -.1(ke).2 G 2.997 -(d. When).1 F .498(an option requires an ar)2.997 F(gument,)-.18 E F1(getopts) -2.998 E F0 .498(places that ar)2.998 F(gu-)-.18 E .028(ment into the v)144 168 -R(ariable)-.25 E F3(OPT)2.528 E(ARG)-.81 E F4(.)A F0 .028 -(The shell does not reset)4.528 F F3(OPTIND)2.528 E F0 .027 -(automatically; it must be manu-)2.278 F .161 -(ally reset between multiple calls to)144 180 R F1(getopts)2.661 E F0 .161 -(within the same shell in)2.661 F -.2(vo)-.4 G .161(cation if a ne).2 F 2.662 -(ws)-.25 G .162(et of param-)490.806 180 R(eters is to be used.)144 192 Q F1 -(getopts)144 216 Q F0 1.252(can report errors in tw)3.752 F 3.752(ow)-.1 G -3.752(ays. If)287.942 216 R 1.252(the \214rst character of)3.752 F F2 -(optstring)3.752 E F0 1.251(is a colon,)3.752 F F2(silent)3.751 E F0(error) -3.751 E 1.442(reporting is used.)144 228 R 1.442 -(In normal operation diagnostic messages are printed when ille)6.442 F -.05(ga) --.15 G 3.943(lo).05 G 1.443(ptions or)503.277 228 R .654(missing option ar)144 -240 R .653(guments are encountered.)-.18 F .653(If the v)5.653 F(ariable)-.25 E -F3(OPTERR)3.153 E F0 .653(is set to 0, no error message)2.903 F -(will be displayed, e)144 252 Q -.15(ve)-.25 G 2.5(ni).15 G 2.5(ft)241.09 252 S -(he \214rst character of)249.7 252 Q F2(optstring)2.5 E F0(is not a colon.)2.5 -E .826(If an ille)144 276 R -.05(ga)-.15 G 3.326(lo).05 G .826(ption is seen,) -199.878 276 R F1(getopts)3.326 E F0 .826(places ? into)3.326 F F2(name)3.326 E -F0 .826(and, if not silent, prints an error message)3.326 F .4(and unsets)144 -288 R F3(OPT)2.9 E(ARG)-.81 E F4(.)A F0(If)4.899 E F1(getopts)2.899 E F0 .399 -(is silent, the option character found is placed in)2.899 F F3(OPT)2.899 E(ARG) --.81 E F0 .399(and no)2.649 F(diagnostic message is printed.)144 300 Q 1.241 -(If a required ar)144 324 R 1.241(gument is not found, and)-.18 F F1(getopts) -3.741 E F0 1.241(is not silent, a question mark \()3.741 F F1(?).833 E F0 3.742 -(\)i).833 G 3.742(sp)494.746 324 S 1.242(laced in)507.378 324 R F2(name)144 336 -Q F0(,).18 E F1(OPT)3.357 E(ARG)-.9 E F0 .856 -(is unset, and a diagnostic message is printed.)3.357 F(If)5.856 E F1(getopts) -3.356 E F0 .856(is silent, then a colon)3.356 F(\()144 348 Q F1(:).833 E F0 2.5 -(\)i).833 G 2.5(sp)160.936 348 S(laced in)172.326 348 Q F2(name)2.5 E F0(and) -2.5 E F3(OPT)2.5 E(ARG)-.81 E F0(is set to the option character found.)2.25 E -F1(getopts)144 372 Q F0 2.392(normally parses the positional parameters, b) -4.892 F 2.392(ut if more ar)-.2 F 2.393(guments are gi)-.18 F -.15(ve)-.25 G -4.893(ni).15 G(n)509.927 372 Q F2(ar)4.893 E(gs)-.37 E F0(,).27 E F1(getopts) -144 384 Q F0 .651(parses those instead.)3.151 F F1(getopts)5.651 E F0 .651 -(returns true if an option, speci\214ed or unspeci\214ed, is found.)3.151 F -(It returns f)144 396 Q -(alse if the end of options is encountered or an error occurs.)-.1 E F1(hash) -108 412.8 Q F0([)2.5 E F1A F0 2.5(][)C F2(name)153.14 412.8 Q F0(])A -.15 -(Fo)144 424.8 S 2.819(re).15 G(ach)164.999 424.8 Q F2(name)2.819 E F0 2.819(,t) -.18 G .319(he full pathname of the command is determined and remembered.) -211.637 424.8 R(The)5.32 E F12.82 E F0(option)2.82 E .508 -(causes the shell to for)144 436.8 R .508(get all remembered locations.)-.18 F -.508(If no ar)5.508 F .508(guments are gi)-.18 F -.15(ve)-.25 G .507 -(n, information about).15 F .193(remembered commands is printed.)144 448.8 R -.193(An ar)5.193 F .193(gument of)-.18 F F12.693 E F0 .194 -(disables option checking for the rest of the)2.693 F(ar)144 460.8 Q 2.5 -(guments. The)-.18 F(return status is true unless a)2.5 E F2(name)2.5 E F0 -(is not found or an ille)2.5 E -.05(ga)-.15 G 2.5(lo).05 G(ption is supplied.) -453.86 460.8 Q F1(help)108 477.6 Q F0([)2.5 E F2(pattern)A F0(])A .991 -(Display helpful information about b)144 489.6 R .991(uiltin commands.)-.2 F -(If)5.991 E F2(pattern)3.491 E F0 .991(is speci\214ed,)3.491 F F1(help)3.491 E -F0(gi)3.49 E -.15(ve)-.25 G 3.49(sd).15 G(etailed)513.34 489.6 Q .408 -(help on all commands matching)144 501.6 R F2(pattern)2.909 E F0 2.909(;o).24 G -.409(therwise a list of the b)316.13 501.6 R .409(uiltins is printed.)-.2 F -.409(The return sta-)5.409 F(tus is 0 unless no command matches)144 513.6 Q F2 -(pattern)2.5 E F0(.).24 E F1(history)108 530.4 Q F0([)2.5 E F2(n)A F0(])A F1 -(history \255rwan)108 542.4 Q F0([)2.5 E F2(\214lename)A F0(])A -.4(Wi)144 -554.4 S .752 -(th no options, display the command history list with line numbers.).4 F .752 -(Lines listed with a)5.752 F F1(*)3.251 E F0(ha)3.251 E -.15(ve)-.2 G .375 -(been modi\214ed.)144 566.4 R .375(An ar)5.375 F .375(gument of)-.18 F F2(n) -2.875 E F0 .375(lists only the last)2.875 F F2(n)2.875 E F0 2.875(lines. If) -2.875 F 2.876(an)2.876 G .376(on-option ar)411.832 566.4 R .376 -(gument is supplied,)-.18 F .811 -(it is used as the name of the history \214le; if not, the v)144 578.4 R .811 -(alue of)-.25 F F3(HISTFILE)3.311 E F0 .811(is used.)3.061 F .811 -(Options, if sup-)5.811 F(plied, ha)144 590.4 Q .3 -.15(ve t)-.2 H(he follo).15 -E(wing meanings:)-.25 E F1144 602.4 Q F0 .598(Append the `)180 602.4 R -(`ne)-.74 E(w')-.25 E 3.098('h)-.74 G .598 -(istory lines \(history lines entered since the be)266.424 602.4 R .599 -(ginning of the current)-.15 F F1(bash)180 614.4 Q F0 -(session\) to the history \214le)2.5 E F1144 626.4 Q F0 .854(Read the hi\ -story lines not already read from the history \214le into the current history \ -list.)180 626.4 R .772 -(These are lines appended to the history \214le since the be)180 638.4 R .773 -(ginning of the current)-.15 F F1(bash)3.273 E F0(ses-)3.273 E(sion.)180 650.4 -Q F1144 662.4 Q F0 -(Read the contents of the history \214le and use them as the current history) -180 662.4 Q F1144 674.4 Q F0 -(Write the current history to the history \214le, o)180 674.4 Q -.15(ve)-.15 G -(rwriting the history \214le').15 E 2.5(sc)-.55 G(ontents.)474.4 674.4 Q .989 -(The return v)144 691.2 R .989(alue is 0 unless an ille)-.25 F -.05(ga)-.15 G -3.489(lo).05 G .989(ption is encountered or an error occurs while reading or) -308.662 691.2 R(writing the history \214le.)144 703.2 Q 185.675(GNU 1995)72 768 -R(May 5)2.5 E(29)530 768 Q EP -%%Page: 30 30 -%%BeginPageSetup -BP -%%EndPageSetup -/F0 10/Times-Roman@0 SF -.35(BA)72 48 S 389.54(SH\(1\) B).35 F(ASH\(1\))-.35 E -/F1 10/Times-Bold@0 SF(jobs)108 84 Q F0([)2.5 E F1(\255lnp)A F0 2.5(][)C/F2 10 -/Times-Italic@0 SF(jobspec)A F0(... ])2.5 E F1(jobs \255x)108 96 Q F2(command) -2.5 E F0([)2.5 E F2(ar)2.5 E(gs)-.37 E F0(... ])2.5 E .297 -(The \214rst form lists the acti)144 108 R .598 -.15(ve j)-.25 H 2.798 -(obs. The).15 F F12.798 E F0 .298 -(option lists process IDs in addition to the normal infor)2.798 F(-)-.2 E .746 -(mation; the)144 120 R F13.246 E F0 .745 -(option lists only the process ID of the job')3.246 F 3.245(sp)-.55 G .745 -(rocess group leader)394.205 120 R 5.745(.T)-.55 G(he)487.25 120 Q F1 -3.245 E F0(option)3.245 E 2.08(displays only jobs that ha)144 132 R 2.38 -.15 -(ve c)-.2 H 2.081(hanged status since last noti\214ed.).15 F(If)7.081 E F2 -(jobspec)4.581 E F0 2.081(is gi)4.581 F -.15(ve)-.25 G 2.081(n, output is).15 F -.727(restricted to information about that job)144 144 R 5.727(.T)-.4 G .727 -(he return status is 0 unless an ille)316.282 144 R -.05(ga)-.15 G 3.227(lo).05 -G .726(ption is encoun-)474.108 144 R(tered or an ille)144 156 Q -.05(ga)-.15 G -(l).05 E F2(jobspec)2.5 E F0(is supplied.)2.5 E .607(If the)144 180 R F1 -3.107 E F0 .607(option is supplied,)3.107 F F1(jobs)3.107 E F0 .607 -(replaces an)3.107 F(y)-.15 E F2(jobspec)3.107 E F0 .607(found in)3.107 F F2 -(command)3.107 E F0(or)3.107 E F2(ar)3.107 E(gs)-.37 E F0 .607(with the corre-) -3.107 F(sponding process group ID, and e)144 192 Q -.15(xe)-.15 G(cutes).15 E -F2(command)2.5 E F0(passing it)2.5 E F2(ar)2.5 E(gs)-.37 E F0 2.5(,r).27 G -(eturning its e)418.56 192 Q(xit status.)-.15 E F1(kill)108 208.8 Q F0([)2.5 E -F1(-s sigspec)A F0(|)2.5 E F1(\255sigspec)2.5 E F0 2.5(][)C F2(pid)219.31 208.8 -Q F0(|)2.5 E F2(jobspec)2.5 E F0 2.5(].)C(..)277.97 208.8 Q F1(kill \255l)108 -220.8 Q F0([)2.5 E F2(signum)A F0(])A .943(Send the signal named by)144 232.8 R -F2(sigspec)3.443 E F0 .942(to the processes named by)3.443 F F2(pid)3.442 E F0 -(or)3.442 E F2(jobspec)3.442 E F0(.).31 E F2(sigspec)5.942 E F0 .942 -(is either a)3.442 F .908(signal name such as)144 244.8 R/F3 9/Times-Bold@0 SF -(SIGKILL)3.408 E F0 .908(or a signal number)3.158 F 5.908(.I)-.55 G(f)359.638 -244.8 Q F2(sigspec)3.408 E F0 .908(is a signal name, the name is case)3.408 F -(insensiti)144 256.8 Q 2.43 -.15(ve a)-.25 H 2.13(nd may be gi).15 F -.15(ve) --.25 G 4.63(nw).15 G 2.13(ith or without the)279.67 256.8 R F3(SIG)4.63 E F0 -4.629(pre\214x. If)4.379 F F2(sigspec)4.629 E F0 2.129(is not present, then) -4.629 F F3(SIGTERM)144 268.8 Q F0 .813(is assumed.)3.063 F .813(An ar)5.813 F -.813(gument of)-.18 F F13.313 E F0 .814(lists the signal names.)3.313 F -.814(If an)5.814 F 3.314(ya)-.15 G -.18(rg)450.232 268.8 S .814 -(uments are supplied).18 F(when)144 280.8 Q F12.827 E F0 .327(is gi)2.827 -F -.15(ve)-.25 G .327(n, the names of the speci\214ed signals are listed, and \ -the return status is 0.).15 F .326(An ar)5.326 F(gu-)-.18 E .484(ment of)144 -292.8 R F12.984 E F0 .484 -(disables option checking for the rest of the ar)2.984 F(guments.)-.18 E F1 -(kill)5.485 E F0 .485(returns true if at least one)2.985 F(signal w)144 304.8 Q -(as successfully sent, or f)-.1 E(alse if an error occurs or an ille)-.1 E -.05 -(ga)-.15 G 2.5(lo).05 G(ption is encountered.)419.09 304.8 Q F1(let)108 321.6 Q -F2(ar)2.5 E(g)-.37 E F0([)2.5 E F2(ar)A(g)-.37 E F0(...])2.5 E(Each)144 333.6 Q -F2(ar)3.677 E(g)-.37 E F0 1.177(is an arithmetic e)3.677 F 1.177 -(xpression to be e)-.15 F -.25(va)-.25 G 1.177(luated \(see).25 F F3 1.176 -(ARITHMETIC EV)3.677 F(ALU)-1.215 E -.855(AT)-.54 G(ION).855 E/F4 9 -/Times-Roman@0 SF(\).)A F0 1.176(If the)5.676 F(last)144 345.6 Q F2(ar)2.5 E(g) --.37 E F0 -.25(eva)2.5 G(luates to 0,).25 E F1(let)2.5 E F0 -(returns 1; 0 is returned otherwise.)2.5 E F1(local)108 362.4 Q F0([)2.5 E F2 -(name)A F0([=)A F2(value)A F0 2.5(].)C(..])194.45 362.4 Q -.15(Fo)144 374.4 S -3.276(re).15 G .776(ach ar)165.456 374.4 R .776(gument, create a local v)-.18 F -.776(ariable named)-.25 F F2(name)3.276 E F0 3.276(,a).18 G .776(nd assign it) -380.784 374.4 R F2(value)3.276 E F0 5.777(.W).18 G(hen)470.729 374.4 Q F1 -(local)3.277 E F0 .777(is used)3.277 F .131(within a function, it causes the v) -144 386.4 R(ariable)-.25 E F2(name)2.631 E F0 .131(to ha)2.631 F .431 -.15 -(ve a v)-.2 H .13(isible scope restricted to that function and).15 F .232 -(its children.)144 398.4 R -.4(Wi)5.232 G .232(th no operands,).4 F F1(local) -2.733 E F0 .233(writes a list of local v)2.733 F .233 -(ariables to the standard output.)-.25 F .233(It is an)5.233 F .42 -(error to use)144 410.4 R F1(local)2.92 E F0 .42(when not within a function.) -2.92 F .42(The return status is 0 unless)5.42 F F1(local)2.92 E F0 .42 -(is used outside a)2.92 F(function, or an ille)144 422.4 Q -.05(ga)-.15 G(l).05 -E F2(name)2.5 E F0(is supplied.)2.5 E F1(logout)108 439.2 Q F0 -(Exit a login shell.)9.33 E F1(popd)108 456 Q F0([)2.5 E F1(+/\255n)A F0(])A -(Remo)144 468 Q -.15(ve)-.15 G 2.799(se).15 G .299 -(ntries from the directory stack.)188.159 468 R -.4(Wi)5.299 G .299(th no ar).4 -F .299(guments, remo)-.18 F -.15(ve)-.15 G 2.799(st).15 G .3 -(he top directory from the)438.82 468 R(stack, and performs a)144 480 Q F1(cd) -2.5 E F0(to the ne)2.5 E 2.5(wt)-.25 G(op directory)291.22 480 Q(.)-.65 E F1 -(+n)144 492 Q F0(remo)180 492 Q -.15(ve)-.15 G 2.849(st).15 G(he)219.209 492 Q -F2(n)2.849 E F0 .349(th entry counting from the left of the list sho)B .349 -(wn by)-.25 F F1(dirs)2.848 E F0 2.848(,s)C .348(tarting with zero.)470.704 492 -R -.15(Fo)180 504 S 2.5(re).15 G(xample: `)200.53 504 Q(`popd +0')-.74 E 2.5 -('r)-.74 G(emo)286.06 504 Q -.15(ve)-.15 G 2.5(st).15 G(he \214rst directory) -321.59 504 Q 2.5(,`)-.65 G(`popd +1')394.63 504 Q 2.5('t)-.74 G(he second.) -442.3 504 Q F1144 516 Q F0(remo)180 516 Q -.15(ve)-.15 G 2.501(st).15 G -(he)218.861 516 Q F2(n)2.501 E F0 .001 -(th entry counting from the right of the list sho)B .001(wn by)-.25 F F1(dirs) -2.502 E F0 2.502(,s)C .002(tarting with zero.)471.396 516 R -.15(Fo)180 528 S -2.5(re).15 G(xample: `)200.53 528 Q(`popd -0')-.74 E 2.5('r)-.74 G(emo)283.75 -528 Q -.15(ve)-.15 G 2.5(st).15 G(he last directory)319.28 528 Q 2.5(,`)-.65 G -(`popd -1')390.65 528 Q 2.5('t)-.74 G(he ne)436.01 528 Q(xt to last.)-.15 E -.644(If the)144 544.8 R F1(popd)3.144 E F0 .644(command is successful, a)3.144 -F F1(dirs)3.143 E F0 .643(is performed as well, and the return status is 0.) -3.143 F F1(popd)5.643 E F0 .57(returns f)144 556.8 R .57(alse if an ille)-.1 F --.05(ga)-.15 G 3.07(lo).05 G .571 -(ption is encountered, the directory stack is empty)251.25 556.8 R 3.071(,an) --.65 G(on-e)469.319 556.8 Q .571(xistent direc-)-.15 F -(tory stack entry is speci\214ed, or the directory change f)144 568.8 Q(ails.) --.1 E F1(pushd)108 585.6 Q F0([)2.5 E F2(dir)A F0(])A F1(pushd +/\255n)108 -597.6 Q F0 .64(Adds a directory to the top of the directory stack, or rotates \ -the stack, making the ne)144 609.6 R 3.139(wt)-.25 G .639(op of the)503.172 -609.6 R 1.315(stack the current w)144 621.6 R 1.315(orking directory)-.1 F -6.315(.W)-.65 G 1.315(ith no ar)306.885 621.6 R 1.315(guments, e)-.18 F 1.316 -(xchanges the top tw)-.15 F 3.816(od)-.1 G 1.316(irectories and)484.534 621.6 R -(returns 0, unless the directory stack is empty)144 633.6 Q(.)-.65 E F1(+n)144 -645.6 Q F0 1.268(Rotates the stack so that the)180 645.6 R F2(n)3.768 E F0 -1.267(th directory \(counting from the left of the list sho)B 1.267(wn by)-.25 -F F1(dirs)180 657.6 Q F0 2.5(\)i)C 2.5(sa)205.28 657.6 S 2.5(tt)216.11 657.6 S -(he top.)224.17 657.6 Q F1144 669.6 Q F0(Rotates the stack so that the) -180 669.6 Q F2(n)2.5 E F0 -(th directory \(counting from the right\) is at the top.)A F1(dir)144 681.6 Q -F0(adds)180 681.6 Q F2(dir)2.5 E F0 -(to the directory stack at the top, making it the ne)2.5 E 2.5(wc)-.25 G -(urrent w)422.5 681.6 Q(orking directory)-.1 E(.)-.65 E .488(If the)144 698.4 R -F1(pushd)2.988 E F0 .488(command is successful, a)2.988 F F1(dirs)2.988 E F0 -.488(is performed as well.)2.988 F .489(If the \214rst form is used,)5.488 F F1 -(pushd)2.989 E F0 1.103(returns 0 unless the cd to)144 710.4 R F2(dir)3.603 E -F0 -.1(fa)3.603 G 3.603(ils. W).1 F 1.103(ith the second form,)-.4 F F1(pushd) -3.603 E F0 1.103(returns 0 unless the directory)3.603 F .846(stack is empty)144 -722.4 R 3.346(,an)-.65 G(on-e)220.894 722.4 Q .847(xistant directory stack ele\ -ment is speci\214ed, or the directory change to the)-.15 F 185.675(GNU 1995)72 -768 R(May 5)2.5 E(30)530 768 Q EP -%%Page: 31 31 -%%BeginPageSetup -BP -%%EndPageSetup -/F0 10/Times-Roman@0 SF -.35(BA)72 48 S 389.54(SH\(1\) B).35 F(ASH\(1\))-.35 E -(speci\214ed ne)144 84 Q 2.5(wc)-.25 G(urrent directory f)205.4 84 Q(ails.)-.1 -E/F1 10/Times-Bold@0 SF(pwd)108 100.8 Q F0 .725 -(Print the absolute pathname of the current w)144 100.8 R .724 -(orking directory)-.1 F 5.724(.T)-.65 G .724(he path printed contains no sym-) -405.56 100.8 R .521(bolic links if the)144 112.8 R F13.021 E F0 .521 -(option to the)3.021 F F1(set)3.021 E F0 -.2(bu)3.021 G .521 -(iltin command is set.).2 F .521(See also the description of)5.521 F F1 -(nolinks)3.022 E F0(under)144 124.8 Q F1 .074(Shell V)2.574 F(ariables)-.92 E -F0(abo)2.574 E -.15(ve)-.15 G 2.574(\). The).15 F .074 -(return status is 0 unless an error occurs while reading the path-)2.574 F -(name of the current directory)144 136.8 Q(.)-.65 E F1 -.18(re)108 153.6 S(ad) -.18 E F0([)2.5 E F1A F0 2.5(][)C/F2 10/Times-Italic@0 SF(name)152.39 -153.6 Q F0(...])2.5 E .036 -(One line is read from the standard input, and the \214rst w)144 165.6 R .037 -(ord is assigned to the \214rst)-.1 F F2(name)2.537 E F0 2.537(,t).18 G .037 -(he second)500.253 165.6 R -.1(wo)144 177.6 S .109(rd to the second).1 F F2 -(name)2.609 E F0 2.609(,a).18 G .109(nd so on, with lefto)254.045 177.6 R -.15 -(ve)-.15 G 2.609(rw).15 G .109(ords assigned to the last)354.18 177.6 R F2 -(name)2.609 E F0 5.109(.O).18 G .108(nly the char)489.444 177.6 R(-)-.2 E .143 -(acters in)144 189.6 R/F3 9/Times-Bold@0 SF(IFS)2.643 E F0 .143 -(are recognized as w)2.393 F .143(ord delimiters.)-.1 F .143(If no)5.143 F F2 -(names)2.643 E F0 .144(are supplied, the line read is assigned)2.643 F .194 -(to the v)144 201.6 R(ariable)-.25 E F3(REPL)2.694 E(Y)-.828 E/F4 9 -/Times-Roman@0 SF(.)A F0 .194 -(The return code is zero, unless end-of-\214le is encountered.)4.694 F .193 -(If the)5.193 F F12.693 E F0(option)2.693 E .444(is gi)144 213.6 R -.15 -(ve)-.25 G .444(n, a backslash-ne).15 F .444 -(wline pair is not ignored, and the backslash is considered to be part of the) --.25 F(line.)144 225.6 Q F1 -.18(re)108 242.4 S(adonly).18 E F0([)2.5 E F1 -A F0 2.5(][)C F2(name)169.62 242.4 Q F0(...])2.5 E F1 -.18(re)108 254.4 S -(adonly -p).18 E F0 .419(The gi)144 266.4 R -.15(ve)-.25 G(n).15 E F2(names) -2.919 E F0 .419(are mark)2.919 F .419(ed readonly and the v)-.1 F .419 -(alues of these)-.25 F F2(names)2.919 E F0 .418(may not be changed by sub-) -2.919 F .541(sequent assignment.)144 278.4 R .541(If the)5.541 F F13.041 -E F0 .541(option is supplied, the functions corresponding to the)3.041 F F2 -(names)3.042 E F0 .542(are so)3.042 F(mark)144 290.4 Q 3.037(ed. If)-.1 F .537 -(no ar)3.037 F .537(guments are gi)-.18 F -.15(ve)-.25 G .536(n, or if the).15 -F F13.036 E F0 .536(option is supplied, a list of all readonly names is) -3.036 F 2.501(printed. An)144 302.4 R(ar)2.501 E .002(gument of)-.18 F F1 -2.502 E F0 .002(disables option checking for the rest of the ar)2.502 F 2.502 -(guments. The)-.18 F .002(return sta-)2.502 F .192(tus is 0 unless an ille)144 -314.4 R -.05(ga)-.15 G 2.692(lo).05 G .192(ption is encountered, one of the) -247.732 314.4 R F2(names)2.691 E F0 .191(is not a le)2.691 F -.05(ga)-.15 G -2.691(ls).05 G .191(hell v)463.498 314.4 R .191(ariable name,)-.25 F(or)144 -326.4 Q F12.5 E F0(is supplied with a)2.5 E F2(name)2.5 E F0 -(that is not a function.)2.5 E F1 -.18(re)108 343.2 S(tur).18 E(n)-.15 E F0([) -2.5 E F2(n)A F0(])A .618(Causes a function to e)144 355.2 R .618 -(xit with the return v)-.15 F .618(alue speci\214ed by)-.25 F F2(n)3.118 E F0 -5.619(.I).24 G(f)404.557 355.2 Q F2(n)3.119 E F0 .619 -(is omitted, the return status is)3.119 F 1.335(that of the last command e)144 -367.2 R -.15(xe)-.15 G 1.335(cuted in the function body).15 F 6.335(.I)-.65 G -3.835(fu)387.48 367.2 S 1.335(sed outside a function, b)399.645 367.2 R 1.335 -(ut during)-.2 F -.15(exe)144 379.2 S .794(cution of a script by the).15 F F1 -(.)3.294 E F0(\()5.794 E F1(sour)A(ce)-.18 E F0 3.294(\)c)C .794 -(ommand, it causes the shell to stop e)309.832 379.2 R -.15(xe)-.15 G .795 -(cuting that script).15 F .278(and return either)144 391.2 R F2(n)2.778 E F0 -.278(or the e)2.778 F .277(xit status of the last command e)-.15 F -.15(xe)-.15 -G .277(cuted within the script as the e).15 F .277(xit sta-)-.15 F .081 -(tus of the script.)144 403.2 R .082 -(If used outside a function and not during e)5.082 F -.15(xe)-.15 G .082 -(cution of a script by).15 F F1(.)2.582 E F0 2.582(,t).833 G .082 -(he return sta-)487.076 403.2 R(tus is f)144 415.2 Q(alse.)-.1 E F1(set)108 432 -Q F0([)2.5 E F1(\255\255abefhkmnptuvxldCHP)A F0 2.5(][)C F1(-o)243.29 432 Q F2 -(option)2.5 E F0 2.5(][)C F2(ar)288.84 432 Q(g)-.37 E F0(...])2.5 E F1144 -444 Q F0 1.036(Automatically mark v)184 444 R 1.036 -(ariables which are modi\214ed or created for e)-.25 F 1.035(xport to the en) --.15 F(viron-)-.4 E(ment of subsequent commands.)184 456 Q F1144 468 Q F0 -.721(Cause the status of terminated background jobs to be reported immediately) -184 468 R 3.221(,r)-.65 G .721(ather than)499.569 468 R(before the ne)184 480 Q -(xt primary prompt.)-.15 E(\(Also see)5 E F1(notify)2.5 E F0(under)2.5 E F1 -(Shell V)2.5 E(ariables)-.92 E F0(abo)2.5 E -.15(ve)-.15 G(\).).15 E F1 -144 492 Q F0 1.772(Exit immediately if a)184 492 R F2(simple-command)4.272 E F0 -(\(see)4.272 E F3 1.772(SHELL GRAMMAR)4.272 F F0(abo)4.022 E -.15(ve)-.15 G -4.271(\)e).15 G 1.771(xits with a)494.788 492 R .642(non\255zero status.)184 -504 R .642(The shell does not e)5.642 F .642(xit if the command that f)-.15 F -.643(ails is part of an)-.1 F F2(until)3.143 E F0(or)3.143 E F2(while)184 516 Q -F0 .728(loop, part of an)3.228 F F2(if)3.228 E F0 .728(statement, part of a) -3.228 F F1(&&)3.228 E F0(or)3.228 E/F5 10/Symbol SF 1.6663.228 G F0 .728 -(list, or if the command')1.562 F 3.228(sr)-.55 G(eturn)519.45 516 Q -.25(va) -184 528 S(lue is being in).25 E -.15(ve)-.4 G(rted via).15 E F1(!)2.5 E F0(.)A -F1144 540 Q F0(Disable pathname e)184 540 Q(xpansion.)-.15 E F1144 -552 Q F0 .106 -(Locate and remember function commands as functions are de\214ned.)184 552 R -.106(Function commands)5.106 F(are normally look)184 564 Q -(ed up when the function is e)-.1 E -.15(xe)-.15 G(cuted.).15 E F1144 576 -Q F0 .162(All k)184 576 R -.15(ey)-.1 G -.1(wo).15 G .162(rd ar).1 F .162 -(guments are placed in the en)-.18 F .161 -(vironment for a command, not just those that)-.4 F(precede the command name.) -184 588 Q F1144 600 Q F0 .009(Monitor mode.)184 600 R .009 -(Job control is enabled.)5.009 F .009(This \215ag is on by def)5.009 F .01 -(ault for interacti)-.1 F .31 -.15(ve s)-.25 H .01(hells on).15 F .124 -(systems that support it \(see)184 612 R F3 .124(JOB CONTR)2.624 F(OL)-.27 E F0 -(abo)2.374 E -.15(ve)-.15 G 2.624(\). Background).15 F .124 -(processes run in a sep-)2.624 F .72 -(arate process group and a line containing their e)184 624 R .721 -(xit status is printed upon their comple-)-.15 F(tion.)184 636 Q F1144 -648 Q F0 .653(Read commands b)184 648 R .653(ut do not e)-.2 F -.15(xe)-.15 G -.653(cute them.).15 F .652(This may be used to check a shell script for)5.653 F -(syntax errors.)184 660 Q(This is ignored for interacti)5 E .3 -.15(ve s)-.25 H -(hells.).15 E F1144 672 Q F2(option-name)2.5 E F0(The)184 684 Q F2 -(option-name)2.5 E F0(can be one of the follo)2.5 E(wing:)-.25 E F1(allexport) -184 696 Q F0(Same as)224 708 Q F12.5 E F0(.)A 185.675(GNU 1995)72 768 R -(May 5)2.5 E(31)530 768 Q EP -%%Page: 32 32 -%%BeginPageSetup -BP -%%EndPageSetup -/F0 10/Times-Roman@0 SF -.35(BA)72 48 S 389.54(SH\(1\) B).35 F(ASH\(1\))-.35 E -/F1 10/Times-Bold@0 SF(braceexpand)184 84 Q F0 .312(The shell performs brace e) -224 96 R .313(xpansion \(see)-.15 F F1 .313(Brace Expansion)2.813 F F0(abo) -2.813 E -.15(ve)-.15 G 2.813(\). This).15 F .313(is on)2.813 F(by def)224 108 Q -(ault.)-.1 E F1(emacs)184 120 Q F0 .089 -(Use an emacs-style command line editing interf)224 120 R 2.589(ace. This)-.1 F -.089(is enabled by def)2.589 F(ault)-.1 E .128(when the shell is interacti)224 -132 R -.15(ve)-.25 G 2.628(,u).15 G .128(nless the shell is started with the) -345.89 132 R F1(\255nolineediting)2.629 E F0(option.)224 144 Q F1(err)184 156 Q -(exit)-.18 E F0(Same as)224 156 Q F12.5 E F0(.)A F1(histexpand)184 168 Q -F0(Same as)224 180 Q F12.5 E F0(.)A F1(ignor)184 192 Q(eeof)-.18 E F0 -1.024(The ef)224 204 R 1.024 -(fect is as if the shell command `IGNOREEOF=10' had been e)-.25 F -.15(xe)-.15 -G(cuted).15 E(\(see)224 216 Q F1(Shell V)2.5 E(ariables)-.92 E F0(abo)2.5 E --.15(ve)-.15 G(\).).15 E F1(interacti)184 228 Q -.1(ve)-.1 G(\255comments).1 E -F0(Allo)224 240 Q 2.52(waw)-.25 G .02(ord be)265.35 240 R .021(ginning with) --.15 F F1(#)2.521 E F0 .021(to cause that w)2.521 F .021 -(ord and all remaining characters)-.1 F -(on that line to be ignored in an interacti)224 252 Q .3 -.15(ve s)-.25 H -(hell \(see).15 E/F2 9/Times-Bold@0 SF(COMMENTS)2.5 E F0(abo)2.25 E -.15(ve) --.15 G(\).).15 E F1(monitor)184 264 Q F0(Same as)5.56 E F12.5 E F0(.)A F1 -(noclob)184 276 Q(ber)-.1 E F0(Same as)224 288 Q F12.5 E F0(.)A F1 -(noexec)184 300 Q F0(Same as)224 300 Q F12.5 E F0(.)A F1(noglob)184 312 Q -F0(Same as)224 312 Q F12.5 E F0(.)A F1(nohash)184 324 Q F0(Same as)9.43 E -F12.5 E F0(.)A F1(notify)184 336 Q F0(Same as)224 336 Q F12.5 E F0 -(.)A F1(nounset)184 348 Q F0(Same as)6.66 E F12.5 E F0(.)A F1(ph)184 360 -Q(ysical)-.15 E F0(Same as)5.14 E F12.5 E F0(.)A F1(posix)184 372 Q F0 -2.244(Change the beha)224 372 R 2.244(vior of bash where the def)-.2 F 2.243 -(ault operation dif)-.1 F 2.243(fers from the)-.25 F -(Posix 1003.2 standard to match the standard.)224 384 Q F1(pri)184 396 Q -(vileged)-.1 E F0(Same as)224 408 Q F12.5 E F0(.)A F1 -.1(ve)184 420 S -(rbose).1 E F0(Same as)7.33 E F12.5 E F0(.)A F1(vi)184 432 Q F0 -(Use a vi-style command line editing interf)224 432 Q(ace.)-.1 E F1(xtrace)184 -444 Q F0(Same as)224 444 Q F12.5 E F0(.)A(If no)184 456 Q/F3 10 -/Times-Italic@0 SF(option-name)2.5 E F0(is supplied, the v)2.5 E -(alues of the current options are printed.)-.25 E F1144 468 Q F0 -.45(Tu) -184 468 S .521(rn on).45 F F3(privile)3.021 E -.1(ge)-.4 G(d).1 E F0 3.021 -(mode. In)3.021 F .521(this mode, the)3.021 F F1($ENV)3.021 E F0 .522 -(\214le is not processed, and shell func-)3.021 F .26 -(tions are not inherited from the en)184 480 R 2.76(vironment. This)-.4 F .26 -(is enabled automatically on startup if)2.76 F .481(the ef)184 492 R(fecti)-.25 -E .781 -.15(ve u)-.25 H .482 -(ser \(group\) id is not equal to the real user \(group\) id.).15 F -.45(Tu) -5.482 G .482(rning this option).45 F(of)184 504 Q 2.5(fc)-.25 G(auses the ef) -202.35 504 Q(fecti)-.25 E .3 -.15(ve u)-.25 H -(ser and group ids to be set to the real user and group ids.).15 E F1144 -516 Q F0(Exit after reading and e)184 516 Q -.15(xe)-.15 G(cuting one command.) -.15 E F1144 528 Q F0 -.35(Tr)184 528 S .445(eat unset v).35 F .444 -(ariables as an error when performing parameter e)-.25 F 2.944(xpansion. If) --.15 F -.15(ex)2.944 G .444(pansion is).15 F .519(attempted on an unset v)184 -540 R .519(ariable, the shell prints an error message, and, if not interacti) --.25 F -.15(ve)-.25 G(,).15 E -.15(ex)184 552 S(its with a non\255zero status.) -.15 E F1144 564 Q F0(Print shell input lines as the)184 564 Q 2.5(ya)-.15 -G(re read.)306.63 564 Q F1144 576 Q F0 1.057(After e)184 576 R 1.056 -(xpanding each)-.15 F F3(simple-command)3.556 E F0(,).77 E F1(bash)3.556 E F0 -1.056(displays the e)3.556 F 1.056(xpanded v)-.15 F 1.056(alue of)-.25 F F2 -(PS4)3.556 E/F4 9/Times-Roman@0 SF(,)A F0(fol-)3.306 E(lo)184 588 Q -(wed by the command and its e)-.25 E(xpanded ar)-.15 E(guments.)-.18 E F1 -144 600 Q F0(Sa)184 600 Q 1.398 -.15(ve a)-.2 H 1.098 -(nd restore the binding of).15 F F3(name)3.598 E F0 1.098(in a)3.598 F F1 -.25 -(fo)3.598 G(r).25 E F3(name)3.598 E F0([in)3.599 E F1 -.1(wo)3.599 G(rd).1 E F0 -3.599(]c)C 1.099(ommand \(see)451.687 600 R F2(SHELL)3.599 E(GRAMMAR)184 612 Q -F0(abo)2.25 E -.15(ve)-.15 G(\).).15 E F1144 624 Q F0 1.68 -(Disable the hashing of commands that are look)184 624 R 1.68(ed up for e)-.1 F --.15(xe)-.15 G 4.18(cution. Normally).15 F 4.18(,c)-.65 G(om-)523.89 624 Q -1.275(mands are remembered in a hash table, and once found, do not ha)184 636 R -1.576 -.15(ve t)-.2 H 3.776(ob).15 G 3.776(el)490.888 636 S(ook)501.884 636 Q -1.276(ed up)-.1 F(ag)184 648 Q(ain.)-.05 E F1144 660 Q F0 .812(The ef)184 -660 R .812(fect is as if the shell command `noclobber=' had been e)-.25 F -.15 -(xe)-.15 G .811(cuted \(see).15 F F1 .811(Shell V)3.311 F(ari-)-.92 E(ables)184 -672 Q F0(abo)2.5 E -.15(ve)-.15 G(\).).15 E F1144 684 Q F0(Enable)184 684 -Q F1(!)3.13 E F0 .63(style history substitution.)5.63 F .63 -(This \215ag is on by def)5.63 F .63(ault when the shell is interac-)-.1 F(ti) -184 696 Q -.15(ve)-.25 G(.).15 E F1144 708 Q F0 2.107 -(If set, do not follo)184 708 R 4.607(ws)-.25 G 2.107 -(ymbolic links when performing commands such as)279.835 708 R F1(cd)4.607 E F0 -(which)4.606 E(change the current directory)184 720 Q 5(.T)-.65 G(he ph)309.42 -720 Q(ysical directory is used instead.)-.05 E 185.675(GNU 1995)72 768 R(May 5) -2.5 E(32)530 768 Q EP -%%Page: 33 33 -%%BeginPageSetup -BP -%%EndPageSetup -/F0 10/Times-Roman@0 SF -.35(BA)72 48 S 389.54(SH\(1\) B).35 F(ASH\(1\))-.35 E -/F1 10/Times-Bold@0 SF144 84 Q F0 .05(If no ar)184 84 R .05 -(guments follo)-.18 F 2.55(wt)-.25 G .05 -(his \215ag, then the positional parameters are unset.)280.98 84 R .05 -(Otherwise, the)5.05 F(positional parameters are set to the)184 96 Q/F2 10 -/Times-Italic@0 SF(ar)2.5 E(g)-.37 E F0(s, e)A -.15(ve)-.25 G 2.5(ni).15 G 2.5 -(fs)371.81 96 S(ome of them be)381.53 96 Q(gin with a)-.15 E F12.5 E F0(.)A -F1144 108 Q F0 1.945(Signal the end of options, cause all remaining)184 108 -R F2(ar)4.444 E(g)-.37 E F0 4.444(st)C 4.444(ob)409.45 108 S 4.444(ea)423.894 -108 S 1.944(ssigned to the positional)437.218 108 R 3.445(parameters. The)184 -120 R F13.445 E F0(and)3.445 E F13.445 E F0 .945 -(options are turned of)3.445 F 3.445(f. If)-.25 F .946(there are no)3.445 F F2 -(ar)3.446 E(g)-.37 E F0 .946(s, the positional)B(parameters remain unchanged.) -184 132 Q .317(The \215ags are of)144 148.8 R 2.817(fb)-.25 G 2.817(yd)218.328 -148.8 S(ef)231.145 148.8 Q .317(ault unless otherwise noted.)-.1 F .316 -(Using + rather than \255 causes these \215ags to be)5.317 F .198(turned of)144 -160.8 R 2.698(f. The)-.25 F .199 -(\215ags can also be speci\214ed as options to an in)2.699 F -.2(vo)-.4 G .199 -(cation of the shell.).2 F .199(The current set)5.199 F .643 -(of \215ags may be found in)144 172.8 R F1<24ad>3.143 E F0 5.642(.A)C .642 -(fter the option ar)273.91 172.8 R .642(guments are processed, the remaining) --.18 F F2 3.142(na)3.142 G -.37(rg)512.238 172.8 S F0 3.142(sa).37 G(re)532.23 -172.8 Q .775(treated as v)144 184.8 R .775 -(alues for the positional parameters and are assigned, in order)-.25 F 3.275 -(,t)-.4 G(o)448.69 184.8 Q F1($1)3.275 E F0(,)A F1($2)3.275 E F0(,)A F1 3.275 -(... $)3.275 F F2(n)A F0 5.775(.I)C 3.275(fn)523.395 184.8 S(o)535 184.8 Q .309 -(options or)144 196.8 R F2(ar)2.809 E(g)-.37 E F0 2.808(sa)C .308 -(re supplied, all shell v)212.056 196.8 R .308(ariables are printed.)-.25 F -.308(The return status is al)5.308 F -.1(wa)-.1 G .308(ys true unless).1 F -(an ille)144 208.8 Q -.05(ga)-.15 G 2.5(lo).05 G(ption is encountered.)188.24 -208.8 Q F1(shift)108 225.6 Q F0([)2.5 E F2(n)A F0(])A .428 -(The positional parameters from)144 237.6 R F2(n)2.928 E F0 .429 -(+1 ... are renamed to)B F1 .429($1 ....)2.929 F F0 -.15(Pa)5.429 G .429 -(rameters represented by the num-).15 F(bers)144 249.6 Q F1($#)3.434 E F0(do) -3.434 E .934(wn to)-.25 F F1($#)3.434 E F0A F2(n)A F0 .934(+1 are unset.)B -(If)5.934 E F2(n)3.433 E F0 .933(is 0, no parameters are changed.)3.433 F(If) -5.933 E F2(n)3.433 E F0 .933(is not gi)3.433 F -.15(ve)-.25 G .933(n, it is).15 -F .026(assumed to be 1.)144 261.6 R F2(n)5.026 E F0 .026(must be a non-ne)2.526 -F -.05(ga)-.15 G(ti).05 E .326 -.15(ve n)-.25 H .026 -(umber less than or equal to).15 F F1($#)2.526 E F0 5.026(.I)C(f)454.886 261.6 -Q F2(n)2.526 E F0 .027(is greater than)2.527 F F1($#)2.527 E F0(,)A .03 -(the positional parameters are not changed.)144 273.6 R .029 -(The return status is greater than 0 if)5.03 F F2(n)2.529 E F0 .029 -(is greater than)2.529 F F1($#)2.529 E F0(or less than 0; otherwise 0.)144 -285.6 Q F1(suspend)108 302.4 Q F0([)2.5 E F1A F0(])A .492(Suspend the e) -144 314.4 R -.15(xe)-.15 G .492(cution of this shell until it recei).15 F -.15 -(ve)-.25 G 2.992(sa).15 G/F3 9/Times-Bold@0 SF(SIGCONT).001 E F0 2.993 -(signal. The)2.743 F F12.993 E F0 .493(option says not to)2.993 F .759 -(complain if this is a login shell; just suspend an)144 326.4 R(yw)-.15 E(ay) --.1 E 5.758(.T)-.65 G .758(he return status is 0 unless the shell is a)375.688 -326.4 R(login shell and)144 338.4 Q F12.5 E F0 -(is not supplied, or if job control is not enabled.)2.5 E F1(test)108 355.2 Q -F2 -.2(ex)2.5 G(pr).2 E F1([)108 367.2 Q F2 -.2(ex)2.5 G(pr).2 E F1(])2.5 E F0 -.877(Return a status of 0 \(true\) or 1 \(f)6.77 F .878 -(alse\) depending on the e)-.1 F -.25(va)-.25 G .878 -(luation of the conditional e).25 F(xpression)-.15 E F2 -.2(ex)144 379.2 S(pr) -.2 E F0 5.008(.E).73 G .008(xpressions may be unary or binary)175.918 379.2 R -5.007(.U)-.65 G .007(nary e)328.064 379.2 R .007 -(xpressions are often used to e)-.15 F .007(xamine the status)-.15 F .203 -(of a \214le.)144 391.2 R .203 -(There are string operators and numeric comparison operators as well.)5.203 F -.204(Each operator and)5.204 F 1.592(operand must be a separate ar)144 403.2 R -4.091(gument. If)-.18 F F2(\214le)4.091 E F0 1.591(is of the form /de)4.091 F -(v/fd/)-.25 E F2(n)A F0 4.091(,t)C 1.591(hen \214le descriptor)444.756 403.2 R -F2(n)4.091 E F0(is)4.091 E(check)144 415.2 Q(ed.)-.1 E F1144 427.2 Q F2 -(\214le)2.5 E F0 -.35(Tr)180 427.2 S(ue if).35 E F2(\214le)2.5 E F0 -.15(ex)2.5 -G(ists and is block special.).15 E F1144 439.2 Q F2(\214le)2.5 E F0 -.35 -(Tr)180 439.2 S(ue if).35 E F2(\214le)2.5 E F0 -.15(ex)2.5 G -(ists and is character special.).15 E F1144 451.2 Q F2(\214le)2.5 E F0 --.35(Tr)180 451.2 S(ue if).35 E F2(\214le)2.5 E F0 -.15(ex)2.5 G -(ists and is a directory).15 E(.)-.65 E F1144 463.2 Q F2(\214le)2.5 E F0 --.35(Tr)180 463.2 S(ue if).35 E F2(\214le)2.5 E F0 -.15(ex)2.5 G(ists.).15 E F1 -144 475.2 Q F2(\214le)2.5 E F0 -.35(Tr)180 475.2 S(ue if).35 E F2(\214le) -2.5 E F0 -.15(ex)2.5 G(ists and is a re).15 E(gular \214le.)-.15 E F1144 -487.2 Q F2(\214le)2.5 E F0 -.35(Tr)180 487.2 S(ue if).35 E F2(\214le)2.5 E F0 --.15(ex)2.5 G(ists and is set-group-id.).15 E F1144 499.2 Q F2(\214le)2.5 -E F0 -.35(Tr)180 499.2 S(ue if).35 E F2(\214le)2.5 E F0(has its `)2.5 E(`stick) --.74 E(y')-.15 E 2.5('b)-.74 G(it set.)295.22 499.2 Q F1144 511.2 Q F2 -(\214le)2.5 E F0 -.35(Tr)8.91 G(ue if).35 E F2(\214le)2.5 E F0 -.15(ex)2.5 G -(ists and is a symbolic link.).15 E F1144 523.2 Q F2(\214le)2.5 E F0 -.35 -(Tr)180 523.2 S(ue if).35 E F2(\214le)2.5 E F0 -.15(ex)2.5 G -(ists and is a named pipe.).15 E F1144 535.2 Q F2(\214le)2.5 E F0 -.35 -(Tr)180 535.2 S(ue if).35 E F2(\214le)2.5 E F0 -.15(ex)2.5 G -(ists and is readable.).15 E F1144 547.2 Q F2(\214le)2.5 E F0 -.35(Tr)180 -547.2 S(ue if).35 E F2(\214le)2.5 E F0 -.15(ex)2.5 G -(ists and has a size greater than zero.).15 E F1144 559.2 Q F2(\214le)2.5 -E F0 -.35(Tr)180 559.2 S(ue if).35 E F2(\214le)2.5 E F0 -.15(ex)2.5 G -(ists and is a sock).15 E(et.)-.1 E F1144 571.2 Q F2(fd)2.5 E F0 -.35(Tr) -180 571.2 S(ue if).35 E F2(fd)2.5 E F0(is opened on a terminal.)2.5 E F1 -144 583.2 Q F2(\214le)2.5 E F0 -.35(Tr)180 583.2 S(ue if).35 E F2(\214le)2.5 E -F0 -.15(ex)2.5 G(ists and its set-user).15 E(-id bit is set.)-.2 E F1144 -595.2 Q F2(\214le)2.5 E F0 -.35(Tr)8.36 G(ue if).35 E F2(\214le)2.5 E F0 -.15 -(ex)2.5 G(ists and is writable.).15 E F1144 607.2 Q F2(\214le)2.5 E F0 --.35(Tr)180 607.2 S(ue if).35 E F2(\214le)2.5 E F0 -.15(ex)2.5 G(ists and is e) -.15 E -.15(xe)-.15 G(cutable.).15 E F1144 619.2 Q F2(\214le)2.5 E F0 -.35 -(Tr)7.8 G(ue if).35 E F2(\214le)2.5 E F0 -.15(ex)2.5 G(ists and is o).15 E -(wned by the ef)-.25 E(fecti)-.25 E .3 -.15(ve u)-.25 H(ser id.).15 E F1 -144 631.2 Q F2(\214le)2.5 E F0 -.35(Tr)7.8 G(ue if).35 E F2(\214le)2.5 E F0 --.15(ex)2.5 G(ists and is o).15 E(wned by the ef)-.25 E(fecti)-.25 E .3 -.15 -(ve g)-.25 H(roup id.).15 E F2(\214le1)144 643.2 Q F02.5 E F1(nt)A F2 -(\214le2)2.5 E F0 -.35(Tr)180 655.2 S(ue if).35 E F2(\214le1)2.5 E F0(is ne)2.5 -E(wer \(according to modi\214cation date\) than)-.25 E F2(\214le2)2.5 E F0(.)A -F2(\214le1)144 667.2 Q F02.5 E F1(ot)A F2(\214le2)2.5 E F0 -.35(Tr)180 -679.2 S(ue if).35 E F2(\214le1)2.5 E F0(is older than \214le2.)2.5 E F2 -(\214le1)144 691.2 Q F1(\255ef)2.5 E F2(\214le)2.5 E F0 -.35(Tr)180 703.2 S -(ue if).35 E F2(\214le1)2.5 E F0(and)2.5 E F2(\214le2)2.5 E F0(ha)2.5 E .3 -.15 -(ve t)-.2 H(he same de).15 E(vice and inode numbers.)-.25 E 185.675(GNU 1995)72 -768 R(May 5)2.5 E(33)530 768 Q EP -%%Page: 34 34 -%%BeginPageSetup -BP -%%EndPageSetup -/F0 10/Times-Roman@0 SF -.35(BA)72 48 S 389.54(SH\(1\) B).35 F(ASH\(1\))-.35 E -/F1 10/Times-Bold@0 SF144 84 Q/F2 10/Times-Italic@0 SF(string)2.5 E F0 --.35(Tr)180 96 S(ue if the length of).35 E F2(string)2.5 E F0(is zero.)2.5 E F1 -144 108 Q F2(string)2.5 E(string)144 120 Q F0 -.35(Tr)180 120 S -(ue if the length of).35 E F2(string)2.5 E F0(is non\255zero.)2.5 E F2(string1) -144 132 Q F1(=)2.5 E F2(string2)2.5 E F0 -.35(Tr)180 144 S -(ue if the strings are equal.).35 E F2(string1)144 156 Q F1(!=)2.5 E F2 -(string2)2.5 E F0 -.35(Tr)180 168 S(ue if the strings are not equal.).35 E F1 -(!)144 180 Q F2 -.2(ex)2.5 G(pr).2 E F0 -.35(Tr)180 180 S(ue if).35 E F2 -.2 -(ex)2.5 G(pr).2 E F0(is f)2.5 E(alse.)-.1 E F2 -.2(ex)144 192 S(pr1).2 E F0 -2.5 E F1(a)A F2 -.2(ex)2.5 G(pr2).2 E F0 -.35(Tr)180 204 S(ue if both).35 E F2 --.2(ex)2.5 G(pr1).2 E F0(AND)2.5 E F2 -.2(ex)2.5 G(pr2).2 E F0(are true.)2.5 E -F2 -.2(ex)144 216 S(pr1).2 E F02.5 E F1(o)A F2 -.2(ex)2.5 G(pr2).2 E F0 --.35(Tr)180 228 S(ue if either).35 E F2 -.2(ex)2.5 G(pr1).2 E F0(OR)2.5 E F2 --.2(ex)2.5 G(pr2).2 E F0(is true.)2.5 E F2(ar)144 240 Q(g1)-.37 E F1(OP)2.5 E -F2(ar)2.5 E(g2)-.37 E/F3 9/Times-Bold@0 SF(OP)180 252 Q F0 .035(is one of)2.284 -F F1(\255eq)2.535 E F0(,)A F1(\255ne)2.535 E F0(,)A F1(\255lt)2.535 E F0(,)A F1 -(\255le)2.535 E F0(,)A F1(\255gt)2.535 E F0 2.535(,o)C(r)332.165 252 Q F1 -(\255ge)2.535 E F0 5.035(.T)C .035 -(hese arithmetic binary operators return true)366.815 252 R(if)180 264 Q F2(ar) -3.32 E(g1)-.37 E F0 .82(is equal, not-equal, less-than, less-than-or)3.32 F .82 -(-equal, greater)-.2 F .82(-than, or greater)-.2 F(-than-or)-.2 E(-)-.2 E .5 -(equal than)180 276 R F2(ar)3 E(g2)-.37 E F0 3.001(,r)C(especti)252.231 276 Q --.15(ve)-.25 G(ly).15 E(.)-.65 E F2(Ar)5.501 E(g1)-.37 E F0(and)3.001 E F2(ar) -3.001 E(g2)-.37 E F0 .501(may be positi)3.001 F .801 -.15(ve i)-.25 H(nte).15 E -.501(gers, ne)-.15 F -.05(ga)-.15 G(ti).05 E .801 -.15(ve i)-.25 H(nte).15 E -(gers,)-.15 E(or the special e)180 288 Q(xpression)-.15 E F12.5 E F2 -(string)2.5 E F0 2.5(,w)C(hich e)327.48 288 Q -.25(va)-.25 G -(luates to the length of).25 E F2(string)2.5 E F0(.).22 E F1(times)108 304.8 Q -F0 1.229(Print the accumulated user and system times for the shell and for pro\ -cesses run from the shell.)144 304.8 R(The return status is 0.)144 316.8 Q F1 -(trap)108 333.6 Q F0([)2.5 E F1A F0 2.5(][)C F2(ar)149.8 333.6 Q(g)-.37 E -F0 2.5(][)C F2(sigspec)172.48 333.6 Q F0(])A .767(The command)144 345.6 R F2 -(ar)3.267 E(g)-.37 E F0 .767(is to be read and e)3.267 F -.15(xe)-.15 G .767 -(cuted when the shell recei).15 F -.15(ve)-.25 G 3.267(ss).15 G(ignal\(s\)) -434.781 345.6 Q F2(sigspec)3.267 E F0 5.767(.I).31 G(f)509.945 345.6 Q F2(ar) -3.267 E(g)-.37 E F0(is)3.268 E 2.164(absent or)144 357.6 R F14.664 E F0 -4.664(,a)C 2.164(ll speci\214ed signals are reset to their original v)204.512 -357.6 R 2.164(alues \(the v)-.25 F 2.163(alues the)-.25 F 4.663(yh)-.15 G 2.163 -(ad upon)505.897 357.6 R .681(entrance to the shell\).)144 369.6 R(If)5.681 E -F2(ar)3.181 E(g)-.37 E F0 .681 -(is the null string this signal is ignored by the shell and by the com-)3.181 F -1.174(mands it in)144 381.6 R -.2(vo)-.4 G -.1(ke).2 G(s.).1 E F2(sigspec)6.174 -E F0 1.174(is either a signal name de\214ned in <)3.674 F F2(signal.h)A F0 -1.173(>, or a signal number)B 6.173(.I)-.55 G(f)536.67 381.6 Q F2(sigspec)144 -393.6 Q F0(is)2.769 E F3(EXIT)2.769 E F0 .269(\(0\) the command)2.519 F F2(ar) -2.769 E(g)-.37 E F0 .269(is e)2.769 F -.15(xe)-.15 G .269(cuted on e).15 F .269 -(xit from the shell.)-.15 F -.4(Wi)5.269 G .269(th no ar).4 F(guments,)-.18 E -F1(trap)2.77 E F0 .403 -(prints the list of commands associated with each signal number)144 405.6 R -5.402(.T)-.55 G(he)414.118 405.6 Q F12.902 E F0 .402 -(option causes the shell to)2.902 F .562 -(print a list of signal names and their corresponding numbers.)144 417.6 R .562 -(An ar)5.562 F .562(gument of)-.18 F F13.062 E F0 .562(disables option) -3.062 F .564(checking for the rest of the ar)144 429.6 R 3.064 -(guments. Signals)-.18 F .564 -(ignored upon entry to the shell cannot be trapped)3.064 F 1.144(or reset.)144 -441.6 R -.35(Tr)6.144 G 1.145(apped signals are reset to their original v).35 F -1.145(alues in a child process when it is created.)-.25 F -(The return status is f)144 453.6 Q -(alse if either the trap name or number is in)-.1 E -.25(va)-.4 G -(lid; otherwise).25 E F1(trap)2.5 E F0(returns true.)2.5 E F1(type)108 470.4 Q -F0([)2.5 E F1(\255all)A F0 2.5(][)C F1(\255type)157.58 470.4 Q F0(|)2.5 E F1 -(\255path)2.5 E F0(])A F2(name)2.5 E F0([)2.5 E F2(name)A F0(...])2.5 E -.4(Wi) -144 482.4 S .206(th no options, indicate ho).4 F 2.706(we)-.25 G(ach)272.15 -482.4 Q F2(name)2.705 E F0 -.1(wo)2.705 G .205 -(uld be interpreted if used as a command name.).1 F .205(If the)5.205 F F1 -(\255type)144 494.4 Q F0 .527(\215ag is used,)3.027 F F1(type)3.027 E F0 .528 -(prints a phrase which is one of)3.028 F F2(alias)3.028 E F0(,).27 E F2 -.1(ke) -3.028 G(ywor)-.2 E(d)-.37 E F0(,).77 E F2(function)3.028 E F0(,).24 E F2 -.2 -(bu)3.028 G(iltin).2 E F0 3.028(,o).24 G(r)512.284 494.4 Q F2(\214le)3.028 E F0 -(if)3.028 E F2(name)144 506.4 Q F0 .297(is an alias, shell reserv)2.798 F .297 -(ed w)-.15 F .297(ord, function, b)-.1 F .297(uiltin, or disk \214le, respecti) --.2 F -.15(ve)-.25 G(ly).15 E 2.797(.I)-.65 G 2.797(ft)472.152 506.4 S .297 -(he name is not)481.059 506.4 R 1.097(found, then nothing is printed, and an e) -144 518.4 R 1.097(xit status of f)-.15 F 1.097(alse is returned.)-.1 F 1.097 -(If the)6.097 F F1(\255path)3.598 E F0 1.098(\215ag is used,)3.598 F F1(type) -144 530.4 Q F0 1.009(either returns the name of the disk \214le that w)3.509 F -1.008(ould be e)-.1 F -.15(xe)-.15 G 1.008(cuted if).15 F F2(name)3.508 E F0 -1.008(were speci\214ed as a)3.508 F .562(command name, or nothing if)144 542.4 -R F1(\255type)3.062 E F0 -.1(wo)3.062 G .562(uld not return).1 F F2(\214le) -3.063 E F0 5.563(.I).18 G 3.063(fac)389.542 542.4 S .563(ommand is hashed,) -407.878 542.4 R F1(\255path)3.063 E F0(prints)3.063 E .684(the hashed v)144 -554.4 R .684(alue, not necessarily the \214le that appears \214rst in)-.25 F F3 --.666(PA)3.184 G(TH)-.189 E/F4 9/Times-Roman@0 SF(.)A F0 .684(If the)5.184 F F1 -(\255all)3.184 E F0 .683(\215ag is used,)3.184 F F1(type)3.183 E F0 1.135 -(prints all of the places that contain an e)144 566.4 R -.15(xe)-.15 G 1.135 -(cutable named).15 F F2(name)3.635 E F0 6.136(.T).18 G 1.136 -(his includes aliases and func-)418.256 566.4 R 1.011 -(tions, if and only if the)144 578.4 R F1(\255path)3.511 E F0 1.011 -(\215ag is not also used.)3.511 F 1.011 -(The table of hashed commands is not con-)6.011 F .786(sulted when using)144 -590.4 R F1(\255all)3.286 E F0(.)A F1(type)5.786 E F0(accepts)3.286 E F1 -3.286 E F0(,)A F13.286 E F0 3.286(,a)C(nd)335.698 590.4 Q F13.286 E -F0 .787(in place of)3.287 F F1(\255all)3.287 E F0(,)A F1(\255type)3.287 E F0 -3.287(,a)C(nd)466.906 590.4 Q F1(\255path)3.287 E F0 3.287(,r)C(espec-)514.46 -590.4 Q(ti)144 602.4 Q -.15(ve)-.25 G(ly).15 E 6.127(.A)-.65 G 3.627(na)181.577 -602.4 S -.18(rg)194.644 602.4 S 1.127(ument of).18 F F13.627 E F0 1.127 -(disables option checking for the rest of the ar)3.627 F(guments.)-.18 E F1 -(type)6.126 E F0(returns)3.626 E(true if an)144 614.4 Q 2.5(yo)-.15 G 2.5(ft) -192.45 614.4 S(he ar)201.06 614.4 Q(guments are found, f)-.18 E -(alse if none are found.)-.1 E F1(ulimit)108 631.2 Q F0([)2.5 E F1 -(\255SHacdfmstpnuv)A F0([)2.5 E F2(limit)A F0(]])A F1(Ulimit)144 643.2 Q F0 -(pro)3.056 E .556(vides control o)-.15 F -.15(ve)-.15 G 3.057(rt).15 G .557 -(he resources a)266.316 643.2 R -.25(va)-.2 G .557 -(ilable to the shell and to processes started by it, on).25 F .765 -(systems that allo)144 655.2 R 3.265(ws)-.25 G .765(uch control.)226.325 655.2 -R .765(The v)5.765 F .765(alue of)-.25 F F2(limit)3.265 E F0 .765 -(can be a number in the unit speci\214ed for the)3.265 F .301 -(resource, or the v)144 667.2 R(alue)-.25 E F1(unlimited)2.801 E F0 5.301(.T)C -(he)288.565 667.2 Q F1(H)2.801 E F0(and)2.801 E F1(S)2.801 E F0 .302 -(options specify that the hard or soft limit is set for)2.802 F .005(the gi)144 -679.2 R -.15(ve)-.25 G 2.505(nr).15 G 2.505(esource. A)186.38 679.2 R .004(har\ -d limit cannot be increased once it is set; a soft limit may be increased up) -2.505 F .008(to the v)144 691.2 R .008(alue of the hard limit.)-.25 F .008 -(If neither)5.008 F F1(H)2.508 E F0(nor)2.508 E F1(S)2.508 E F0 .008 -(is speci\214ed, the command applies to the soft limit.)2.508 F(If)144 703.2 Q -F2(limit)2.758 E F0 .258(is omitted, the current v)2.758 F .257 -(alue of the soft limit of the resource is printed, unless the)-.25 F F1(H) -2.757 E F0(option)2.757 E .575(is gi)144 715.2 R -.15(ve)-.25 G 3.075(n. When) -.15 F .576(more than one resource is speci\214ed, the limit name and unit is p\ -rinted before the)3.076 F -.25(va)144 727.2 S 2.5(lue. Other).25 F -(options are interpreted as follo)2.5 E(ws:)-.25 E 185.675(GNU 1995)72 768 R -(May 5)2.5 E(34)530 768 Q EP -%%Page: 35 35 -%%BeginPageSetup -BP -%%EndPageSetup -/F0 10/Times-Roman@0 SF -.35(BA)72 48 S 389.54(SH\(1\) B).35 F(ASH\(1\))-.35 E -/F1 10/Times-Bold@0 SF144 84 Q F0(all current limits are reported)180 84 -Q F1144 96 Q F0(the maximum size of core \214les created)180 96 Q F1 -144 108 Q F0(the maximum size of a process')180 108 Q 2.5(sd)-.55 G -(ata se)317.76 108 Q(gment)-.15 E F1144 120 Q F0 -(the maximum size of \214les created by the shell)180 120 Q F1144 132 Q -F0(the maximum resident set size)180 132 Q F1144 144 Q F0 -(the maximum stack size)180 144 Q F1144 156 Q F0 -(the maximum amount of cpu time in seconds)180 156 Q F1144 168 Q F0 -(the pipe size in 512-byte blocks \(this may not be set\))180 168 Q F1144 -180 Q F0 .164 -(the maximum number of open \214le descriptors \(most systems do not allo)180 -180 R 2.664(wt)-.25 G .164(his v)481.708 180 R .164(alue to be)-.25 F -(set, only displayed\))180 192 Q F1144 204 Q F0 -(the maximum number of processes a)180 204 Q -.25(va)-.2 G -(ilable to a single user).25 E F1144 216 Q F0 -(The maximum amount of virtual memory a)180 216 Q -.25(va)-.2 G -(ilable to the shell).25 E .778(An ar)144 232.8 R .778(gument of)-.18 F F1 -3.278 E F0 .778(disables option checking for the rest of the ar)3.278 F -3.279(guments. If)-.18 F/F2 10/Times-Italic@0 SF(limit)3.279 E F0 .779(is gi) -3.279 F -.15(ve)-.25 G .779(n, it is).15 F .394(the ne)144 244.8 R 2.894(wv) --.25 G .394(alue of the speci\214ed resource \(the)183.168 244.8 R F1 -2.893 E F0 .393(option is display only\).)2.893 F .393(If no option is gi)5.393 -F -.15(ve)-.25 G .393(n, then).15 F F1144 256.8 Q F0 .43(is assumed.)2.93 -F -1.11(Va)5.43 G .43(lues are in 1024-byte increments, e)1.11 F .431 -(xcept for)-.15 F F12.931 E F0 2.931(,w)C .431(hich is in seconds,) -421.315 256.8 R F12.931 E F0 2.931(,w)C(hich)522.78 256.8 Q .828 -(is in units of 512-byte blocks, and)144 268.8 R F13.327 E F0(and)3.327 E -F13.327 E F0 3.327(,w)C .827(hich are unscaled v)344.784 268.8 R 3.327 -(alues. The)-.25 F .827(return status is 0)3.327 F .621(unless an ille)144 -280.8 R -.05(ga)-.15 G 3.121(lo).05 G .621 -(ption is encountered, a non-numeric ar)217.603 280.8 R .622(gument other than) --.18 F F1(unlimited)3.122 E F0 .622(is supplied)3.122 F(as)144 292.8 Q F2 -(limit)2.5 E F0 2.5(,o)C 2.5(ra)183.17 292.8 S 2.5(ne)193.44 292.8 S -(rror occurs while setting a ne)205.38 292.8 Q 2.5(wl)-.25 G(imit.)333.99 292.8 -Q F1(umask)108 309.6 Q F0([)2.5 E F1A F0 2.5(][)C F2(mode)162.59 309.6 Q -F0(])A .23(The user \214le-creation mask is set to)144 321.6 R F2(mode)2.73 E -F0 5.23(.I).18 G(f)323.21 321.6 Q F2(mode)2.73 E F0(be)2.729 E .229 -(gins with a digit, it is interpreted as an octal)-.15 F .066(number; otherwis\ -e it is interpreted as a symbolic mode mask similar to that accepted by)144 -333.6 R F2 -.15(ch)2.566 G(mod).15 E F0(\(1\).).77 E(If)144 345.6 Q F2(mode) -2.55 E F0 .05(is omitted, or if the)2.55 F F12.55 E F0 .049 -(option is supplied, the current v)2.55 F .049(alue of the mask is printed.) --.25 F(The)5.049 E F12.549 E F0 .475 -(option causes the mask to be printed in symbolic form; the def)144 357.6 R -.475(ault output is an octal number)-.1 F 5.475(.A)-.55 G(n)535 357.6 Q(ar)144 -369.6 Q .125(gument of)-.18 F F12.625 E F0 .125 -(disables option checking for the rest of the ar)2.625 F 2.624(guments. The) --.18 F .124(return status is 0 if the)2.624 F(mode w)144 381.6 Q -(as successfully changed or if no)-.1 E F2(mode)2.5 E F0(ar)2.5 E(gument w)-.18 -E(as supplied, and f)-.1 E(alse otherwise.)-.1 E F1(unalias)108 398.4 Q F0 -<5bad>2.5 E F1(a)A F0 2.5(][)C F2(name)164.2 398.4 Q F0(...])2.5 E(Remo)144 -410.4 Q -.15(ve)-.15 G F2(name)2.882 E F0 2.732(sf)C .232 -(rom the list of de\214ned aliases.)211.374 410.4 R(If)5.232 E F12.733 E -F0 .233(is supplied, all alias de\214nitions are remo)2.733 F -.15(ve)-.15 G -(d.).15 E(The return v)144 422.4 Q(alue is true unless a supplied)-.25 E F2 -(name)2.5 E F0(is not a de\214ned alias.)2.5 E F1(unset)108 439.2 Q F0<5bad>2.5 -E F1(fv)A F0 2.5(][)C F2(name)159.74 439.2 Q F0(...])2.5 E -.15(Fo)144 451.2 S -2.773(re).15 G(ach)164.953 451.2 Q F2(name)2.773 E F0 2.773(,r).18 G(emo) -212.049 451.2 Q .573 -.15(ve t)-.15 H .273(he corresponding v).15 F .273 -(ariable or)-.25 F 2.773(,g)-.4 G -2.15 -.25(iv e)369.094 451.2 T 2.773(nt).25 -G(he)391.467 451.2 Q F12.773 E F0 .273(option, function.)2.773 F .272 -(An ar)5.272 F(gument)-.18 E(of)144 463.2 Q F12.58 E F0 .08 -(disables option checking for the rest of the ar)2.58 F 2.58(guments. Note)-.18 -F(that)2.58 E/F3 9/Times-Bold@0 SF -.666(PA)2.58 G(TH)-.189 E/F4 9 -/Times-Roman@0 SF(,)A F3(IFS)2.33 E F4(,)A F3(PPID)2.33 E F4(,)A F3(PS1)2.331 E -F4(,)A F3(PS2)2.331 E F4(,)A F3(UID)144 475.2 Q F4(,)A F0(and)4.074 E F3(EUID) -4.324 E F0 1.824(cannot be unset.)4.074 F 1.824(If an)6.824 F 4.323(yo)-.15 G -(f)321.938 475.2 Q F3(RANDOM)4.323 E F4(,)A F3(SECONDS)4.073 E F4(,)A F3 -(LINENO)4.073 E F4(,)A F0(or)4.073 E F3(HISTCMD)4.323 E F0(are)4.073 E .328 -(unset, the)144 487.2 R 2.828(yl)-.15 G .328(ose their special properties, e) -193.116 487.2 R -.15(ve)-.25 G 2.828(ni).15 G 2.828(ft)330.436 487.2 S(he) -339.374 487.2 Q 2.828(ya)-.15 G .328(re subsequently reset.)360.932 487.2 R -.328(The e)5.328 F .329(xit status is true)-.15 F(unless a)144 499.2 Q F2(name) -2.5 E F0(does not e)2.5 E(xist or is non-unsettable.)-.15 E F1(wait)108 516 Q -F0([)2.5 E F2(n)A F0(])A -.8(Wa)144 528 S 1.061 -(it for the speci\214ed process and return its termination status.).8 F F2(n) -6.061 E F0 1.06(may be a process ID or a job)3.56 F .753 -(speci\214cation; if a job spec is gi)144 540 R -.15(ve)-.25 G .754 -(n, all processes in that job').15 F 3.254(sp)-.55 G .754(ipeline are w)404.012 -540 R .754(aited for)-.1 F 5.754(.I)-.55 G(f)502.458 540 Q F2(n)3.254 E F0 .754 -(is not)3.254 F(gi)144 552 Q -.15(ve)-.25 G .027(n, all currently acti).15 F -.327 -.15(ve c)-.25 H .027(hild processes are w).15 F .027(aited for)-.1 F -2.526(,a)-.4 G .026(nd the return status is zero.)375.932 552 R(If)5.026 E F2 -(n)2.526 E F0(speci\214es)2.526 E 2.595(an)144 564 S(on-e)156.035 564 Q .095 -(xistant process or job, the return status is 127.)-.15 F .096 -(Otherwise, the return status is the e)5.095 F .096(xit status)-.15 F -(of the last process or job w)144 576 Q(aited for)-.1 E(.)-.55 E F3(INV)72 -592.8 Q(OCA)-.405 E(TION)-.855 E F0(A)108 604.8 Q F2(lo)2.5 E(gin shell)-.1 E -F0(is one whose \214rst character of ar)2.5 E(gument zero is a)-.18 E F12.5 -E F0 2.5(,o)C 2.5(ro)375.87 604.8 S(ne started with the)386.7 604.8 Q F1 -(\255login)2.5 E F0(\215ag.)2.5 E(An)108 621.6 Q F2(inter)2.812 E(active)-.15 E -F0 .312(shell is one whose standard input and output are both connected to ter\ -minals \(as determined)2.812 F(by)108 633.6 Q F2(isatty)2.57 E F0 .07 -(\(3\)\), or one started with the).32 F F12.57 E F0(option.)2.57 E F3 -(PS1)5.07 E F0 .07(is set and)2.32 F F1<24ad>2.57 E F0(includes)2.57 E F1(i) -2.571 E F0(if)2.571 E F1(bash)2.571 E F0 .071(is interacti)2.571 F -.15(ve)-.25 -G 2.571(,a).15 G(llo)502.679 633.6 Q .071(wing a)-.25 F -(shell script or a startup \214le to test this state.)108 645.6 Q -(Login shells:)108 662.4 Q(On login \(subject to the)113 674.4 Q F1(\255nopr) -2.5 E(o\214le)-.18 E F0(option\):)2.5 E(if)128 686.4 Q F2(/etc/pr)2.5 E -(o\214le)-.45 E F0 -.15(ex)2.5 G(ists, source it.).15 E(if)128 710.4 Q F2 -(~/.bash_pr)2.5 E(o\214le)-.45 E F0 -.15(ex)2.5 G(ists, source it,).15 E -(else if)133 722.4 Q F2(~/.bash_lo)2.5 E(gin)-.1 E F0 -.15(ex)2.5 G -(ists, source it,).15 E 185.675(GNU 1995)72 768 R(May 5)2.5 E(35)530 768 Q EP -%%Page: 36 36 -%%BeginPageSetup -BP -%%EndPageSetup -/F0 10/Times-Roman@0 SF -.35(BA)72 48 S 389.54(SH\(1\) B).35 F(ASH\(1\))-.35 E -(else if)138 84 Q/F1 10/Times-Italic@0 SF(~/.pr)2.5 E(o\214le)-.45 E F0 -.15 -(ex)2.5 G(ists, source it.).15 E(On e)113 108 Q(xit:)-.15 E(if)128 120 Q F1 -(~/.bash_lo)2.5 E(gout)-.1 E F0 -.15(ex)2.5 G(ists, source it.).15 E -(Non-login interacti)108 144 Q .3 -.15(ve s)-.25 H(hells:).15 E -(On startup \(subject to the)113 156 Q/F2 10/Times-Bold@0 SF(\255nor)2.5 E(c) --.18 E F0(and)2.5 E F22.5 E(c\214le)-.18 E F0(options\):)2.5 E(if)128 168 -Q F1(~/.bashr)2.5 E(c)-.37 E F0 -.15(ex)2.5 G(ists, source it.).15 E -(Non-interacti)108 192 Q .3 -.15(ve s)-.25 H(hells:).15 E(On startup:)113 204 Q -(if the en)128 216 Q(vironment v)-.4 E(ariable)-.25 E F2(ENV)2.5 E F0 -(is non-null, e)2.5 E(xpand)-.15 E -(it and source the \214le it names, as if the command)128 228 Q -(if [ "$ENV" ]; then . $ENV)148 240 Q 2.5<3b8c>-.74 G(had been e)128 252 Q -.15 -(xe)-.15 G(cuted, b).15 E(ut do not use)-.2 E F2 -.74(PA)2.5 G(TH)-.21 E F0 -(to search)2.5 E(for the pathname.)128 264 Q -(When not started in Posix mode, bash)5 E(looks for)128 276 Q F2 -.3(BA)2.5 G -(SH_ENV).3 E F0(before)2.5 E F2(ENV)2.5 E F0(.)A 1.023(If Bash is in)108 297.6 -R -.2(vo)-.4 G -.1(ke).2 G 3.523(da).1 G(s)191.382 297.6 Q F2(sh)3.523 E F0 -3.523(,i)C 3.523(tt)217.048 297.6 S 1.023(ries to mimic the beha)226.131 297.6 -R 1.023(vior of)-.2 F F2(sh)3.523 E F0 1.023(as closely as possible.)3.523 F --.15(Fo)6.022 G 3.522(ral).15 G 1.022(ogin shell, it)488.226 297.6 R .505 -(attempts to source only)108 309.6 R F1(/etc/pr)3.006 E(o\214le)-.45 E F0(and) -3.006 E F1(~/.pr)3.006 E(o\214le)-.45 E F0 3.006(,i).18 G 3.006(nt)311.64 309.6 -S .506(hat order)322.426 309.6 R 5.506(.T)-.55 G(he)372.318 309.6 Q F2 -(\255nopr)3.006 E(o\214le)-.18 E F0 .506(option may still be used to)3.006 F -(disable this beha)108 321.6 Q(vior)-.2 E 5(.A)-.55 G(shell in)207.24 321.6 Q --.2(vo)-.4 G -.1(ke).2 G 2.5(da).1 G(s)267.09 321.6 Q F2(sh)2.5 E F0 -(does not attempt to source an)2.5 E 2.5(yo)-.15 G(ther startup \214les.)414.71 -321.6 Q(When)108 338.4 Q F2(bash)2.71 E F0 .21(is started in)2.71 F F1(posix) -2.71 E F0 .21(mode, as with the)2.71 F F2(\255posix)2.709 E F0 .209 -(command line option, it follo)2.709 F .209(ws the Posix standard)-.25 F .187 -(for startup \214les.)108 350.4 R .188(In this mode, the)5.188 F F2(ENV)2.688 E -F0 -.25(va)2.688 G .188(riable is e).25 F .188 -(xpanded and that \214le sourced; no other startup \214les are)-.15 F(read.)108 -362.4 Q/F3 9/Times-Bold@0 SF(SEE ALSO)72 379.2 Q F1(Bash F)108 391.2 Q(eatur) --.75 E(es)-.37 E F0 2.5(,B)C(rian F)176.6 391.2 Q(ox and Chet Rame)-.15 E(y) --.15 E F1(The Gnu Readline Libr)108 403.2 Q(ary)-.15 E F0 2.5(,B)C(rian F) -225.35 403.2 Q(ox and Chet Rame)-.15 E(y)-.15 E F1(The Gnu History Libr)108 -415.2 Q(ary)-.15 E F0 2.5(,B)C(rian F)219.8 415.2 Q(ox and Chet Rame)-.15 E(y) --.15 E F1 2.5(AS)108 427.2 S(ystem V Compatible Implementation of 4.2)121.61 -427.2 Q/F4 9/Times-Italic@0 SF(BSD)A F1 -.25(Jo)2.5 G 2.5(bC).25 G(ontr)335.067 -427.2 Q(ol)-.45 E F0 2.5(,D)C -.2(av)371.287 427.2 S(id Lennert).2 E F1 -.8(Po) -108 439.2 S(rtable Oper).8 E(ating System Interface \(POSIX\) P)-.15 E -(art 2: Shell and Utilities)-.8 E F0 2.5(,I)C(EEE)404.83 439.2 Q F1(sh)108 -451.2 Q F0(\(1\),)A F1(ksh)2.5 E F0(\(1\),)A F1(csh)2.5 E F0(\(1\))A F1(emacs) -108 463.2 Q F0(\(1\),)A F1(vi)2.5 E F0(\(1\))A F1 -.37(re)108 475.2 S(adline) -.37 E F0(\(3\))A F3(FILES)72 492 Q F1(/bin/bash)109.666 504 Q F0(The)144 516 Q -F2(bash)2.5 E F0 -.15(exe)2.5 G(cutable).15 E F1(/etc/pr)109.666 528 Q(o\214le) --.45 E F0(The systemwide initialization \214le, e)144 540 Q -.15(xe)-.15 G -(cuted for login shells).15 E F1(~/.bash_pr)109.666 552 Q(o\214le)-.45 E F0 -(The personal initialization \214le, e)144 564 Q -.15(xe)-.15 G -(cuted for login shells).15 E F1(~/.bashr)109.666 576 Q(c)-.37 E F0(The indi) -144 588 Q(vidual per)-.25 E(-interacti)-.2 E -.15(ve)-.25 G -(-shell startup \214le).15 E F1(~/.inputr)109.666 600 Q(c)-.37 E F0(Indi)144 -612 Q(vidual)-.25 E F1 -.37(re)2.5 G(adline).37 E F0(initialization \214le)2.5 -E F3 -.45(AU)72 628.8 S(THORS).45 E F0(Brian F)144 640.8 Q(ox, Free Softw)-.15 -E(are F)-.1 E(oundation \(primary author\))-.15 E(bfox@ai.MIT)144 652.8 Q(.Edu) --.74 E(Chet Rame)144 669.6 Q 1.3 -.65(y, C)-.15 H(ase W).65 E(estern Reserv)-.8 -E 2.5(eU)-.15 G(ni)296.66 669.6 Q -.15(ve)-.25 G(rsity).15 E(chet@ins.CWR)144 -681.6 Q(U.Edu)-.4 E F3 -.09(BU)72 698.4 S 2.25(GR).09 G(EPOR)100.161 698.4 Q -(TS)-.36 E F0 .568(If you \214nd a b)108 710.4 R .568(ug in)-.2 F F2(bash,) -3.068 E F0 .568(you should report it.)3.068 F .568(But \214rst, you should mak) -5.568 F 3.068(es)-.1 G .568(ure that it really is a b)419.578 710.4 R .567 -(ug, and)-.2 F(that it appears in the latest v)108 722.4 Q(ersion of)-.15 E F2 -(bash)2.5 E F0(that you ha)2.5 E -.15(ve)-.2 G(.).15 E 185.675(GNU 1995)72 768 -R(May 5)2.5 E(36)530 768 Q EP -%%Page: 37 37 -%%BeginPageSetup -BP -%%EndPageSetup -/F0 10/Times-Roman@0 SF -.35(BA)72 48 S 389.54(SH\(1\) B).35 F(ASH\(1\))-.35 E -.437(Once you ha)108 84 R .737 -.15(ve d)-.2 H .438(etermined that a b).15 F -.438(ug actually e)-.2 F .438(xists, use the)-.15 F/F1 10/Times-Italic@0 SF -(bashb)2.938 E(ug)-.2 E F0 .438(command to submit a b)2.938 F .438(ug report.) --.2 F(If)5.438 E .454(you ha)108 96 R .754 -.15(ve a \214)-.2 H .453 -(x, you are welcome to mail that as well!).15 F .453 -(Suggestions and `philosophical' b)5.453 F .453(ug reports may be)-.2 F -(mailed to)108 108 Q F1 -.2(bu)2.5 G(g-bash).2 E F0(@)A F1(pr)A(ep.ai.MIT)-.37 -E(.Edu)-.74 E F0(or posted to the Usenet ne)2.5 E(wsgroup)-.25 E/F2 10 -/Times-Bold@0 SF(gnu.bash.b)2.5 E(ug)-.2 E F0(.)A(ALL b)108 124.8 Q -(ug reports should include:)-.2 E(The v)108 141.6 Q(ersion number of)-.15 E F2 -(bash)2.5 E F0(The hardw)108 153.6 Q(are and operating system)-.1 E -(The compiler used to compile)108 165.6 Q 2.5(Ad)108 177.6 S -(escription of the b)122.72 177.6 Q(ug beha)-.2 E(viour)-.2 E 2.5(As)108 189.6 -S(hort script or `recipe' which e)121.61 189.6 Q -.15(xe)-.15 G(rcises the b) -.15 E(ug)-.2 E F1(bashb)108 206.4 Q(ug)-.2 E F0 -(inserts the \214rst three items automatically into the template it pro)2.5 E -(vides for \214ling a b)-.15 E(ug report.)-.2 E(Comments and b)108 223.2 Q -(ug reports concerning this manual page should be directed to)-.2 E F1 -.15(ch) -2.5 G(et@ins.CWR).15 E -.25(U.)-.4 G(Edu).25 E F0(.).25 E/F3 9/Times-Bold@0 SF --.09(BU)72 240 S(GS).09 E F0(It')108 252 Q 2.5(st)-.55 G(oo big and too slo) -126.06 252 Q -.65(w.)-.25 G 1.868(There are some subtle dif)108 268.8 R 1.868 -(ferences between)-.25 F F2(bash)4.369 E F0 1.869(and traditional v)4.369 F -1.869(ersions of)-.15 F F2(sh)4.369 E F0 4.369(,m)C 1.869(ostly because of the) -455.243 268.8 R F3(POSIX)108 280.8 Q F0(speci\214cation.)2.25 E -(Aliases are confusing in some uses.)108 297.6 Q 185.675(GNU 1995)72 768 R -(May 5)2.5 E(37)530 768 Q EP -%%Trailer -end -%%EOF diff --git a/documentation/bash.txt b/documentation/bash.txt deleted file mode 100644 index c23f298..0000000 --- a/documentation/bash.txt +++ /dev/null @@ -1,3960 +0,0 @@ - - - -BASH(1) USER COMMANDS BASH(1) - - - -NAME - bash - GNU Bourne-Again SHell - -SYNOPSIS - bash [options] [file] - -COPYRIGHT - Bash is Copyright (C) 1989, 1991 by the Free Software Foun- - dation, Inc. - -DESCRIPTION - Bash is an sh-compatible command language interpreter that - executes commands read from the standard input or from a - file. Bash also incorporates useful features from the _K_o_r_n - and _C shells (ksh and csh). - - Bash is ultimately intended to be a conformant implementa- - tion of the IEEE Posix Shell and Tools specification (IEEE - Working Group 1003.2). - -OPTIONS - In addition to the single-character shell options documented - in the description of the set builtin command, bash inter- - prets the following flags when it is invoked: - - -c _s_t_r_i_n_g If the -c flag is present, then commands are read - from _s_t_r_i_n_g. If there are arguments after the - _s_t_r_i_n_g, they are assigned to the positional param- - eters, starting with $0. - -i If the -i flag is present, the shell is _i_n_t_e_r_a_c_- - _t_i_v_e. - -s If the -s flag is present, or if no arguments - remain after option processing, then commands are - read from the standard input. This option allows - the positional parameters to be set when invoking - an interactive shell. - - A single - signals the end of options and disables - further option processing. Any arguments after - the - are treated as filenames and arguments. An - argument of -- is equivalent to an argument of -. - - Bash also interprets a number of multi-character options. - These options must appear on the command line before the - single-character options to be recognized. - - -norc Do not read and execute the personal initializa- - tion file ~/._b_a_s_h_r_c if the shell is interactive. - This option is on by default if the shell is - invoked as sh. - -noprofile - Do not read either the system-wide startup file - /_e_t_c/_p_r_o_f_i_l_e or any of the personal initialization - - - -GNU Last change: 1995 May 5 1 - - - - - - -BASH(1) USER COMMANDS BASH(1) - - - - files ~/._b_a_s_h__p_r_o_f_i_l_e, ~/._b_a_s_h__l_o_g_i_n, or ~/._p_r_o_- - _f_i_l_e. By default, bash normally reads these files - when it is invoked as a login shell (see INVOCA- - TION below). - -rcfile _f_i_l_e - Execute commands from _f_i_l_e instead of the standard - personal initialization file ~/._b_a_s_h_r_c, if the - shell is interactive (see INVOCATION below). - -version Show the version number of this instance of bash - when starting. - -quiet Do not be verbose when starting up (do not show - the shell version or any other information). This - is the default. - -login Make bash act as if it had been invoked as a login - shell. - -nobraceexpansion - Do not perform curly brace expansion (see Brace - Expansion below). - -nolineediting - Do not use the GNU _r_e_a_d_l_i_n_e library to read com- - mand lines if interactive. - -posix Change the behavior of bash where the default - operation differs from the Posix 1003.2 standard - to match the standard - -ARGUMENTS - If arguments remain after option processing, and neither the - -c nor the -s option has been supplied, the first argument - is assumed to be the name of a file containing shell com- - mands. If bash is invoked in this fashion, $0 is set to the - name of the file, and the positional parameters are set to - the remaining arguments. Bash reads and executes commands - from this file, then exits. Bash's exit status is the exit - status of the last command executed in the script. - -DEFINITIONS - blank - A space or tab. - word A sequence of characters considered as a single unit by - the shell. Also known as a token. - name A _w_o_r_d consisting only of alphanumeric characters and - underscores, and beginning with an alphabetic character - or an underscore. Also referred to as an identifier. - metacharacter - A character that, when unquoted, separates words. One - of the following: - | & ; ( ) < > space tab - control operator - A _t_o_k_e_n that performs a control function. It is one of - the following symbols: - || & && ; ;; ( ) | - - - - -GNU Last change: 1995 May 5 2 - - - - - - -BASH(1) USER COMMANDS BASH(1) - - - -RESERVED WORDS - _R_e_s_e_r_v_e_d _w_o_r_d_s are words that have a special meaning to the - shell. The following words are recognized as reserved when - unquoted and either the first word of a simple command (see - SHELL GRAMMAR below) or the third word of a case or for com- - mand: - - ! case do done elif else esac fi for function if in select - then until while { } - -SHELL GRAMMAR - Simple Commands - A _s_i_m_p_l_e _c_o_m_m_a_n_d is a sequence of optional variable assign- - ments followed by _b_l_a_n_k-separated words and redirections, - and terminated by a _c_o_n_t_r_o_l _o_p_e_r_a_t_o_r. The first word speci- - fies the command to be executed. The remaining words are - passed as arguments to the invoked command. - - The return value of a _s_i_m_p_l_e _c_o_m_m_a_n_d is its exit status, or - 128+_n if the command is terminated by signal _n. - - Pipelines - A _p_i_p_e_l_i_n_e is a sequence of one or more commands separated - by the character |. The format for a pipeline is: - - [ ! ] _c_o_m_m_a_n_d [ | _c_o_m_m_a_n_d_2 ... ] - - The standard output of _c_o_m_m_a_n_d is connected to the standard - input of _c_o_m_m_a_n_d_2. This connection is performed before any - redirections specified by the command (see REDIRECTION - below). - - If the reserved word ! 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. - - Each command in a pipeline is executed as a separate process - (i.e., in a subshell). - - Lists - A _l_i_s_t is a sequence of one or more pipelines separated by - one of the operators ;, &, &&, or ||, and terminated by one - of ;, &, or . - - Of these list operators, && and || have equal precedence, - followed by ; and &, which have equal precedence. - - If a command is terminated by the control operator &, the - shell executes the command in the _b_a_c_k_g_r_o_u_n_d in a subshell. - - - -GNU Last change: 1995 May 5 3 - - - - - - -BASH(1) USER COMMANDS BASH(1) - - - - The shell does not wait for the command to finish, and the - return status is 0. Commands separated by a ; are executed - sequentially; the shell waits for each command to terminate - in turn. The return status is the exit status of the last - command executed. - - The control operators && and || denote AND lists and OR - lists, respectively. An AND list has the form - - _c_o_m_m_a_n_d && _c_o_m_m_a_n_d_2 - - _c_o_m_m_a_n_d_2 is executed if, and only if, _c_o_m_m_a_n_d returns an - exit status of zero. - - An OR list has the form - - _c_o_m_m_a_n_d || _c_o_m_m_a_n_d_2 - - _c_o_m_m_a_n_d_2 is executed if and only if _c_o_m_m_a_n_d returns a - non-zero exit status. The return status of AND and OR lists - is the exit status of the last command executed in the list. - - Compound Commands - A _c_o_m_p_o_u_n_d _c_o_m_m_a_n_d is one of the following: - - (_l_i_s_t) - _l_i_s_t is executed in a subshell. Variable assignments - and builtin commands that affect the shell's environ- - ment do not remain in effect after the command com- - pletes. The return status is the exit status of _l_i_s_t. - - { _l_i_s_t; } - _l_i_s_t is simply executed in the current shell environ- - ment. This is known as a _g_r_o_u_p _c_o_m_m_a_n_d. The return - status is the exit status of _l_i_s_t. - - for _n_a_m_e [ in _w_o_r_d; ] do _l_i_s_t ; done - The list of words following in is expanded, generating - a list of items. The variable _n_a_m_e is set to each ele- - ment of this list in turn, and _l_i_s_t is executed each - time. If the in _w_o_r_d is omitted, the for command exe- - cutes _l_i_s_t once for each positional parameter that is - set (see PARAMETERS below). - - select _n_a_m_e [ in _w_o_r_d; ] do _l_i_s_t ; done - The list of words following in is expanded, generating - a list of items. The set of expanded words is printed - on the standard error, each preceded by a number. If - the in _w_o_r_d is omitted, the positional parameters are - printed (see PARAMETERS below). The PS3 prompt is then - displayed and a line read from the standard input. If - the line consists of the number corresponding to one of - - - -GNU Last change: 1995 May 5 4 - - - - - - -BASH(1) USER COMMANDS BASH(1) - - - - the displayed words, then the value of _n_a_m_e is set to - that word. If the line is empty, the words and prompt - are displayed again. If EOF is read, the command com- - pletes. Any other value read causes _n_a_m_e to be set to - null. The line read is saved in the variable REPLY. - The _l_i_s_t is executed after each selection until a break - or return command is executed. The exit status of - select is the exit status of the last command executed - in _l_i_s_t, or zero if no commands were executed. - - case _w_o_r_d in [ _p_a_t_t_e_r_n [ | _p_a_t_t_e_r_n ] ... ) _l_i_s_t ;; ] ... esac - A case command first expands _w_o_r_d, and tries to match - it against each _p_a_t_t_e_r_n in turn, using the same match- - ing rules as for pathname expansion (see Pathname - Expansion below). When a match is found, the - corresponding _l_i_s_t is executed. After the first match, - no subsequent matches are attempted. The exit status - is zero if no patterns are matches. Otherwise, it is - the exit status of the last command executed in _l_i_s_t. - - if _l_i_s_t then _l_i_s_t [ elif _l_i_s_t then _l_i_s_t ] ... [ else _l_i_s_t ] fi - The if _l_i_s_t is executed. If its exit status is zero, - the then _l_i_s_t is executed. Otherwise, each elif _l_i_s_t - is executed in turn, and if its exit status is zero, - the corresponding then _l_i_s_t is executed and the command - completes. Otherwise, the else _l_i_s_t is executed, if - present. The exit status is the exit status of the - last command executed, or zero if no condition tested - true. - - while _l_i_s_t do _l_i_s_t done - until _l_i_s_t do _l_i_s_t done - The while command continuously executes the do _l_i_s_t as - long as the last command in _l_i_s_t returns an exit status - of zero. The until command is identical to the while - command, except that the test is negated; the do _l_i_s_t - is executed as long as the last command in _l_i_s_t returns - a non-zero exit status. The exit status of the while - and until commands is the exit status of the last do - _l_i_s_t command executed, or zero if none was executed. - - [ function ] _n_a_m_e () { _l_i_s_t; } - This defines a function named _n_a_m_e. The _b_o_d_y of the - function is the _l_i_s_t of commands between { and }. This - list is executed whenever _n_a_m_e 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 FUNCTIONS below.) - -COMMENTS - In a non-interactive shell, or an interactive shell in which - the -o interactive-comments option to the set builtin is - - - -GNU Last change: 1995 May 5 5 - - - - - - -BASH(1) USER COMMANDS BASH(1) - - - - enabled, a word beginning with # causes that word and all - remaining characters on that line to be ignored. An - interactive shell without the -o interactive-comments option - enabled does not allow comments. - -QUOTING - _Q_u_o_t_i_n_g is used to remove the special meaning of certain - characters or words to the shell. Quoting can be used to - disable special treatment for special characters, to prevent - reserved words from being recognized as such, and to prevent - parameter expansion. - - Each of the _m_e_t_a_c_h_a_r_a_c_t_e_r_s listed above under DEFINITIONS - has special meaning to the shell and must be quoted if they - are to represent themselves. There are three quoting - mechanisms: the _e_s_c_a_p_e _c_h_a_r_a_c_t_e_r, single quotes, and double - quotes. - - A non-quoted backslash (\) is the _e_s_c_a_p_e _c_h_a_r_a_c_t_e_r. It - preserves the literal value of the next character that fol- - lows, with the exception of . If a \ pair - appears, and the backslash is not quoted, the \ is - treated as a line continuation (that is, it is effectively - ignored). - - Enclosing characters in single quotes preserves the literal - value of each character within the quotes. A single quote - may not occur between single quotes, even when preceded by a - backslash. - - Enclosing characters in double quotes preserves the literal - value of all characters within the quotes, with the excep- - tion of $, `, and \. The characters $ and ` retain their - special meaning within double quotes. The backslash retains - its special meaning only when followed by one of the follow- - ing characters: $, `, ", \, or . A double quote - may be quoted within double quotes by preceding it with a - backslash. - - The special parameters * and @ have special meaning when in - double quotes (see PARAMETERS below). - -PARAMETERS - A _p_a_r_a_m_e_t_e_r is an entity that stores values, somewhat like a - variable in a conventional programming language. It can be - a _n_a_m_e, a number, or one of the special characters listed - below under Special Parameters. For the shell's purposes, a - _v_a_r_i_a_b_l_e is a parameter denoted by a _n_a_m_e. - - A parameter is set if it has been assigned a value. The - null string is a valid value. Once a variable is set, it - may be unset only by using the unset builtin command (see - - - -GNU Last change: 1995 May 5 6 - - - - - - -BASH(1) USER COMMANDS BASH(1) - - - - SHELL BUILTIN COMMANDS below). - - A _v_a_r_i_a_b_l_e may be assigned to by a statement of the form - - _n_a_m_e=[_v_a_l_u_e] - - If _v_a_l_u_e is not given, the variable is assigned the null - string. All _v_a_l_u_e_s undergo tilde expansion, parameter and - variable expansion, command substitution, arithmetic expan- - sion, and quote removal. If the variable has its -i attri- - bute set (see declare below in SHELL BUILTIN COMMANDS) then - _v_a_l_u_e is subject to arithmetic expansion even if the $[...] - syntax does not appear. Word splitting is not performed, - with the exception of "$@" as explained below under Special - Parameters. Pathname expansion is not performed. - - Positional Parameters - A _p_o_s_i_t_i_o_n_a_l _p_a_r_a_m_e_t_e_r is a parameter denoted by one or more - digits, other than the single digit 0. Positional parame- - ters are assigned from the shell's arguments when it is - invoked, and may be reassigned using the set builtin com- - mand. Positional parameters may not be assigned to with - assignment statements. The positional parameters are tem- - porarily replaced when a shell function is executed (see - FUNCTIONS below). - - When a positional parameter consisting of more than a single - digit is expanded, it must be enclosed in braces (see EXPAN- - SION below). - - Special Parameters - The shell treats several parameters specially. These param- - eters may only be referenced; assignment to them is not - allowed. - * Expands to the positional parameters, starting from - one. When the expansion occurs within double quotes, - it expands to a single word with the value of each - parameter separated by the first character of the IFS - special variable. That is, ``$*'' is equivalent to - ``$1_c$2_c...'', where _c is the first character of the - value of the IFS variable. If IFS is null or unset, - the parameters are separated by spaces. - @ Expands to the positional parameters, starting from - one. When the expansion occurs within double quotes, - each parameter expands as a separate word. That is, `` - $@'' is equivalent to ``$1'' ``$2'' ... When there are - no positional parameters, ``$@'' and $@ expand to noth- - ing (i.e., they are removed). - # Expands to the number of positional parameters in - decimal. - ? Expands to the status of the most recently executed - foreground pipeline. - - - -GNU Last change: 1995 May 5 7 - - - - - - -BASH(1) USER COMMANDS BASH(1) - - - - - Expands to the current option flags as specified upon - invocation, by the set builtin command, or those set by - the shell itself (such as the -i flag). - $ Expands to the process ID of the shell. In a () sub- - shell, it expands to the process ID of the current - shell, not the subshell. - ! Expands to the process ID of the most recently executed - background (asynchronous) command. - 0 Expands to the name of the shell or shell script. This - is set at shell initialization. If bash is invoked - with a file of commands, $0 is set to the name of that - file. If bash is started with the -c option, then $0 - is set to the first argument after the string to be - executed, if one is present. Otherwise, it is set to - the pathname used to invoke bash, as given by argument - zero. - _ Expands to the last argument to the previous command, - after expansion. Also set to the full pathname of each - command executed and placed in the environment exported - to that command. - - Shell Variables - The following variables are set by the shell: - - PPID The process ID of the shell's parent. - PWD The current working directory as set by the cd command. - OLDPWD - The previous working directory as set by the cd com- - mand. - REPLY - Set to the line of input read by the read builtin com- - mand when no arguments are supplied. - UID Expands to the user ID of the current user, initialized - at shell startup. - EUID Expands to the effective user ID of the current user, - initialized at shell startup. - BASH Expands to the full pathname used to invoke this - instance of bash. - BASH_VERSION - Expands to the version number of this instance of bash. - SHLVL - Incremented by one each time an instance of bash is - started. - RANDOM - Each time this parameter is referenced, a random - integer is generated. The sequence of random numbers - may be initialized by assigning a value to RANDOM. If - RANDOM is unset, it loses its special properties, even - if it is subsequently reset. - SECONDS - Each time this parameter is referenced, the number of - seconds since shell invocation is returned. If a value - - - -GNU Last change: 1995 May 5 8 - - - - - - -BASH(1) USER COMMANDS BASH(1) - - - - is assigned to SECONDS, the value returned upon subse- - quent references is the number of seconds since the - assignment plus the value assigned. If SECONDS is - unset, it loses its special properties, even if it is - subsequently reset. - LINENO - Each time this parameter is referenced, the shell sub- - stitutes a decimal number representing the current - sequential line number (starting with 1) within a - script or function. When not in a script or function, - the value substituted is not guaranteed to be meaning- - ful. When in a function, the value is not the number - of the source line that the command appears on (that - information has been lost by the time the function is - executed), but is an approximation of the number of - _s_i_m_p_l_e _c_o_m_m_a_n_d_s executed in the current function. If - LINENO is unset, it loses its special properties, even - if it is subsequently reset. - HISTCMD - The history number, or index in the history list, of - the current command. If HISTCMD is unset, it loses its - special properties, even if it is subsequently reset. - OPTARG - The value of the last option argument processed by the - getopts builtin command (see SHELL BUILTIN COMMANDS - below). - OPTIND - The index of the next argument to be processed by the - getopts builtin command (see SHELL BUILTIN COMMANDS - below). - HOSTTYPE - Automatically set to a string that uniquely describes - the type of machine on which bash is executing. The - default is system-dependent. - OSTYPE - Automatically set to a string that describes the - operating system on which bash is executing. The - default is system-dependent. - - The following variables are used by the shell. In some - cases, bash assigns a default value to a variable; these - cases are noted below. - - IFS The _I_n_t_e_r_n_a_l _F_i_e_l_d _S_e_p_a_r_a_t_o_r that is used for word - splitting after expansion and to split lines into words - with the read builtin command. The default value is - ``''. - PATH The search path for commands. It is a colon-separated - list of directories in which the shell looks for com- - mands (see COMMAND EXECUTION below). The default path - is system-dependent, and is set by the administrator - who installs bash. A common value is - - - -GNU Last change: 1995 May 5 9 - - - - - - -BASH(1) USER COMMANDS BASH(1) - - - - ``/usr/gnu/bin:/usr/local/bin:/usr/ucb:/bin:/usr/bin:.''. - HOME The home directory of the current user; the default - argument for the cd builtin command. - CDPATH - The search path for the cd command. This is a colon- - separated list of directories in which the shell looks - for destination directories specified by the cd com- - mand. A sample value is ``.:~:/usr''. - ENV If this parameter is set when bash is executing a shell - script, its value is interpreted as a filename contain- - ing commands to initialize the shell, as in ._b_a_s_h_r_c. - The value of ENV is subjected to parameter expansion, - command substitution, and arithmetic expansion before - being interpreted as a pathname. PATH is not used to - search for the resultant pathname. - MAIL If this parameter is set to a filename and the MAILPATH - variable is not set, bash informs the user of the - arrival of mail in the specified file. - MAILCHECK - Specifies how often (in seconds) bash checks for mail. - The default is 60 seconds. When it is time to check - for mail, the shell does so before prompting. If this - variable is unset, the shell disables mail checking. - MAILPATH - A colon-separated list of pathnames to be checked for - mail. The message to be printed may be specified by - separating the pathname from the message with a `?'. - $_ stands for the name of the current mailfile. Exam- - ple: - MAILPATH='/usr/spool/mail/bfox?"You have - mail":~/shell-mail?"$_ has mail!"' - Bash supplies a default value for this variable, but - the location of the user mail files that it uses is - system dependent (e.g., /usr/spool/mail/$USER). - MAIL_WARNING - If set, and a file that bash is checking for mail has - been accessed since the last time it was checked, the - message ``The mail in _m_a_i_l_f_i_l_e has been read'' is - printed. - PS1 The value of this parameter is expanded (see PROMPTING - below) and used as the primary prompt string. The - default value is ``bash\$ ''. - PS2 The value of this parameter is expanded and used as the - secondary prompt string. The default is ``> ''. - PS3 The value of this parameter is used as the prompt for - the _s_e_l_e_c_t command (see SHELL GRAMMAR above). - PS4 The value of this parameter is expanded and the value - is printed before each command bash displays during an - execution trace. The first character of PS4 is repli- - cated multiple times, as necessary, to indicate multi- - ple levels of indirection. The default is ``+ ''. - HISTSIZE - - - -GNU Last change: 1995 May 5 10 - - - - - - -BASH(1) USER COMMANDS BASH(1) - - - - The number of commands to remember in the command his- - tory (see HISTORY below). The default value is 500. - HISTFILE - The name of the file in which command history is saved. - (See HISTORY below.) The default value is - ~/._b_a_s_h__h_i_s_t_o_r_y. If unset, the command history is not - saved when an interactive shell exits. - HISTFILESIZE - The maximum number of lines contained in the history - file. When this variable is assigned a value, the his- - tory file is truncated, if necessary, to contain no - more than that number of lines. The default value is - 500. - OPTERR - If set to the value 1, bash displays error messages - generated by the getopts builtin command (see SHELL - BUILTIN COMMANDS below). OPTERR is initialized to 1 - each time the shell is invoked or a shell script is - executed. - PROMPT_COMMAND - If set, the value is executed as a command prior to - issuing each primary prompt. - IGNOREEOF - Controls the action of the shell on receipt of an EOF - character as the sole input. If set, the value is the - number of consecutive EOF characters typed as the first - characters on an input line before bash exits. If the - variable exists but does not have a numeric value, or - has no value, the default value is 10. If it does not - exist, EOF signifies the end of input to the shell. - This is only in effect for interactive shells. - TMOUT - If set to a value greater than zero, the value is - interpreted as the number of seconds to wait for input - after issuing the primary prompt. Bash terminates - after waiting for that number of seconds if input does - not arrive. - FCEDIT - The default editor for the fc builtin command. - FIGNORE - A colon-separated list of suffixes to ignore when per- - forming filename completion (see READLINE below). A - filename whose suffix matches one of the entries in - FIGNORE is excluded from the list of matched filenames. - A sample value is ``.o:~''. - INPUTRC - The filename for the readline startup file, overriding - the default of ~/._i_n_p_u_t_r_c (see READLINE below). - notify - If set, bash reports terminated background jobs immedi- - ately, rather than waiting until before printing the - next primary prompt (see also the -b option to the set - - - -GNU Last change: 1995 May 5 11 - - - - - - -BASH(1) USER COMMANDS BASH(1) - - - - builtin command). - history_control - HISTCONTROL - If set to a value of _i_g_n_o_r_e_s_p_a_c_e, lines which begin - with a space character are not entered on the history - list. If set to a value of _i_g_n_o_r_e_d_u_p_s, lines matching - the last history line are not entered. A value of - _i_g_n_o_r_e_b_o_t_h combines the two options. If unset, or if - set to any other value than those above, all lines read - by the parser are saved on the history list. - - command_oriented_history - If set, bash attempts to save all lines of a - multiple-line command in the same history entry. This - allows easy re-editing of multi-line commands. - - glob_dot_filenames - If set, bash includes filenames beginning with a `.' in - the results of pathname expansion. - - allow_null_glob_expansion - If set, bash allows pathname patterns which match no - files (see Pathname Expansion below) to expand to a - null string, rather than themselves. - - histchars - The two or three characters which control history - expansion and tokenization (see HISTORY EXPANSION - below). The first character is the _h_i_s_t_o_r_y _e_x_p_a_n_s_i_o_n - _c_h_a_r_a_c_t_e_r, that is, the character which signals the - start of a history expansion, normally `!'. The second - character is the _q_u_i_c_k _s_u_b_s_t_i_t_u_t_i_o_n character, which is - used as shorthand for re-running the previous command - entered, substituting one string for another in the - command. The default is `^'. The optional third char- - acter is the character which signifies that the - remainder of the line is a comment, when found as the - first character of a word, normally `#'. The history - comment character causes history substitution to be - skipped for the remaining words on the line. It does - not necessarily cause the shell parser to treat the - rest of the line as a comment. - - nolinks - If set, the shell does not follow symbolic links when - executing commands that change the current working - directory. It uses the physical directory structure - instead. By default, bash follows the logical chain of - directories when performing commands which change the - current directory, such as cd. See also the descrip- - tion of the -P option to the set builtin ( SHELL BUIL- - TIN COMMANDS below). - - - -GNU Last change: 1995 May 5 12 - - - - - - -BASH(1) USER COMMANDS BASH(1) - - - - hostname_completion_file - HOSTFILE - Contains the name of a file in the same format as - /_e_t_c/_h_o_s_t_s that should be read when the shell needs to - complete a hostname. The file may be changed interac- - tively; the next time hostname completion is attempted - bash adds the contents of the new file to the already - existing database. - - noclobber - If set, bash does not overwrite an existing file with - the >, >&, and <> redirection operators. This variable - may be overridden when creating output files by using - the redirection operator >| instead of > (see also the - -C option to the set builtin command). - - auto_resume - This variable controls how the shell interacts with the - user and job control. If this variable is set, single - word simple commands without redirections are treated - as candidates for resumption of an existing stopped - job. There is no ambiguity allowed; if there is more - than one job beginning with the string typed, the job - most recently accessed is selected. The _n_a_m_e of a - stopped job, in this context, is the command line used - to start it. If set to the value _e_x_a_c_t, the string - supplied must match the name of a stopped job exactly; - if set to _s_u_b_s_t_r_i_n_g, the string supplied needs to match - a substring of the name of a stopped job. The _s_u_b_- - _s_t_r_i_n_g value provides functionality analogous to the %? - job id (see 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 analo- - gous to the % job id. - - no_exit_on_failed_exec - If this variable exists, a non-interactive shell will - not exit if it cannot execute the file specified in the - exec builtin command. An interactive shell does not - exit if exec fails. - - cdable_vars - If this is set, an argument to the cd builtin command - that is not a directory is assumed to be the name of a - variable whose value is the directory to change to. - -EXPANSION - Expansion is performed on the command line after it has been - split into words. There are seven kinds of expansion per- - formed: _b_r_a_c_e _e_x_p_a_n_s_i_o_n, _t_i_l_d_e _e_x_p_a_n_s_i_o_n, _p_a_r_a_m_e_t_e_r _a_n_d - _v_a_r_i_a_b_l_e _e_x_p_a_n_s_i_o_n, _c_o_m_m_a_n_d _s_u_b_s_t_i_t_u_t_i_o_n, _a_r_i_t_h_m_e_t_i_c _e_x_p_a_n_- - _s_i_o_n, _w_o_r_d _s_p_l_i_t_t_i_n_g, and _p_a_t_h_n_a_m_e _e_x_p_a_n_s_i_o_n. - - - -GNU Last change: 1995 May 5 13 - - - - - - -BASH(1) USER COMMANDS BASH(1) - - - - The order of expansions is: brace expansion, tilde expan- - sion, parameter, variable, command, and arithmetic substitu- - tion (done in a left-to-right fashion), word splitting, and - pathname expansion. - - On systems that can support it, there is an additional - expansion available: _p_r_o_c_e_s_s _s_u_b_s_t_i_t_u_t_i_o_n. - - Only brace expansion, word splitting, and pathname expansion - can change the number of words of the expansion; other - expansions expand a single word to a single word. The sin- - gle exception to this is the expansion of ``$@'' as - explained above (see PARAMETERS). - - Brace Expansion - _B_r_a_c_e _e_x_p_a_n_s_i_o_n is a mechanism by which arbitrary strings - may be generated. This mechanism is similar to _p_a_t_h_n_a_m_e - _e_x_p_a_n_s_i_o_n, but the filenames generated need not exist. Pat- - terns to be brace expanded take the form of an optional - _p_r_e_a_m_b_l_e, followed by a series of comma-separated strings - between a pair of braces, followed by an optional _p_o_s_t_a_m_b_l_e. - The preamble is prepended to each string contained within - the braces, and the postamble is then appended to each - resulting string, expanding left to right. - - Brace expansions may be nested. The results of each - expanded string are not sorted; left to right order is - preserved. For example, a{d,c,b}e expands into `ade ace - abe'. - - Brace expansion is performed before any other expansions, - and any characters special to other expansions are preserved - in the result. It is strictly textual. Bash does not apply - any syntactic interpretation to the context of the expansion - or the text between the braces. - - A correctly-formed brace expansion must contain unquoted - opening and closing braces, and at least one unquoted comma. - Any incorrectly formed brace expansion is left unchanged. - - This construct is typically used as shorthand when the com- - mon prefix of the strings to be generated is longer than in - the above example: - - mkdir /usr/local/src/bash/{old,new,dist,bugs} - or - chown root /usr/{ucb/{ex,edit},lib/{ex?.?*,how_ex}} - - Brace expansion introduces a slight incompatibility with - traditional versions of sh, the Bourne shell. sh does not - treat opening or closing braces specially when they appear - as part of a word, and preserves them in the output. Bash - - - -GNU Last change: 1995 May 5 14 - - - - - - -BASH(1) USER COMMANDS BASH(1) - - - - removes braces from words as a consequence of brace expan- - sion. For example, a word entered to sh as _f_i_l_e{_1,_2} - appears identically in the output. The same word is output - as _f_i_l_e_1 _f_i_l_e_2 after expansion by bash. If strict compati- - bility with sh is desired, start bash with the -nobraceex- - pansion flag (see OPTIONS above) or disable brace expansion - with the +o braceexpand option to the set command (see SHELL - BUILTIN COMMANDS below). - - Tilde Expansion - If a word begins with a tilde character (`~'), all of the - characters preceding the first slash (or all characters, if - there is no slash) are treated as a possible _l_o_g_i_n _n_a_m_e. If - this _l_o_g_i_n _n_a_m_e is the null string, the tilde is replaced - with the value of the parameter HOME. If HOME is unset, the - home directory of the user executing the shell is substi- - tuted instead. - - If a `+' follows the tilde, the value of PWD replaces the - tilde and `+'. If a `-' follows, the value of OLDPWD is - substituted. If the value following the tilde is a valid - _l_o_g_i_n _n_a_m_e, the tilde and _l_o_g_i_n _n_a_m_e are replaced with the - home directory associated with that name. If the name is - invalid, or the tilde expansion fails, the word is - unchanged. - - Each variable assignment is checked for unquoted instances - of tildes following a : or =. In these cases, tilde substi- - tution is also performed. Consequently, one may use path- - names with tildes in assignments to PATH, MAILPATH, and - CDPATH, and the shell assigns the expanded value. - - Parameter Expansion - The `$' character introduces parameter expansion, command - substitution, or arithmetic expansion. The parameter name - or symbol to be expanded may be enclosed in braces, which - are optional but serve to protect the variable to be - expanded from characters immediately following it which - could be interpreted as part of the name. - - ${_p_a_r_a_m_e_t_e_r} - The value of _p_a_r_a_m_e_t_e_r is substituted. The braces are - required when _p_a_r_a_m_e_t_e_r is a positional parameter with - more than one digit, or when _p_a_r_a_m_e_t_e_r is followed by a - character which is not to be interpreted as part of its - name. - - In each of the cases below, _w_o_r_d is subject to tilde expan- - sion, parameter expansion, command substitution, and arith- - metic expansion. Bash tests for a parameter that is unset - or null; omitting the colon results in a test only for a - parameter that is unset. - - - -GNU Last change: 1995 May 5 15 - - - - - - -BASH(1) USER COMMANDS BASH(1) - - - - ${_p_a_r_a_m_e_t_e_r:-_w_o_r_d} - Use Default Values. If _p_a_r_a_m_e_t_e_r is unset or null, the - expansion of _w_o_r_d is substituted. Otherwise, the value - of _p_a_r_a_m_e_t_e_r is substituted. - ${_p_a_r_a_m_e_t_e_r:=_w_o_r_d} - Assign Default Values. If _p_a_r_a_m_e_t_e_r is unset or null, - the expansion of _w_o_r_d is assigned to _p_a_r_a_m_e_t_e_r. The - value of _p_a_r_a_m_e_t_e_r is then substituted. Positional - parameters and special parameters may not be assigned - to in this way. - ${_p_a_r_a_m_e_t_e_r:?_w_o_r_d} - Display Error if Null or Unset. If _p_a_r_a_m_e_t_e_r is null - or unset, the expansion of _w_o_r_d (or a message to that - effect if _w_o_r_d is not present) is written to the stan- - dard error and the shell, if it is not interactive, - exits. Otherwise, the value of _p_a_r_a_m_e_t_e_r is substi- - tuted. - ${_p_a_r_a_m_e_t_e_r:+_w_o_r_d} - Use Alternate Value. If _p_a_r_a_m_e_t_e_r is null or unset, - nothing is substituted, otherwise the expansion of _w_o_r_d - is substituted. - ${#_p_a_r_a_m_e_t_e_r} - The length in characters of the value of _p_a_r_a_m_e_t_e_r is - substituted. If _p_a_r_a_m_e_t_e_r is * or @, the length sub- - stituted is the length of * expanded within double - quotes. - ${_p_a_r_a_m_e_t_e_r#_w_o_r_d} - ${_p_a_r_a_m_e_t_e_r##_w_o_r_d} - The _w_o_r_d is expanded to produce a pattern just as in - pathname expansion. If the pattern matches the begin- - ning of the value of _p_a_r_a_m_e_t_e_r, then the expansion is - the value of _p_a_r_a_m_e_t_e_r with the shortest matching pat- - tern deleted (the ``#'' case) or the longest matching - pattern deleted (the ``##'' case). - - ${_p_a_r_a_m_e_t_e_r%_w_o_r_d} - ${_p_a_r_a_m_e_t_e_r%%_w_o_r_d} - The _w_o_r_d is expanded to produce a pattern just as in - pathname expansion. If the pattern matches a trailing - portion of the value of _p_a_r_a_m_e_t_e_r, then the expansion - is the value of _p_a_r_a_m_e_t_e_r with the shortest matching - pattern deleted (the ``%'' case) or the longest match- - ing pattern deleted (the ``%%'' case). - - Command Substitution - _C_o_m_m_a_n_d _s_u_b_s_t_i_t_u_t_i_o_n allows the output of a command to - replace the command name. There are two forms: - - $(_c_o_m_m_a_n_d) - or - `_c_o_m_m_a_n_d` - - - - -GNU Last change: 1995 May 5 16 - - - - - - -BASH(1) USER COMMANDS BASH(1) - - - - Bash performs the expansion by executing _c_o_m_m_a_n_d and replac- - ing the command substitution with the standard output of the - command, with any trailing newlines deleted. - - When the old-style backquote form of substitution is used, - backslash retains its literal meaning except when followed - by $, `, or \. When using the $(_c_o_m_m_a_n_d) form, all charac- - ters between the parentheses make up the command; none are - treated specially. - - Command substitutions may be nested. To nest when using the - old form, escape the inner backquotes with backslashes. - - If the substitution appears within double quotes, word - splitting and pathname expansion are not performed on the - results. - - Arithmetic Expansion - Arithmetic expansion allows the evaluation of an arithmetic - expression and the substitution of the result. There are - two formats for arithmetic expansion: - - $[_e_x_p_r_e_s_s_i_o_n] - - $((_e_x_p_r_e_s_s_i_o_n)) - - The _e_x_p_r_e_s_s_i_o_n is treated as if it were within double - quotes, but a double quote inside the braces or parentheses - is not treated specially. All tokens in the expression - undergo parameter expansion, command substitution, and quote - removal. Arithmetic substitutions may be nested. - - The evaluation is performed according to the rules listed - below under ARITHMETIC EVALUATION. If _e_x_p_r_e_s_s_i_o_n is - invalid, bash prints a message indicating failure and no - substitution occurs. - - Process Substitution - _P_r_o_c_e_s_s _s_u_b_s_t_i_t_u_t_i_o_n is supported on systems that support - named pipes (_F_I_F_O_s) or the /dev/fd method of naming open - files. It takes the form of <(_l_i_s_t) or >(_l_i_s_t). The pro- - cess _l_i_s_t is run with its input or output connected to a - _F_I_F_O or some file in /dev/fd. The name of this file is - passed as an argument to the current command as the result - of the expansion. If the >(_l_i_s_t) form is used, writing to - the file will provide input for _l_i_s_t. If the <(_l_i_s_t) form - is used, the file passed as an argument should be read to - obtain the output of _l_i_s_t. - - On systems that support it, _p_r_o_c_e_s_s _s_u_b_s_t_i_t_u_t_i_o_n is per- - formed simultaneously with _p_a_r_a_m_e_t_e_r _a_n_d _v_a_r_i_a_b_l_e _e_x_p_a_n_s_i_o_n, - _c_o_m_m_a_n_d _s_u_b_s_t_i_t_u_t_i_o_n, and _a_r_i_t_h_m_e_t_i_c _e_x_p_a_n_s_i_o_n. - - - -GNU Last change: 1995 May 5 17 - - - - - - -BASH(1) USER COMMANDS BASH(1) - - - - Word Splitting - The shell scans the results of parameter expansion, command - substitution, and arithmetic expansion that did not occur - within double quotes for _w_o_r_d _s_p_l_i_t_t_i_n_g. - - The shell treats each character of IFS as a delimiter, and - splits the results of the other expansions into words on - these characters. If the value of IFS is exactly - , the default, then any sequence of IFS - characters serves to delimit words. If IFS has a value - other than the default, then sequences of the whitespace - characters space and tab are ignored at the beginning and - end of the word, as long as the whitespace character is in - the value of IFS (an IFS whitespace character). Any charac- - ter in IFS that is not IFS whitespace, along with any adja- - cent IFS whitespace characters, delimits a field. A - sequence of IFS whitespace characters is also treated as a - delimiter. If the value of IFS is null, no word splitting - occurs. IFS cannot be unset. - - Explicit null arguments ("" or '') are retained. Implicit - null arguments, resulting from the expansion of _p_a_r_a_m_e_t_e_r_s - that have no values, are removed. - - Note that if no expansion occurs, no splitting is performed. - - Pathname Expansion - After word splitting, unless the -f option has been set, - bash scans each _w_o_r_d for the characters *, ?, and [. If one - of these characters appears, then the word is regarded as a - _p_a_t_t_e_r_n, and replaced with an alphabetically sorted list of - pathnames matching the pattern. If no matching pathnames - are found, and the shell variable allow_null_glob_expansion - is unset, the word is left unchanged. If the variable is - set, and no matches are found, the word is removed. When a - pattern is used for pathname generation, the character ``.'' - at the start of a name or immediately following a slash must - be matched explicitly, unless the shell variable - glob_dot_filenames is set. The slash character must always - be matched explicitly. In other cases, the ``.'' character - is not treated specially. - - The special pattern characters have the following meanings: - - * Matches any string, including the null string. - ? Matches any single character. - [...] - Matches any one of the enclosed characters. A pair of - characters separated by a minus sign denotes a _r_a_n_g_e; - any character lexically between those two characters, - inclusive, is matched. If the first character follow- - ing the [ is a ! or a ^ then any character not enclosed - - - -GNU Last change: 1995 May 5 18 - - - - - - -BASH(1) USER COMMANDS BASH(1) - - - - is matched. A - or ] may be matched by including it as - the first or last character in the set. - - Quote Removal - After the preceding expansions, all unquoted occurrences of - the characters \, `, and " are removed. - -REDIRECTION - Before a command is executed, its input and output may be - _r_e_d_i_r_e_c_t_e_d using a special notation interpreted by the - shell. Redirection may also be used to open and close files - for the current shell execution environment. The following - redirection operators may precede or appear anywhere within - a _s_i_m_p_l_e _c_o_m_m_a_n_d or may follow a _c_o_m_m_a_n_d. Redirections are - processed in the order they appear, from left to right. - - In the following descriptions, if the file descriptor number - is omitted, and the first character of the redirection - operator is <, the redirection refers to the standard input - (file descriptor 0). If the first character of the redirec- - tion operator is >, the redirection refers to the standard - output (file descriptor 1). - - The word that follows the redirection operator in the fol- - lowing descriptions is subjected to brace expansion, tilde - expansion, parameter expansion, command substitution, arith- - metic expansion, quote removal, and pathname expansion. If - it expands to more than one word, bash reports an error. - - Note that the order of redirections is significant. For - example, the command - - ls > dirlist 2>&1 - - directs both standard output and standard error to the file - _d_i_r_l_i_s_t, while the command - - ls 2>&1 > dirlist - - directs only the standard output to file _d_i_r_l_i_s_t, because - the standard error was duplicated as standard output before - the standard output was redirected to _d_i_r_l_i_s_t. - - Redirecting Input - Redirection of input causes the file whose name results from - the expansion of _w_o_r_d to be opened for reading on file - descriptor _n, or the standard input (file descriptor 0) if _n - is not specified. - - The general format for redirecting input is: - - - - - -GNU Last change: 1995 May 5 19 - - - - - - -BASH(1) USER COMMANDS BASH(1) - - - - [_n]<_w_o_r_d - - Redirecting Output - Redirection of output causes the file whose name results - from the expansion of _w_o_r_d to be opened for writing on file - descriptor _n, or the standard output (file descriptor 1) if - _n is not specified. If the file does not exist it is - created; if it does exist it is truncated to zero size. - - The general format for redirecting output is: - - [_n]>_w_o_r_d - - If the redirection operator is >|, then the value of the -C - option to the set builtin command is not tested, and file - creation is attempted. (See also the description of - noclobber under Shell Variables above.) - - Appending Redirected Output - Redirection of output in this fashion causes the file whose - name results from the expansion of _w_o_r_d to be opened for - appending on file descriptor _n, or the standard output (file - descriptor 1) if _n is not specified. If the file does not - exist it is created. - - The general format for appending output is: - - [_n]>>_w_o_r_d - - Redirecting Standard Output and Standard Error - Bash allows both the standard output (file descriptor 1) and - the standard error output (file descriptor 2) to be - redirected to the file whose name is the expansion of _w_o_r_d - with this construct. - - There are two formats for redirecting standard output and - standard error: - - &>_w_o_r_d - and - >&_w_o_r_d - - Of the two forms, the first is preferred. This is semanti- - cally equivalent to - - >_w_o_r_d 2>&1 - - Here Documents - This type of redirection instructs the shell to read input - from the current source until a line containing only _w_o_r_d - (with no trailing blanks) is seen. All of the lines read up - to that point are then used as the standard input for a - - - -GNU Last change: 1995 May 5 20 - - - - - - -BASH(1) USER COMMANDS BASH(1) - - - - command. - - The format of here-documents is as follows: - - <<[-]_w_o_r_d - _h_e_r_e-_d_o_c_u_m_e_n_t - _d_e_l_i_m_i_t_e_r - - No parameter expansion, command substitution, pathname - expansion, or arithmetic expansion is performed on _w_o_r_d. If - any characters in _w_o_r_d are quoted, the _d_e_l_i_m_i_t_e_r is the - result of quote removal on _w_o_r_d, and the lines in the here- - document are not expanded. Otherwise, all lines of the - here-document are subjected to parameter expansion, command - substitution, and arithmetic expansion. In the latter case, - the pair \ is ignored, and \ must be used to quote - the characters \, $, and `. - - If the redirection operator is <<-, then all leading tab - characters are stripped from input lines and the line con- - taining _d_e_l_i_m_i_t_e_r. This allows here-documents within shell - scripts to be indented in a natural fashion. - - Duplicating File Descriptors - The redirection operator - - [_n]<&_w_o_r_d - - is used to duplicate input file descriptors. If _w_o_r_d - expands to one or more digits, the file descriptor denoted - by _n is made to be a copy of that file descriptor. If _w_o_r_d - evaluates to -, file descriptor _n is closed. If _n is not - specified, the standard input (file descriptor 0) is used. - - The operator - - [_n]>&_w_o_r_d - - is used similarly to duplicate output file descriptors. If - _n is not specified, the standard output (file descriptor 1) - is used. As a special case, if _n is omitted, and _w_o_r_d does - not expand to one or more digits, the standard output and - standard error are redirected as described previously. - - Opening File Descriptors for Reading and Writing - The redirection operator - - [_n]<>_w_o_r_d - - causes the file whose name is the expansion of _w_o_r_d to be - opened for both reading and writing on file descriptor _n, or - as the standard input and standard output if _n is not - - - -GNU Last change: 1995 May 5 21 - - - - - - -BASH(1) USER COMMANDS BASH(1) - - - - specified. If the file does not exist, it is created. - -FUNCTIONS - A shell function, defined as described above under SHELL - GRAMMAR, stores a series of commands for later execution. - Functions are executed in the context of the current shell; - no new process is created to interpret them (contrast this - with the execution of a shell script). When a function is - executed, the arguments to the function become the posi- - tional parameters during its execution. The special parame- - ter # is updated to reflect the change. Positional parame- - ter 0 is unchanged. - - Variables local to the function may be declared with the - local builtin command. Ordinarily, variables and their - values are shared between the function and its caller. - - If the builtin command return is executed in a function, the - function completes and execution resumes with the next com- - mand after the function call. When a function completes, - the values of the positional parameters and the special - parameter # are restored to the values they had prior to - function execution. - - Function names and definitions may be listed with the -f - option to the declare or typeset builtin commands. Func- - tions may be exported so that subshells automatically have - them defined with the -f option to the export builtin. - - Functions may be recursive. No limit is imposed on the - number of recursive calls. - -ALIASES - The shell maintains a list of _a_l_i_a_s_e_s that may be set and - unset with the alias and unalias builtin commands (see SHELL - BUILTIN COMMANDS below). 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 alias name - and the replacement text may contain any valid shell input, - including the _m_e_t_a_c_h_a_r_a_c_t_e_r_s listed above, with the excep- - tion that the alias name may not contain =. 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 ls to ls -F, - for instance, and bash does not try to recursively expand - the replacement text. If the last character of the alias - value is a _b_l_a_n_k, then the next command word following the - alias is also checked for alias expansion. - - Aliases are created and listed with the alias command, and - removed with the unalias command. - - - - -GNU Last change: 1995 May 5 22 - - - - - - -BASH(1) USER COMMANDS BASH(1) - - - - There is no mechanism for using arguments in the replacement - text, as in csh. If arguments are needed, a shell function - should be used. - - Aliases are not expanded when the shell is not interactive. - - The rules concerning the definition and use of aliases are - somewhat confusing. Bash always reads at least one complete - line of input before executing any of the commands on that - line. Aliases are expanded when a command is read, not when - it is executed. Therefore, an alias definition appearing on - the same line as another command does not take effect until - the next line of input is read. This means that the com- - mands following the alias definition on that line are not - affected by the new alias. This behavior is also an issue - when functions are executed. Aliases are expanded when the - function definition is read, not when the function is exe- - cuted, because a function definition is itself a compound - command. As a consequence, aliases defined in a function - are not available until after that function is executed. To - be safe, always put alias definitions on a separate line, - and do not use alias in compound commands. - - Note that for almost every purpose, aliases are superseded - by shell functions. - -JOB CONTROL - _J_o_b _c_o_n_t_r_o_l refers to the ability to selectively stop - (_s_u_s_p_e_n_d) the execution of processes and continue (_r_e_s_u_m_e) - their execution at a later point. A user typically employs - this facility via an interactive interface supplied jointly - by the system's terminal driver and bash. - - The shell associates a _j_o_b with each pipeline. It keeps a - table of currently executing jobs, which may be listed with - the jobs command. When bash starts a job asynchronously (in - the _b_a_c_k_g_r_o_u_n_d), it prints a line that looks like: - - [1] 25647 - - indicating that this job is job number 1 and that the pro- - cess ID of the last process in the pipeline associated with - this job is 25647. All of the processes in a single pipe- - line are members of the same job. Bash uses the _j_o_b - abstraction as the basis for job control. - - To facilitate the implementation of the user interface to - job control, the system maintains the notion of a _c_u_r_r_e_n_t - _t_e_r_m_i_n_a_l _p_r_o_c_e_s_s _g_r_o_u_p _I_D. Members of this process group - (processes whose process group ID is equal to the current - terminal process group ID) receive keyboard-generated sig- - nals such as SIGINT. These processes are said to be in the - - - -GNU Last change: 1995 May 5 23 - - - - - - -BASH(1) USER COMMANDS BASH(1) - - - - _f_o_r_e_g_r_o_u_n_d. _B_a_c_k_g_r_o_u_n_d processes are those whose process - group ID differs from the terminal's; such processes are - immune to keyboard-generated signals. Only foreground - processes are allowed to read from or write to the terminal. - Background processes which attempt to read from (write to) - the terminal are sent a SIGTTIN (SIGTTOU) signal by the ter- - minal driver, which, unless caught, suspends the process. - - If the operating system on which bash is running supports - job control, bash allows you to use it. Typing the _s_u_s_p_e_n_d - character (typically ^Z, Control-Z) while a process is run- - ning causes that process to be stopped and returns you to - bash. Typing the _d_e_l_a_y_e_d _s_u_s_p_e_n_d character (typically ^Y, - Control-Y) causes the process to be stopped when it attempts - to read input from the terminal, and control to be returned - to bash. You may then manipulate the state of this job, - using the bg command to continue it in the background, the - fg command to continue it in the foreground, or the kill - command to kill it. A ^Z takes effect immediately, and has - the additional side effect of causing pending output and - typeahead to be discarded. - - There are a number of ways to refer to a job in the shell. - The character % introduces a job name. Job number _n may be - referred to as %n. A job may also be referred to using a - prefix of the name used to start it, or using a substring - that appears in its command line. For example, %ce refers - to a stopped ce job. If a prefix matches more than one job, - bash reports an error. Using %?ce, on the other hand, - refers to any job containing the string ce in its command - line. If the substring matches more than one job, bash - reports an error. The symbols %% and %+ refer to the - shell's notion of the _c_u_r_r_e_n_t _j_o_b, which is the last job - stopped while it was in the foreground. The _p_r_e_v_i_o_u_s _j_o_b - may be referenced using %-. In output pertaining to jobs - (e.g., the output of the jobs command), the current job is - always flagged with a +, and the previous job with a -. - - Simply naming a job can be used to bring it into the fore- - ground: %1 is a synonym for ``fg %1'', bringing job 1 from - the background into the foreground. Similarly, ``%1 &'' - resumes job 1 in the background, equivalent to ``bg %1''. - - The shell learns immediately whenever a job changes state. - Normally, bash waits until it is about to print a prompt - before reporting changes in a job's status so as to not - interrupt any other output. If the -b option to the set - builtin command is set, bash reports such changes immedi- - ately. (See also the description of notify variable under - Shell Variables above.) - - - - - -GNU Last change: 1995 May 5 24 - - - - - - -BASH(1) USER COMMANDS BASH(1) - - - - If you attempt to exit bash while jobs are stopped, the - shell prints a message warning you. You may then use the - jobs command to inspect their status. If you do this, or - try to exit again immediately, you are not warned again, and - the stopped jobs are terminated. - -SIGNALS - When bash is interactive, it ignores SIGTERM (so that kill 0 - does not kill an interactive shell), and SIGINT is caught - and handled (so that the wait builtin is interruptible). In - all cases, bash ignores SIGQUIT. If job control is in - effect, bash ignores SIGTTIN, SIGTTOU, and SIGTSTP. - - Synchronous jobs started by bash have signals set to the - values inherited by the shell from its parent. When job - control is not in effect, background jobs (jobs started with - &) ignore SIGINT and SIGQUIT. Commands run as a result of - command substitution ignore the keyboard-generated job con- - trol signals SIGTTIN, SIGTTOU, and SIGTSTP. - -COMMAND EXECUTION - After a command has been split into words, if it results in - a simple command and an optional list of arguments, the fol- - lowing actions are taken. - - If the command name contains no slashes, the shell attempts - to locate it. If there exists a shell function by that - name, that function is invoked as described above in FUNC- - TIONS. If the name does not match a function, the shell - searches for it in the list of shell builtins. If a match - is found, that builtin is invoked. - - If the name is neither a shell function nor a builtin, and - contains no slashes, bash searches each element of the PATH - for a directory containing an executable file by that name. - If the search is unsuccessful, the shell prints an error - message and returns a nonzero exit status. - - If the search is successful, or if the command name contains - one or more slashes, the shell executes the named program. - Argument 0 is set to the name given, and the remaining argu- - ments to the command are set to the arguments given, if any. - - If this execution fails because the file is not in execut- - able format, and the file is not a directory, it is assumed - to be a _s_h_e_l_l _s_c_r_i_p_t, a file containing shell commands. A - subshell is spawned to execute it. This subshell reinitial- - izes itself, so that the effect is as if a new shell had - been invoked to handle the script, with the exception that - the locations of commands remembered by the parent (see hash - below under SHELL BUILTIN COMMANDS) are retained by the - child. - - - -GNU Last change: 1995 May 5 25 - - - - - - -BASH(1) USER COMMANDS BASH(1) - - - - If the program is a file beginning with #!, the remainder of - the first line specifies an interpreter for the program. - The shell executes the specified interpreter on operating - systems that do not handle this executable format them- - selves. The arguments to the interpreter consist of a sin- - gle optional argument following the interpreter name on the - first line of the program, followed by the name of the pro- - gram, followed by the command arguments, if any. - -ENVIRONMENT - When a program is invoked it is given an array of strings - called the _e_n_v_i_r_o_n_m_e_n_t. This is a list of _n_a_m_e-_v_a_l_u_e pairs, - of the form _n_a_m_e=_v_a_l_u_e. - - The shell allows you to manipulate the environment in - several ways. On invocation, the shell scans its own - environment and creates a parameter for each name found, - automatically marking it for _e_x_p_o_r_t to child processes. - Executed commands inherit the environment. The export and - declare -x commands allow parameters and functions to be - added to and deleted from the environment. If the value of - a parameter in the environment is modified, the new value - becomes part of the environment, replacing the old. The - environment inherited by any executed command consists of - the shell's initial environment, whose values may be modi- - fied in the shell, less any pairs removed by the unset com- - mand, plus any additions via the export and declare -x com- - mands. - - The environment for any _s_i_m_p_l_e _c_o_m_m_a_n_d or function may be - augmented temporarily by prefixing it with parameter assign- - ments, as described above in PARAMETERS. These assignment - statements affect only the environment seen by that command. - - If the -k flag is set (see the set builtin command below), - then _a_l_l parameter assignments are placed in the environment - for a command, not just those that precede the command name. - - When bash invokes an external command, the variable _ is set - to the full path name of the command and passed to that com- - mand in its environment. - -EXIT STATUS - For the purposes of the shell, a command which exits with a - zero exit status has succeeded. An exit status of zero - indicates success. A non-zero exit status indicates - failure. When a command terminates on a fatal signal, bash - uses the value of 128+signal as the exit status. - - If a command is not found, the child process created to exe- - cute it returns a status of 127. If a command is found but - is not executable, the return status is 126. - - - -GNU Last change: 1995 May 5 26 - - - - - - -BASH(1) USER COMMANDS BASH(1) - - - - Bash itself returns the exit status of the last command exe- - cuted, unless a syntax error occurs, in which case it exits - with a non-zero value. See also the exit builtin command - below. - -PROMPTING - When executing interactively, bash displays the primary - prompt PS1 when it is ready to read a command, and the - secondary prompt PS2 when it needs more input to complete a - command. Bash allows these prompt strings to be customized - by inserting a number of backslash-escaped special charac- - ters that are decoded as follows: - \t the current time in HH:MM:SS format - \d the date in "Weekday Month Date" format (e.g., - "Tue May 26") - \n newline - \s the name of the shell, the basename of $0 (the - portion following the final slash) - \w the current working directory - \W the basename of the current working directory - \u the username of the current user - \h the hostname - \# the command number of this command - \! the history number of this command - \$ if the effective UID is 0, a #, otherwise a $ - \nnn the character corresponding to the octal number - nnn - \\ a backslash - \[ begin a sequence of non-printing characters, which - could be used to embed a terminal control sequence - into the prompt - \] end a sequence of non-printing characters - - The command number and the history number are usually dif- - ferent: the history number of a command is its position in - the history list, which may include commands restored from - the history file (see HISTORY below), while the command - number is the position in the sequence of commands executed - during the current shell session. After the string is - decoded, it is expanded via parameter expansion, command - substitution, arithmetic expansion, and word splitting. - -READLINE - This is the library that handles reading input when using an - interactive shell, unless the -nolineediting option is - given. By default, the line editing commands are similar to - those of emacs. A vi-style line editing interface is also - available. - - In this section, the emacs-style notation is used to denote - keystrokes. Control keys are denoted by C-_k_e_y, e.g., C-n - means Control-N. Similarly, _m_e_t_a keys are denoted by M-_k_e_y, - - - -GNU Last change: 1995 May 5 27 - - - - - - -BASH(1) USER COMMANDS BASH(1) - - - - so M-x means Meta-X. (On keyboards without a _m_e_t_a key, M-_x - means ESC _x, i.e., press the Escape key then the _x key. - This makes ESC the _m_e_t_a _p_r_e_f_i_x. The combination M-C-_x means - ESC-Control-_x, or press the Escape key then hold the Control - key while pressing the _x key.) - - The default key-bindings may be changed with an ~/._i_n_p_u_t_r_c - file. The value of the shell variable INPUTRC, if set, is - used instead of ~/._i_n_p_u_t_r_c. Other programs that use this - library may add their own commands and bindings. - - For example, placing - - M-Control-u: universal-argument - or - C-Meta-u: universal-argument - into the ~/._i_n_p_u_t_r_c would make M-C-u execute the readline - command _u_n_i_v_e_r_s_a_l-_a_r_g_u_m_e_n_t. - - The following symbolic character names are recognized: - _R_U_B_O_U_T, _D_E_L, _E_S_C, _L_F_D, _N_E_W_L_I_N_E, _R_E_T, _R_E_T_U_R_N, _S_P_C, _S_P_A_C_E, and - _T_A_B. In addition to command names, readline allows keys to - be bound to a string that is inserted when the key is - pressed (a _m_a_c_r_o). - - Readline is customized by putting commands in an initializa- - tion file. The name of this file is taken from the value of - the INPUTRC variable. If that variable is unset, the - default is ~/._i_n_p_u_t_r_c. When a program which uses the read- - line library starts up, the init file is read, and the key - bindings and variables are set. There are only a few basic - constructs allowed in the readline init file. Blank lines - are ignored. Lines beginning with a # are comments. Lines - beginning with a $ indicate conditional constructs. Other - lines denote key bindings and variable settings. - - The syntax for controlling key bindings in the ~/._i_n_p_u_t_r_c - file is simple. All that is required is the name of the - command or the text of a macro and a key sequence to which - it should be bound. The name may be specified in one of two - ways: as a symbolic key name, possibly with _M_e_t_a- or - _C_o_n_t_r_o_l- prefixes, or as a key sequence. When using the - form keyname:_f_u_n_c_t_i_o_n-_n_a_m_e or _m_a_c_r_o, _k_e_y_n_a_m_e is the name of - a key spelled out in English. For example: - - Control-u: universal-argument - Meta-Rubout: backward-kill-word - Control-o: ">&output" - - In the above example, _C-_u is bound to the function - universal-argument, _M-_D_E_L is bound to the function - backward-kill-word, and _C-_o is bound to run the macro - - - -GNU Last change: 1995 May 5 28 - - - - - - -BASH(1) USER COMMANDS BASH(1) - - - - expressed on the right hand side (that is, to insert the - text >&_o_u_t_p_u_t into the line). - - In the second form, "keyseq":_f_u_n_c_t_i_o_n-_n_a_m_e or _m_a_c_r_o, keyseq - differs from keyname above in that strings denoting an - entire key sequence may be specified by placing the sequence - within double quotes. Some GNU Emacs style key escapes can - be used, as in the following example. - - "\C-u": universal-argument - "\C-x\C-r": re-read-init-file - "\e[11~": "Function Key 1" - - In this example, _C-_u is again bound to the function - universal-argument. _C-_x _C-_r is bound to the function - re-read-init-file, and _E_S_C [ _1 _1 ~ is bound to insert the - text Function Key 1. The full set of escape sequences is - - \C- control prefix - - \M- meta prefix - - \e an escape character - - \\ backslash - - " \" literal " - - \' literal ' - - When entering the text of a macro, single or double quotes - should be used to indicate a macro definition. Unquoted - text is assumed to be a function name. Backslash will quote - any character in the macro text, including " and '. - - Bash allows the current readline key bindings to be - displayed or modified with the bind builtin command. The - editing mode may be switched during interactive use by using - the -o option to the set builtin command (see SHELL BUILTIN - COMMANDS below). - - Readline has variables that can be used to further customize - its behavior. A variable may be set in the _i_n_p_u_t_r_c file - with a statement of the form - - set _v_a_r_i_a_b_l_e-_n_a_m_e _v_a_l_u_e - - Except where noted, readline variables can take the values - On or Off. The variables and their default values are: - - horizontal-scroll-mode (Off) - When set to On, makes readline use a single line for - - - -GNU Last change: 1995 May 5 29 - - - - - - -BASH(1) USER COMMANDS BASH(1) - - - - display, scrolling the input horizontally on a single - screen line when it becomes longer than the screen - width rather than wrapping to a new line. - editing-mode (emacs) - Controls whether readline begins with a set of key - bindings similar to _e_m_a_c_s or _v_i. editing-mode can be - set to either emacs or vi. - mark-modified-lines (Off) - If set to On, history lines that have been modified are - displayed with a preceding asterisk (*). - bell-style (audible) - Controls what happens when readline wants to ring the - terminal bell. If set to none, readline never rings - the bell. If set to visible, readline uses a visible - bell if one is available. If set to audible, readline - attempts to ring the terminal's bell. - comment-begin (``#'') - The string that is inserted in vi mode when the - vi-comment command is executed. - meta-flag (Off) - If set to On, readline will enable eight-bit input - (that is, it will not strip the high bit from the char- - acters it reads), regardless of what the terminal - claims it can support. - convert-meta (On) - If set to On, readline will convert characters with the - eighth bit set to an ASCII key sequence by stripping - the eighth bit and prepending an escape character (in - effect, using escape as the _m_e_t_a _p_r_e_f_i_x). - output-meta (Off) - If set to On, readline will display characters with the - eighth bit set directly rather than as a meta-prefixed - escape sequence. - completion-query-items (100) - This determines when the user is queried about viewing - the number of possible completions generated by the - possible-completions command. It may be set to any - integer value greater than or equal to zero. If the - number of possible completions is greater than or equal - to the value of this variable, the user is asked - whether or not he wishes to view them; otherwise they - are simply listed on the terminal. - keymap (emacs) - Set the current readline keymap. The set of legal key- - map names is _e_m_a_c_s, _e_m_a_c_s-_s_t_a_n_d_a_r_d, _e_m_a_c_s-_m_e_t_a, _e_m_a_c_s- - _c_t_l_x, _v_i, _v_i-_m_o_v_e, _v_i-_c_o_m_m_a_n_d, and _v_i-_i_n_s_e_r_t. _v_i is - equivalent to _v_i-_c_o_m_m_a_n_d; _e_m_a_c_s is equivalent to - _e_m_a_c_s-_s_t_a_n_d_a_r_d. The default value is _e_m_a_c_s; the value - of editing-mode also affects the default keymap. - show-all-if-ambiguous (Off) - This alters the default behavior of the completion - functions. If set to on, words which have more than - - - -GNU Last change: 1995 May 5 30 - - - - - - -BASH(1) USER COMMANDS BASH(1) - - - - one possible completion cause the matches to be listed - immediately instead of ringing the bell. - expand-tilde (Off) - If set to on, tilde expansion is performed when read- - line attempts word completion. - - Readline implements a facility similar in spirit to the con- - ditional compilation features of the C preprocessor which - allows key bindings and variable settings to be performed as - the result of tests. There are three parser directives - used. - - $if The $if construct allows bindings to be made based on - the editing mode, the terminal being used, or the - application using readline. The text of the test - extends to the end of the line; no characters are - required to isolate it. - - mode The mode= form of the $if directive is used to - test whether readline is in emacs or vi mode. - This may be used in conjunction with the set key- - map command, for instance, to set bindings in the - _e_m_a_c_s-_s_t_a_n_d_a_r_d and _e_m_a_c_s-_c_t_l_x keymaps only if - readline is starting out in emacs mode. - - term The term= form may be used to include terminal- - specific key bindings, perhaps to bind the key - sequences output by the terminal's function keys. - The word on the right side of the = is tested - against the full name of the terminal and the por- - tion of the terminal name before the first -. - This allows _s_u_n to match both _s_u_n and _s_u_n-_c_m_d, for - instance. - - application - The application construct is used to include - application-specific settings. Each program using - the readline library sets the _a_p_p_l_i_c_a_t_i_o_n _n_a_m_e, - and an initialization file can test for a particu- - lar value. This could be used to bind key - sequences to functions useful for a specific pro- - gram. For instance, the following command adds a - key sequence that quotes the current or previous - word in Bash: - $if Bash - # Quote the current or previous word - "\C-xq": "\eb\"\ef\"" - $endif - - $endif - This command, as you saw in the previous example, ter- - minates an $if command. - - - -GNU Last change: 1995 May 5 31 - - - - - - -BASH(1) USER COMMANDS BASH(1) - - - - $else - Commands in this branch of the $if directive are exe- - cuted if the test fails. - - Readline commands may be given numeric _a_r_g_u_m_e_n_t_s, which nor- - mally act as a repeat count. Sometimes, however, it is the - sign of the argument that is significant. Passing a nega- - tive argument to a command that acts in the forward direc- - tion (e.g., kill-line) causes that command to act in a back- - ward direction. Commands whose behavior with arguments - deviates from this are noted. - - When a command is described as _k_i_l_l_i_n_g text, the text - deleted is saved for possible future retrieval (_y_a_n_k_i_n_g). - The killed text is saved in a _k_i_l_l-_r_i_n_g. Consecutive kills - cause the text to be accumulated into one unit, which can be - yanked all at once. Commands which do not kill text separate - the chunks of text on the kill-ring. - - The following is a list of the names of the commands and the - default key sequences to which they are bound. - - Commands for Moving - beginning-of-line (C-a) - Move to the start of the current line. - end-of-line (C-e) - Move to the end of the line. - forward-char (C-f) - Move forward a character. - backward-char (C-b) - Move back a character. - forward-word (M-f) - Move forward to the end of the next word. Words are - composed of alphanumeric characters (letters and - digits). - backward-word (M-b) - Move back to the start of this, or the previous, word. - Words are composed of alphanumeric characters (letters - and digits). - clear-screen (C-l) - Clear the screen leaving the current line at the top of - the screen. With an argument, refresh the current line - without clearing the screen. - redraw-current-line - Refresh the current line. By default, this is unbound. - - Commands for Manipulating the History - accept-line (Newline, Return) - Accept the line regardless of where the cursor is. If - this line is non-empty, add it to the history list - according to the state of the HISTCONTROL variable. If - the line is a modified history line, then restore the - - - -GNU Last change: 1995 May 5 32 - - - - - - -BASH(1) USER COMMANDS BASH(1) - - - - history line to its original state. - previous-history (C-p) - Fetch the previous command from the history list, mov- - ing back in the list. - next-history (C-n) - Fetch the next command from the history list, moving - forward in the list. - beginning-of-history (M-<) - Move to the first line in the history. - end-of-history (M->) - Move to the end of the input history, i.e., the line - currently being entered. - reverse-search-history (C-r) - Search backward starting at the current line and moving - `up' through the history as necessary. This is an - incremental search. - forward-search-history (C-s) - Search forward starting at the current line and moving - `down' through the history as necessary. This is an - incremental search. - non-incremental-reverse-search-history (M-p) - Search backward through the history starting at the - current line using a non-incremental search for a - string supplied by the user. - non-incremental-forward-search-history (M-n) - Search forward through the history using a - non-incremental search for a string supplied by the - user. - history-search-forward - Search forward through the history for the string of - characters between the start of the current line and - the current point. This is a non-incremental search. - By default, this command is unbound. - history-search-backward - Search backward through the history for the string of - characters between the start of the current line and - the current point. This is a non-incremental search. - By default, this command is unbound. - yank-nth-arg (M-C-y) - Insert the first argument to the previous command (usu- - ally the second word on the previous line) at point - (the current cursor position). With an argument _n, - insert the _nth word from the previous command (the - words in the previous command begin with word 0). A - negative argument inserts the _nth word from the end of - the previous command. - yank-last-arg (M-., M-_) - Insert the last argument to the previous command (the - last word on the previous line). With an argument, - behave exactly like yank-nth-arg. - shell-expand-line (M-C-e) - Expand the line the way the shell does when it reads - - - -GNU Last change: 1995 May 5 33 - - - - - - -BASH(1) USER COMMANDS BASH(1) - - - - it. This performs alias and history expansion as well - as all of the shell word expansions. See HISTORY - EXPANSION below for a description of history expansion. - history-expand-line (M-^) - Perform history expansion on the current line. See - HISTORY EXPANSION below for a description of history - expansion. - insert-last-argument (M-., M-_) - A synonym for yank-last-arg. - operate-and-get-next (C-o) - Accept the current line for execution and fetch the - next line relative to the current line from the history - for editing. Any argument is ignored. - - Commands for Changing Text - delete-char (C-d) - Delete the character under the cursor. If point is at - the beginning of the line, there are no characters in - the line, and the last character typed was not C-d, - then return EOF. - backward-delete-char (Rubout) - Delete the character behind the cursor. When given a - numeric argument, save the deleted text on the - kill-ring. - quoted-insert (C-q, C-v) - Add the next character that you type to the line verba- - tim. This is how to insert characters like C-q, for - example. - tab-insert (C-v TAB) - Insert a tab character. - self-insert (a, b, A, 1, !, ...) - Insert the character typed. - transpose-chars (C-t) - Drag the character before point forward over the char- - acter at point. Point moves forward as well. If point - is at the end of the line, then transpose the two char- - acters before point. Negative arguments don't work. - transpose-words (M-t) - Drag the word behind the cursor past the word in front - of the cursor moving the cursor over that word as well. - upcase-word (M-u) - Uppercase the current (or following) word. With a - negative argument, do the previous word, but do not - move point. - downcase-word (M-l) - Lowercase the current (or following) word. With a - negative argument, do the previous word, but do not - move point. - capitalize-word (M-c) - Capitalize the current (or following) word. With a - negative argument, do the previous word, but do not - move point. - - - -GNU Last change: 1995 May 5 34 - - - - - - -BASH(1) USER COMMANDS BASH(1) - - - - Killing and Yanking - kill-line (C-k) - Kill the text from the current cursor position to the - end of the line. - backward-kill-line (C-x C-Rubout) - Kill backward to the beginning of the line. - unix-line-discard (C-u) - Kill backward from point to the beginning of the line. - kill-whole-line - Kill all characters on the current line, no matter - where the cursor is. By default, this is unbound. - kill-word (M-d) - Kill from the cursor to the end of the current word, or - if between words, to the end of the next word. Word - boundaries are the same as those used by forward-word. - backward-kill-word (M-Rubout) - Kill the word behind the cursor. Word boundaries are - the same as those used by backward-word. - unix-word-rubout (C-w) - Kill the word behind the cursor, using white space as a - word boundary. The word boundaries are different from - backward-kill-word. - delete-horizontal-space - Delete all spaces and tabs around point. By default, - this is unbound. - yank (C-y) - Yank the top of the kill ring into the buffer at the - cursor. - yank-pop (M-y) - Rotate the kill-ring, and yank the new top. Only works - following yank or yank-pop. - - Numeric Arguments - digit-argument (M-0, M-1, ..., M--) - Add this digit to the argument already accumulating, or - start a new argument. M-- starts a negative argument. - universal-argument - Each time this is executed, the argument count is mul- - tiplied by four. The argument count is initially one, - so executing this function the first time makes the - argument count four. By default, this is not bound to - a key. - - Completing - complete (TAB) - Attempt to perform completion on the text before point. - Bash attempts completion treating the text as a vari- - able (if the text begins with $), username (if the text - begins with ~), hostname (if the text begins with @), - or command (including aliases and functions) in turn. - If none of these produces a match, filename completion - is attempted. - - - -GNU Last change: 1995 May 5 35 - - - - - - -BASH(1) USER COMMANDS BASH(1) - - - - possible-completions (M-?) - List the possible completions of the text before point. - insert-completions - Insert all completions of the text before point that - would have been generated by possible-completions. By - default, this is not bound to a key. - complete-filename (M-/) - Attempt filename completion on the text before point. - possible-filename-completions (C-x /) - List the possible completions of the text before point, - treating it as a filename. - complete-username (M-~) - Attempt completion on the text before point, treating - it as a username. - possible-username-completions (C-x ~) - List the possible completions of the text before point, - treating it as a username. - complete-variable (M-$) - Attempt completion on the text before point, treating - it as a shell variable. - possible-variable-completions (C-x $) - List the possible completions of the text before point, - treating it as a shell variable. - complete-hostname (M-@) - Attempt completion on the text before point, treating - it as a hostname. - possible-hostname-completions (C-x @) - List the possible completions of the text before point, - treating it as a hostname. - complete-command (M-!) - Attempt completion on the text before point, treating - it as a command name. Command completion attempts to - match the text against aliases, reserved words, shell - functions, builtins, and finally executable filenames, - in that order. - possible-command-completions (C-x !) - List the possible completions of the text before point, - treating it as a command name. - dynamic-complete-history (M-TAB) - Attempt completion on the text before point, comparing - the text against lines from the history list for possi- - ble completion matches. - complete-into-braces (M-{) - Perform filename completion and return the list of pos- - sible completions enclosed within braces so the list is - available to the shell (see Brace Expansion above). - - Keyboard Macros - start-kbd-macro (C-x () - Begin saving the characters typed into the current key- - board macro. - end-kbd-macro (C-x )) - - - -GNU Last change: 1995 May 5 36 - - - - - - -BASH(1) USER COMMANDS BASH(1) - - - - Stop saving the characters typed into the current key- - board macro and save the definition. - call-last-kbd-macro (C-x e) - Re-execute the last keyboard macro defined, by making - the characters in the macro appear as if typed at the - keyboard. - - Miscellaneous - re-read-init-file (C-x C-r) - Read in the contents of your init file, and incorporate - any bindings or variable assignments found there. - abort (C-g) - Abort the current editing command and ring the - terminal's bell (subject to the setting of bell-style). - do-uppercase-version (M-a, M-b, ...) - Run the command that is bound to the corresponding - uppercase character. - prefix-meta (ESC) - Metafy the next character typed. ESC f is equivalent - to Meta-f. - undo (C-_, C-x C-u) - Incremental undo, separately remembered for each line. - revert-line (M-r) - Undo all changes made to this line. This is like typ- - ing the undo command enough times to return the line to - its initial state. - tilde-expand (M-~) - Perform tilde expansion on the current word. - dump-functions - Print all of the functions and their key bindings to - the readline output stream. If a numeric argument is - supplied, the output is formatted in such a way that it - can be made part of an _i_n_p_u_t_r_c file. - display-shell-version (C-x C-v) - Display version information about the current instance - of bash. - -HISTORY - When interactive, the shell provides access to the _c_o_m_m_a_n_d - _h_i_s_t_o_r_y, the list of commands previously typed. The text of - the last HISTSIZE commands (default 500) is saved in a his- - tory list. The shell stores each command in the history - list prior to parameter and variable expansion (see EXPAN- - SION above) but after history expansion is performed, sub- - ject to the values of the shell variables - command_oriented_history and HISTCONTROL. On startup, the - history is initialized from the file named by the variable - HISTFILE (default ~/._b_a_s_h__h_i_s_t_o_r_y). HISTFILE is truncated, - if necessary, to contain no more than HISTFILESIZE lines. - The builtin command fc (see SHELL BUILTIN COMMANDS below) - may be used to list or edit and re-execute a portion of the - history list. The history builtin can be used to display - - - -GNU Last change: 1995 May 5 37 - - - - - - -BASH(1) USER COMMANDS BASH(1) - - - - the history list and manipulate the history file. When - using the command-line editing, search commands are avail- - able in each editing mode that provide access to the history - list. When an interactive shell exits, the last HISTSIZE - lines are copied from the history list to HISTFILE. If - HISTFILE is unset, or if the history file is unwritable, the - history is not saved. - -HISTORY EXPANSION - The shell supports a history expansion feature that is simi- - lar to the history expansion in csh. This section describes - what syntax features are available. This feature is enabled - by default for interactive shells, and can be disabled using - the +H option to the set builtin command (see SHELL BUILTIN - COMMANDS below). Non-interactive shells do not perform his- - tory expansion. - - History expansion is performed immediately after a complete - line is read, before the shell breaks it into words. It - takes place in two parts. The first is to determine which - line from the previous history to use during substitution. - The second is to select portions of that line for inclusion - into the current one. The line selected from the previous - history is the _e_v_e_n_t, and the portions of that line that are - acted upon are _w_o_r_d_s. The line is broken into words in the - same fashion as when reading input, so that several - _m_e_t_a_c_h_a_r_a_c_t_e_r-separated words surrounded by quotes are con- - sidered as one word. Only backslash (\) and single quotes - can quote the history escape character, which is ! by - default. - - The shell allows control of the various characters used by - the history expansion mechanism (see the description of - histchars above under Shell Variables). - - Event Designators - An event designator is a reference to a command line entry - in the history list. - - ! Start a history substitution, except when followed by a - blank, newline, = or (. - !! Refer to the previous command. This is a synonym for - `!-1'. - !_n Refer to command line _n. - !-_n Refer to the current command line minus _n. - !_s_t_r_i_n_g - Refer to the most recent command starting with _s_t_r_i_n_g. - !?_s_t_r_i_n_g[?] - Refer to the most recent command containing _s_t_r_i_n_g. -9 ^8_s_t_r_i_n_g_19^8_s_t_r_i_n_g_29^ -8 Quick substitution. Repeat the last command, replacing - _s_t_r_i_n_g_1 with _s_t_r_i_n_g_2. Equivalent to - - - -GNU Last change: 1995 May 5 38 - - - - - - -BASH(1) USER COMMANDS BASH(1) - - - - ``!!:s/_s_t_r_i_n_g_1/_s_t_r_i_n_g_2/'' (see Modifiers below). - !# The entire command line typed so far. - - Word Designators - A : separates the event specification from the word designa- - tor. It can be omitted if the word designator begins with a - ^, $, *, or %. Words are numbered from the beginning of the - line, with the first word being denoted by a 0 (zero). - - 0 (zero) - The zeroth word. For the shell, this is the command - word. - _n The _nth word. - ^ The first argument. That is, word 1. - $ The last argument. - % The word matched by the most recent `?_s_t_r_i_n_g?' search. - _x-_y A range of words; `-_y' abbreviates `0-_y'. - * All of the words but the zeroth. This is a synonym for - `_1-$'. It is not an error to use * if there is just - one word in the event; the empty string is returned in - that case. - x* Abbreviates _x-$. - x- Abbreviates _x-$ like x*, but omits the last word. - - Modifiers - After the optional word designator, you can add a sequence - of one or more of the following modifiers, each preceded by - a `:'. - - h Remove a trailing pathname component, leaving only the - head. - r Remove a trailing suffix of the form ._x_x_x, leaving the - basename. - e Remove all but the trailing suffix. - t Remove all leading pathname components, leaving the - tail. - p Print the new command but do not execute it. - q Quote the substituted words, escaping further substitu- - tions. - x Quote the substituted words as with q, but break into - words at blanks and newlines. - s/_o_l_d/_n_e_w/ - Substitute _n_e_w for the first occurrence of _o_l_d in the - event line. Any delimiter can be used in place of /. - The final delimiter is optional if it is the last char- - acter of the event line. The delimiter may be quoted - in _o_l_d and _n_e_w with a single backslash. If & appears - in _n_e_w, it is replaced by _o_l_d. A single backslash will - quote the &. - & Repeat the previous substitution. - g Cause changes to be applied over the entire event line. - This is used in conjunction with `:s' (e.g., - - - -GNU Last change: 1995 May 5 39 - - - - - - -BASH(1) USER COMMANDS BASH(1) - - - - `:gs/_o_l_d/_n_e_w/') or `:&'. If used with `:s', any delim- - iter can be used in place of /, and the final delimiter - is optional if it is the last character of the event - line. - -ARITHMETIC EVALUATION - The shell allows arithmetic expressions to be evaluated, - under certain circumstances (see the let builtin command and - Arithmetic Expansion). Evaluation is done in long integers - with no check for overflow, though division by 0 is trapped - and flagged as an error. The following list of operators is - grouped into levels of equal-precedence operators. The lev- - els are listed in order of decreasing precedence. - - - + unary minus and plus - ! ~ logical and bitwise negation - * / % - multiplication, division, remainder - + - addition, subtraction - << >> - left and right bitwise shifts - <= >= < > - comparison - == != - equality and inequality - & bitwise AND - ^ bitwise exclusive OR - | bitwise OR - && logical AND - || logical OR - = *= /= %= += -= - assignment - - Shell variables are allowed as operands; parameter expansion - is performed before the expression is evaluated. The value - of a parameter is coerced to a long integer within an - expression. A shell variable need not have its integer - attribute turned on to be used in an expression. - - Constants with a leading 0 are interpreted as octal numbers. - A leading _0_x or _0_X denotes hexadecimal. Otherwise, numbers - take the form [_b_a_s_e#]n, where _b_a_s_e is a decimal number - between 2 and 36 representing the arithmetic base, and _n is - a number in that base. If _b_a_s_e is omitted, then base 10 is - used. - - Operators are evaluated in order of precedence. Sub- - expressions in parentheses are evaluated first and may over- - ride the precedence rules above. - -SHELL BUILTIN COMMANDS - : [_a_r_g_u_m_e_n_t_s] - - - -GNU Last change: 1995 May 5 40 - - - - - - -BASH(1) USER COMMANDS BASH(1) - - - - No effect; the command does nothing beyond expanding - _a_r_g_u_m_e_n_t_s and performing any specified redirections. A - zero exit code is returned. - - . _f_i_l_e_n_a_m_e [_a_r_g_u_m_e_n_t_s] - source _f_i_l_e_n_a_m_e [_a_r_g_u_m_e_n_t_s] - Read and execute commands from _f_i_l_e_n_a_m_e in the current - shell environment and return the exit status of the - last command executed from _f_i_l_e_n_a_m_e. If _f_i_l_e_n_a_m_e does - not contain a slash, pathnames in PATH are used to find - the directory containing _f_i_l_e_n_a_m_e. The file searched - for in PATH need not be executable. The current direc- - tory is searched if no file is found in PATH. If any - _a_r_g_u_m_e_n_t_s are supplied, they become the positional - parameters when _f_i_l_e is executed. Otherwise the posi- - tional parameters are unchanged. The return status is - the status of the last command exited within the script - (0 if no commands are executed), and false if _f_i_l_e_n_a_m_e - is not found. - - alias [_n_a_m_e[=_v_a_l_u_e] ...] - Alias with no arguments prints the list of aliases in - the form _n_a_m_e=_v_a_l_u_e on standard output. When arguments - are supplied, an alias is defined for each _n_a_m_e whose - _v_a_l_u_e is given. A trailing space in _v_a_l_u_e causes the - next word to be checked for alias substitution when the - alias is expanded. For each _n_a_m_e in the argument list - for which no _v_a_l_u_e is supplied, the name and value of - the alias is printed. Alias returns true unless a _n_a_m_e - is given for which no alias has been defined. - - bg [_j_o_b_s_p_e_c] - Place _j_o_b_s_p_e_c in the background, as if it had been - started with &. If _j_o_b_s_p_e_c is not present, the shell's - notion of the _c_u_r_r_e_n_t _j_o_b is used. bg _j_o_b_s_p_e_c returns - 0 unless run when job control is disabled or, when run - with job control enabled, if _j_o_b_s_p_e_c was not found or - started without job control. - - bind [-m _k_e_y_m_a_p] [-lvd] [-q _n_a_m_e] - bind [-m _k_e_y_m_a_p] -f _f_i_l_e_n_a_m_e - bind [-m _k_e_y_m_a_p] _k_e_y_s_e_q:_f_u_n_c_t_i_o_n-_n_a_m_e - Display current readline key and function bindings, or - bind a key sequence to a readline function or macro. - The binding syntax accepted is identical to that of - ._i_n_p_u_t_r_c, but each binding must be passed as a separate - argument; e.g., '"\C-x\C-r": re-read-init-file'. - Options, if supplied, have the following meanings: - -m _k_e_y_m_a_p - Use _k_e_y_m_a_p as the keymap to be affected by the - subsequent bindings. Acceptable _k_e_y_m_a_p names are - _e_m_a_c_s, _e_m_a_c_s-_s_t_a_n_d_a_r_d, _e_m_a_c_s-_m_e_t_a, _e_m_a_c_s-_c_t_l_x, _v_i, - - - -GNU Last change: 1995 May 5 41 - - - - - - -BASH(1) USER COMMANDS BASH(1) - - - - _v_i-_m_o_v_e, _v_i-_c_o_m_m_a_n_d, and _v_i-_i_n_s_e_r_t. _v_i is - equivalent to _v_i-_c_o_m_m_a_n_d; _e_m_a_c_s is equivalent to - _e_m_a_c_s-_s_t_a_n_d_a_r_d. - -l List the names of all readline functions - -v List current function names and bindings - -d Dump function names and bindings in such a way - that they can be re-read - -f _f_i_l_e_n_a_m_e - Read key bindings from _f_i_l_e_n_a_m_e - -q _f_u_n_c_t_i_o_n - Query about which keys invoke the named _f_u_n_c_t_i_o_n - - The return value is 0 unless an unrecognized option is - given or an error occurred. - - break [_n] - Exit from within a for, while, or until loop. If _n is - specified, break _n levels. _n must be >_ 1. If _n is - greater than the number of enclosing loops, all enclos- - ing loops are exited. The return value is 0 unless the - shell is not executing a loop when break is executed. - - builtin _s_h_e_l_l-_b_u_i_l_t_i_n [_a_r_g_u_m_e_n_t_s] - Execute the specified shell builtin, passing it _a_r_g_u_- - _m_e_n_t_s, and return its exit status. This is useful when - you wish to define a function whose name is the same as - a shell builtin, but need the functionality of the - builtin within the function itself. The cd builtin is - commonly redefined this way. The return status is - false if _s_h_e_l_l-_b_u_i_l_t_i_n is not a shell builtin command. - - cd [_d_i_r] - Change the current directory to _d_i_r. The variable HOME - is the default _d_i_r. The variable CDPATH defines the - search path for the directory containing _d_i_r. Alterna- - tive directory names are separated by a colon (:). A - null directory name in CDPATH is the same as the - current directory, i.e., ``.''. If _d_i_r begins with a - slash (/), then CDPATH is not used. An argument of - - is equivalent to $OLDPWD. The return value is true if - the directory was successfully changed; false other- - wise. - - command [-pVv] _c_o_m_m_a_n_d [_a_r_g ...] - Run _c_o_m_m_a_n_d with _a_r_g_s suppressing the normal shell - function lookup. Only builtin commands or commands - found in the PATH are executed. If the -p option is - given, the search for _c_o_m_m_a_n_d is performed using a - default value for PATH that is guaranteed to find all - of the standard utilities. If either the -V or -v - option is supplied, a description of _c_o_m_m_a_n_d is - printed. The -v option causes a single word indicating - - - -GNU Last change: 1995 May 5 42 - - - - - - -BASH(1) USER COMMANDS BASH(1) - - - - the command or pathname used to invoke _c_o_m_m_a_n_d to be - printed; the -V option produces a more verbose descrip- - tion. An argument of -- disables option checking for - the rest of the arguments. If the -V or -v option is - supplied, the exit status is 0 if _c_o_m_m_a_n_d was found, - and 1 if not. If neither option is supplied and an - error occurred or _c_o_m_m_a_n_d cannot be found, the exit - status is 127. Otherwise, the exit status of the com- - mand builtin is the exit status of _c_o_m_m_a_n_d. - - continue [_n] - Resume the next iteration of the enclosing for, while, - or until loop. If _n is specified, resume at the _nth - enclosing loop. _n must be >_ 1. If _n is greater than - the number of enclosing loops, the last enclosing loop - (the `top-level' loop) is resumed. The return value is - 0 unless the shell is not executing a loop when con- - tinue is executed. - - declare [-frxi] [_n_a_m_e[=_v_a_l_u_e]] - typeset [-frxi] [_n_a_m_e[=_v_a_l_u_e]] - Declare variables and/or give them attributes. If no - _n_a_m_es are given, then display the values of variables - instead. The options can be used to restrict output to - variables with the specified attribute. - -f Use function names only - -r Make _n_a_m_es readonly. These names cannot then be - assigned values by subsequent assignment state- - ments. - -x Mark _n_a_m_es for export to subsequent commands via - the environment. - -i The variable is treated as an integer; arithmetic - evaluation (see ARITHMETIC EVALUATION ) is per- - formed when the variable is assigned a value. - - Using `+' instead of `-' turns off the attribute - instead. When used in a function, makes _n_a_m_es local, - as with the local command. The return value is 0 - unless an illegal option is encountered, an attempt is - made to define a function using "-f foo=bar", one of - the _n_a_m_e_s is not a legal shell variable name, an - attempt is made to turn off readonly status for a - readonly variable, or an attempt is made to display a - non-existant function with -f. - - dirs [-l] [+/-n] - Display the list of currently remembered directories. - Directories are added to the list with the pushd com- - mand; the popd command moves back up through the list. - +n displays the _nth entry counting from the left of - the list shown by dirs when invoked without - options, starting with zero. - - - -GNU Last change: 1995 May 5 43 - - - - - - -BASH(1) USER COMMANDS BASH(1) - - - - -n displays the _nth entry counting from the right of - the list shown by dirs when invoked without - options, starting with zero. - -l produces a longer listing; the default listing - format uses a tilde to denote the home directory. - - The return value is 0 unless an illegal option is sup- - plied or _n indexes beyond the end of the directory - stack. - - echo [-neE] [_a_r_g ...] - Output the _a_r_gs, separated by spaces. The return - status is always 0. If -n is specified, the trailing - newline is suppressed. If the -e option is given, - interpretation of the following backslash-escaped char- - acters is enabled. The -E option disables the - interpretation of these escape characters, even on sys- - tems where they are interpreted by default. - \a alert (bell) - \b backspace - \c suppress trailing newline - \f form feed - \n new line - \r carriage return - \t horizontal tab - \v vertical tab - \\ backslash - \nnn the character whose ASCII code is _n_n_n (octal) - - enable [-n] [-all] [_n_a_m_e ...] - Enable and disable builtin shell commands. This allows - the execution of a disk command which has the same name - as a shell builtin without specifying a full pathname. - If -n is used, each _n_a_m_e is disabled; otherwise, _n_a_m_e_s - are enabled. For example, to use the test binary found - via the PATH instead of the shell builtin version, type - ``enable -n test''. If no arguments are given, a list - of all enabled shell builtins is printed. If only -n - is supplied, a list of all disabled builtins is - printed. If only -all is supplied, the list printed - includes all builtins, with an indication of whether or - not each is enabled. enable accepts -a as a synonym - for -all. The return value is 0 unless a _n_a_m_e is not a - shell builtin. - - eval [_a_r_g ...] - The _a_r_gs are read and concatenated together into a sin- - gle command. This command is then read and executed by - the shell, and its exit status is returned as the value - of the eval command. If there are no _a_r_g_s, or only - null arguments, eval returns true. - - - - -GNU Last change: 1995 May 5 44 - - - - - - -BASH(1) USER COMMANDS BASH(1) - - - - exec [[-] _c_o_m_m_a_n_d [_a_r_g_u_m_e_n_t_s]] - If _c_o_m_m_a_n_d is specified, it replaces the shell. No new - process is created. The _a_r_g_u_m_e_n_t_s become the arguments - to _c_o_m_m_a_n_d. If the first argument is -, the shell - places a dash in the zeroth arg passed to _c_o_m_m_a_n_d. - This is what login does. If the file cannot be exe- - cuted for some reason, a non-interactive shell exits, - unless the shell variable no_exit_on_failed_exec - exists, in which case it returns failure. An interac- - tive shell returns failure if the file cannot be exe- - cuted. If _c_o_m_m_a_n_d is not specified, any redirections - take effect in the current shell, and the return status - is 0. - - exit [_n] - Cause the shell to exit with a status of _n. If _n is - omitted, the exit status is that of the last command - executed. A trap on EXIT is executed before the shell - terminates. - - export [-nf] [_n_a_m_e[=_w_o_r_d]] ... - export -p - The supplied _n_a_m_e_s are marked for automatic export to - the environment of subsequently executed commands. If - the -f option is given, the _n_a_m_e_s refer to functions. - If no _n_a_m_e_s are given, or if the -p option is supplied, - a list of all names that are exported in this shell is - printed. The -n option causes the export property to - be removed from the named variables. An argument of -- - disables option checking for the rest of the arguments. - export returns an exit status of 0 unless an illegal - option is encountered, one of the _n_a_m_e_s is not a legal - shell variable name, or -f is supplied with a _n_a_m_e that - is not a function. - - fc [-e _e_n_a_m_e] [-nlr] [_f_i_r_s_t] [_l_a_s_t] - fc -s [_p_a_t=_r_e_p] [_c_m_d] - Fix Command. In the first form, a range of commands - from _f_i_r_s_t to _l_a_s_t is selected from the history list. - _F_i_r_s_t and _l_a_s_t may be specified as a string (to locate - the last command beginning with that string) or as a - number (an index into the history list, where a nega- - tive number is used as an offset from the current com- - mand number). If _l_a_s_t is not specified it is set to - the current command for listing (so that fc -l -10 - prints the last 10 commands) and to _f_i_r_s_t otherwise. - If _f_i_r_s_t is not specified it is set to the previous - command for editing and -16 for listing. - - The -n flag suppresses the command numbers when list- - ing. The -r flag reverses the order of the commands. - If the -l flag is given, the commands are listed on - - - -GNU Last change: 1995 May 5 45 - - - - - - -BASH(1) USER COMMANDS BASH(1) - - - - standard output. Otherwise, the editor given by _e_n_a_m_e - is invoked on a file containing those commands. If - _e_n_a_m_e is not given, the value of the FCEDIT variable is - used, and the value of EDITOR if FCEDIT is not set. If - neither variable is set, _v_i is used. When editing is - complete, the edited commands are echoed and executed. - - In the second form, _c_o_m_m_a_n_d is re-executed after each - instance of _p_a_t is replaced by _r_e_p. A useful alias to - use with this is ``r=fc -s'', so that typing ``r cc'' - runs the last command beginning with ``cc'' and typing - ``r'' re-executes the last command. - - If the first form is used, the return value is 0 unless - an illegal option is encountered or _f_i_r_s_t or _l_a_s_t - specify history lines out of range. If the -e option - is supplied, the return value is the value of the last - command executed or failure if an error occurs with the - temporary file of commands. If the second form is - used, the return status is that of the command re- - executed, unless _c_m_d does not specify a valid history - line, in which case fc returns failure. - - fg [_j_o_b_s_p_e_c] - Place _j_o_b_s_p_e_c in the foreground, and make it the - current job. If _j_o_b_s_p_e_c is not present, the shell's - notion of the _c_u_r_r_e_n_t _j_o_b is used. The return value is - that of the command placed into the foreground, or - failure if run when job control is disabled or, when - run with job control enabled, if _j_o_b_s_p_e_c does not - specify a valid job or _j_o_b_s_p_e_c specifies a job that was - started without job control. - - getopts _o_p_t_s_t_r_i_n_g _n_a_m_e [_a_r_g_s] - getopts is used by shell procedures to parse positional - parameters. _o_p_t_s_t_r_i_n_g contains the option letters to - be recognized; if a letter is followed by a colon, the - option is expected to have an argument, which should be - separated from it by white space. Each time it is - invoked, getopts places the next option in the shell - variable _n_a_m_e, initializing _n_a_m_e if it does not exist, - and the index of the next argument to be processed into - the variable OPTIND. OPTIND is initialized to 1 each - time the shell or a shell script is invoked. When an - option requires an argument, getopts places that argu- - ment into the variable OPTARG. The shell does not - reset OPTIND automatically; it must be manually reset - between multiple calls to getopts within the same shell - invocation if a new set of parameters is to be used. - - getopts can report errors in two ways. If the first - character of _o_p_t_s_t_r_i_n_g is a colon, _s_i_l_e_n_t error - - - -GNU Last change: 1995 May 5 46 - - - - - - -BASH(1) USER COMMANDS BASH(1) - - - - reporting is used. In normal operation diagnostic mes- - sages are printed when illegal options or missing - option arguments are encountered. If the variable - OPTERR is set to 0, no error message will be displayed, - even if the first character of _o_p_t_s_t_r_i_n_g is not a - colon. - - If an illegal option is seen, getopts places ? into - _n_a_m_e and, if not silent, prints an error message and - unsets OPTARG. If getopts is silent, the option char- - acter found is placed in OPTARG and no diagnostic mes- - sage is printed. - - If a required argument is not found, and getopts is not - silent, a question mark (?) is placed in _n_a_m_e, OPTARG - is unset, and a diagnostic message is printed. If - getopts is silent, then a colon (:) is placed in _n_a_m_e - and OPTARG is set to the option character found. - - getopts normally parses the positional parameters, but - if more arguments are given in _a_r_g_s, getopts parses - those instead. getopts returns true if an option, - specified or unspecified, is found. It returns false - if the end of options is encountered or an error - occurs. - - hash [-r] [_n_a_m_e] - For each _n_a_m_e, the full pathname of the command is - determined and remembered. The -r option causes the - shell to forget all remembered locations. If no argu- - ments are given, information about remembered commands - is printed. An argument of -- disables option checking - for the rest of the arguments. The return status is - true unless a _n_a_m_e is not found or an illegal option is - supplied. - - help [_p_a_t_t_e_r_n] - Display helpful information about builtin commands. If - _p_a_t_t_e_r_n is specified, help gives detailed help on all - commands matching _p_a_t_t_e_r_n; otherwise a list of the - builtins is printed. The return status is 0 unless no - command matches _p_a_t_t_e_r_n. - - history [_n] - history -rwan [_f_i_l_e_n_a_m_e] - With no options, display the command history list with - line numbers. Lines listed with a * have been modi- - fied. An argument of _n lists only the last _n lines. - If a non-option argument is supplied, it is used as the - name of the history file; if not, the value of HISTFILE - is used. Options, if supplied, have the following - meanings: - - - -GNU Last change: 1995 May 5 47 - - - - - - -BASH(1) USER COMMANDS BASH(1) - - - - -a Append the ``new'' history lines (history lines - entered since the beginning of the current bash - session) to the history file - -n Read the history lines not already read from the - history file into the current history list. These - are lines appended to the history file since the - beginning of the current bash session. - -r Read the contents of the history file and use them - as the current history - -w Write the current history to the history file, - overwriting the history file's contents. - - The return value is 0 unless an illegal option is - encountered or an error occurs while reading or writing - the history file. - - jobs [-lnp] [ _j_o_b_s_p_e_c ... ] - jobs -x _c_o_m_m_a_n_d [ _a_r_g_s ... ] - The first form lists the active jobs. The -l option - lists process IDs in addition to the normal informa- - tion; the -p option lists only the process ID of the - job's process group leader. The -n option displays - only jobs that have changed status since last notified. - If _j_o_b_s_p_e_c is given, output is restricted to informa- - tion about that job. The return status is 0 unless an - illegal option is encountered or an illegal _j_o_b_s_p_e_c is - supplied. - - If the -x option is supplied, jobs replaces any _j_o_b_s_p_e_c - found in _c_o_m_m_a_n_d or _a_r_g_s with the corresponding process - group ID, and executes _c_o_m_m_a_n_d passing it _a_r_g_s, return- - ing its exit status. - - kill [-s sigspec | -sigspec] [_p_i_d | _j_o_b_s_p_e_c] ... - kill -l [_s_i_g_n_u_m] - Send the signal named by _s_i_g_s_p_e_c to the processes named - by _p_i_d or _j_o_b_s_p_e_c. _s_i_g_s_p_e_c is either a signal name - such as SIGKILL or a signal number. If _s_i_g_s_p_e_c is a - signal name, the name is case insensitive and may be - given with or without the SIG prefix. If _s_i_g_s_p_e_c is - not present, then SIGTERM is assumed. An argument of - -l lists the signal names. If any arguments are sup- - plied when -l is given, the names of the specified sig- - nals are listed, and the return status is 0. An argu- - ment of -- disables option checking for the rest of the - arguments. kill returns true if at least one signal - was successfully sent, or false if an error occurs or - an illegal option is encountered. - - let _a_r_g [_a_r_g ...] - Each _a_r_g is an arithmetic expression to be evaluated - (see ARITHMETIC EVALUATION). If the last _a_r_g evaluates - - - -GNU Last change: 1995 May 5 48 - - - - - - -BASH(1) USER COMMANDS BASH(1) - - - - to 0, let returns 1; 0 is returned otherwise. - - local [_n_a_m_e[=_v_a_l_u_e] ...] - For each argument, create a local variable named _n_a_m_e, - and assign it _v_a_l_u_e. When local is used within a func- - tion, it causes the variable _n_a_m_e to have a visible - scope restricted to that function and its children. - With no operands, local writes a list of local vari- - ables to the standard output. It is an error to use - local when not within a function. The return status is - 0 unless local is used outside a function, or an ille- - gal _n_a_m_e is supplied. - - logout - Exit a login shell. - - popd [+/-n] - Removes entries from the directory stack. With no - arguments, removes the top directory from the stack, - and performs a cd to the new top directory. - +n removes the _nth entry counting from the left of - the list shown by dirs, starting with zero. For - example: ``popd +0'' removes the first directory, - ``popd +1'' the second. - -n removes the _nth entry counting from the right of - the list shown by dirs, starting with zero. For - example: ``popd -0'' removes the last directory, - ``popd -1'' the next to last. - - If the popd command is successful, a dirs is performed - as well, and the return status is 0. popd returns - false if an illegal option is encountered, the direc- - tory stack is empty, a non-existent directory stack - entry is specified, or the directory change fails. - - pushd [_d_i_r] - pushd +/-n - Adds a directory to the top of the directory stack, or - rotates the stack, making the new top of the stack the - current working directory. With no arguments, - exchanges the top two directories and returns 0, unless - the directory stack is empty. - +n Rotates the stack so that the _nth directory - (counting from the left of the list shown by dirs) - is at the top. - -n Rotates the stack so that the _nth directory - (counting from the right) is at the top. - dir adds _d_i_r to the directory stack at the top, making - it the new current working directory. - - If the pushd command is successful, a dirs is performed - as well. If the first form is used, pushd returns 0 - - - -GNU Last change: 1995 May 5 49 - - - - - - -BASH(1) USER COMMANDS BASH(1) - - - - unless the cd to _d_i_r fails. With the second form, - pushd returns 0 unless the directory stack is empty, a - non-existant directory stack element is specified, or - the directory change to the specified new current - directory fails. - - pwd Print the absolute pathname of the current working - directory. The path printed contains no symbolic links - if the -P option to the set builtin command is set. - See also the description of nolinks under Shell Vari- - ables above). The return status is 0 unless an error - occurs while reading the pathname of the current direc- - tory. - - read [-r] [_n_a_m_e ...] - One line is read from the standard input, and the first - word is assigned to the first _n_a_m_e, the second word to - the second _n_a_m_e, and so on, with leftover words - assigned to the last _n_a_m_e. Only the characters in IFS - are recognized as word delimiters. If no _n_a_m_e_s are - supplied, the line read is assigned to the variable - REPLY. The return code is zero, unless end-of-file is - encountered. If the -r option is given, a backslash- - newline pair is not ignored, and the backslash is con- - sidered to be part of the line. - - readonly [-f] [_n_a_m_e ...] - readonly -p - The given _n_a_m_e_s are marked readonly and the values of - these _n_a_m_e_s may not be changed by subsequent assign- - ment. If the -f option is supplied, the functions - corresponding to the _n_a_m_e_s are so marked. If no argu- - ments are given, or if the -p option is supplied, a - list of all readonly names is printed. An argument of - -- disables option checking for the rest of the argu- - ments. The return status is 0 unless an illegal option - is encountered, one of the _n_a_m_e_s is not a legal shell - variable name, or -f is supplied with a _n_a_m_e that is - not a function. - - return [_n] - Causes a function to exit with the return value speci- - fied by _n. If _n is omitted, the return status is that - of the last command executed in the function body. If - used outside a function, but during execution of a - script by the . (source) command, it causes the shell - to stop executing that script and return either _n or - the exit status of the last command executed within the - script as the exit status of the script. If used out- - side a function and not during execution of a script by - ., the return status is false. - - - - -GNU Last change: 1995 May 5 50 - - - - - - -BASH(1) USER COMMANDS BASH(1) - - - - set [--abefhkmnptuvxldCHP] [-o _o_p_t_i_o_n] [_a_r_g ...] - -a Automatically mark variables which are modified - or created for export to the environment of - subsequent commands. - -b Cause the status of terminated background jobs - to be reported immediately, rather than before - the next primary prompt. (Also see notify - under Shell Variables above). - -e Exit immediately if a _s_i_m_p_l_e-_c_o_m_m_a_n_d (see SHELL - GRAMMAR above) exits with a non-zero status. - The shell does not exit if the command that - fails is part of an _u_n_t_i_l or _w_h_i_l_e loop, part - of an _i_f statement, part of a && or || list, or - if the command's return value is being inverted - via !. - -f Disable pathname expansion. - -h Locate and remember function commands as func- - tions are defined. Function commands are nor- - mally looked up when the function is executed. - -k All keyword arguments are placed in the - environment for a command, not just those that - precede the command name. - -m Monitor mode. Job control is enabled. This - flag is on by default for interactive shells on - systems that support it (see JOB CONTROL - above). Background processes run in a separate - process group and a line containing their exit - status is printed upon their completion. - -n Read commands but do not execute them. This - may be used to check a shell script for syntax - errors. This is ignored for interactive - shells. - -o _o_p_t_i_o_n-_n_a_m_e - The _o_p_t_i_o_n-_n_a_m_e can be one of the following: - allexport - Same as -a. - braceexpand - The shell performs brace expansion (see - Brace Expansion above). This is on by - default. - emacs Use an emacs-style command line editing - interface. This is enabled by default - when the shell is interactive, unless - the shell is started with the -nol- - ineediting option. - errexit Same as -e. - histexpand - Same as -H. - ignoreeof - The effect is as if the shell command - `IGNOREEOF=10' had been executed (see - Shell Variables above). - - - -GNU Last change: 1995 May 5 51 - - - - - - -BASH(1) USER COMMANDS BASH(1) - - - - interactive-comments - Allow a word beginning with # to cause - that word and all remaining characters - on that line to be ignored in an - interactive shell (see COMMENTS above). - monitor Same as -m. - noclobber - Same as -C. - noexec Same as -n. - noglob Same as -f. - nohash Same as -d. - notify Same as -b. - nounset Same as -u. - physical - Same as -P. - posix Change the behavior of bash where the - default operation differs from the - Posix 1003.2 standard to match the - standard. - privileged - Same as -p. - verbose Same as -v. - vi Use a vi-style command line editing - interface. - xtrace Same as -x. - If no _o_p_t_i_o_n-_n_a_m_e is supplied, the values of - the current options are printed. - -p Turn on _p_r_i_v_i_l_e_g_e_d mode. In this mode, the - $ENV file is not processed, and shell functions - are not inherited from the environment. This - is enabled automatically on startup if the - effective user (group) id is not equal to the - real user (group) id. Turning this option off - causes the effective user and group ids to be - set to the real user and group ids. - -t Exit after reading and executing one command. - -u Treat unset variables as an error when perform- - ing parameter expansion. If expansion is - attempted on an unset variable, the shell - prints an error message, and, if not interac- - tive, exits with a non-zero status. - -v Print shell input lines as they are read. - -x After expanding each _s_i_m_p_l_e-_c_o_m_m_a_n_d, bash - displays the expanded value of PS4, followed by - the command and its expanded arguments. - -l Save and restore the binding of _n_a_m_e in a for - _n_a_m_e [in word] command (see SHELL GRAMMAR - above). - -d Disable the hashing of commands that are looked - up for execution. Normally, commands are - remembered in a hash table, and once found, do - not have to be looked up again. - - - -GNU Last change: 1995 May 5 52 - - - - - - -BASH(1) USER COMMANDS BASH(1) - - - - -C The effect is as if the shell command - `noclobber=' had been executed (see Shell Vari- - ables above). - -H Enable ! style history substitution. This flag - is on by default when the shell is interactive. - -P If set, do not follow symbolic links when per- - forming commands such as cd which change the - current directory. The physical directory is - used instead. - -- If no arguments follow this flag, then the - positional parameters are unset. Otherwise, - the positional parameters are set to the _a_r_gs, - even if some of them begin with a -. - - Signal the end of options, cause all remaining - _a_r_gs to be assigned to the positional parame- - ters. The -x and -v options are turned off. - If there are no _a_r_gs, the positional parameters - remain unchanged. - - The flags are off by default unless otherwise noted. - Using + rather than - causes these flags to be turned - off. The flags can also be specified as options to an - invocation of the shell. The current set of flags may - be found in $-. After the option arguments are pro- - cessed, the remaining _n _a_r_gs are treated as values for - the positional parameters and are assigned, in order, - to $1, $2, ... $_n. If no options or _a_r_gs are supplied, - all shell variables are printed. The return status is - always true unless an illegal option is encountered. - - shift [_n] - The positional parameters from _n+1 ... are renamed to - $1 .... Parameters represented by the numbers $# down - to $#-_n+1 are unset. If _n is 0, no parameters are - changed. If _n is not given, it is assumed to be 1. _n - must be a non-negative number less than or equal to $#. - If _n is greater than $#, the positional parameters are - not changed. The return status is greater than 0 if _n - is greater than $# or less than 0; otherwise 0. - - suspend [-f] - Suspend the execution of this shell until it receives a - SIGCONT signal. The -f option says not to complain if - this is a login shell; just suspend anyway. The return - status is 0 unless the shell is a login shell and -f is - not supplied, or if job control is not enabled. - - test _e_x_p_r - [ _e_x_p_r ] - Return a status of 0 (true) or 1 (false) depending on - the evaluation of the conditional expression _e_x_p_r. - Expressions may be unary or binary. Unary expressions - - - -GNU Last change: 1995 May 5 53 - - - - - - -BASH(1) USER COMMANDS BASH(1) - - - - are often used to examine the status of a file. There - are string operators and numeric comparison operators - as well. Each operator and operand must be a separate - argument. If _f_i_l_e is of the form /dev/fd/_n, then file - descriptor _n is checked. - -b _f_i_l_e - True if _f_i_l_e exists and is block special. - -c _f_i_l_e - True if _f_i_l_e exists and is character special. - -d _f_i_l_e - True if _f_i_l_e exists and is a directory. - -e _f_i_l_e - True if _f_i_l_e exists. - -f _f_i_l_e - True if _f_i_l_e exists and is a regular file. - -g _f_i_l_e - True if _f_i_l_e exists and is set-group-id. - -k _f_i_l_e - True if _f_i_l_e has its ``sticky'' bit set. - -L _f_i_l_e - True if _f_i_l_e exists and is a symbolic link. - -p _f_i_l_e - True if _f_i_l_e exists and is a named pipe. - -r _f_i_l_e - True if _f_i_l_e exists and is readable. - -s _f_i_l_e - True if _f_i_l_e exists and has a size greater than - zero. - -S _f_i_l_e - True if _f_i_l_e exists and is a socket. - -t _f_d - True if _f_d is opened on a terminal. - -u _f_i_l_e - True if _f_i_l_e exists and its set-user-id bit is - set. - -w _f_i_l_e - True if _f_i_l_e exists and is writable. - -x _f_i_l_e - True if _f_i_l_e exists and is executable. - -O _f_i_l_e - True if _f_i_l_e exists and is owned by the effective - user id. - -G _f_i_l_e - True if _f_i_l_e exists and is owned by the effective - group id. - _f_i_l_e_1 -nt _f_i_l_e_2 - True if _f_i_l_e_1 is newer (according to modification - date) than _f_i_l_e_2. - _f_i_l_e_1 -ot _f_i_l_e_2 - True if _f_i_l_e_1 is older than file2. - _f_i_l_e_1 -ef _f_i_l_e - True if _f_i_l_e_1 and _f_i_l_e_2 have the same device and - - - -GNU Last change: 1995 May 5 54 - - - - - - -BASH(1) USER COMMANDS BASH(1) - - - - inode numbers. - -z _s_t_r_i_n_g - True if the length of _s_t_r_i_n_g is zero. - -n _s_t_r_i_n_g - _s_t_r_i_n_g - True if the length of _s_t_r_i_n_g is non-zero. - _s_t_r_i_n_g_1 = _s_t_r_i_n_g_2 - True if the strings are equal. - _s_t_r_i_n_g_1 != _s_t_r_i_n_g_2 - True if the strings are not equal. - ! _e_x_p_r - True if _e_x_p_r is false. - _e_x_p_r_1 -a _e_x_p_r_2 - True if both _e_x_p_r_1 AND _e_x_p_r_2 are true. - _e_x_p_r_1 -o _e_x_p_r_2 - True if either _e_x_p_r_1 OR _e_x_p_r_2 is true. - _a_r_g_1 OP _a_r_g_2 - OP is one of -eq, -ne, -lt, -le, -gt, or -ge. - These arithmetic binary operators return true if - _a_r_g_1 is equal, not-equal, less-than, less-than- - or-equal, greater-than, or greater-than-or-equal - than _a_r_g_2, respectively. _A_r_g_1 and _a_r_g_2 may be - positive integers, negative integers, or the spe- - cial expression -l _s_t_r_i_n_g, which evaluates to the - length of _s_t_r_i_n_g. - - times - Print the accumulated user and system times for the - shell and for processes run from the shell. The return - status is 0. - - trap [-l] [_a_r_g] [_s_i_g_s_p_e_c] - The command _a_r_g is to be read and executed when the - shell receives signal(s) _s_i_g_s_p_e_c. If _a_r_g is absent or - -, all specified signals are reset to their original - values (the values they had upon entrance to the - shell). If _a_r_g is the null string this signal is - ignored by the shell and by the commands it invokes. - _s_i_g_s_p_e_c is either a signal name defined in <_s_i_g_n_a_l._h>, - or a signal number. If _s_i_g_s_p_e_c is EXIT (0) the command - _a_r_g is executed on exit from the shell. With no argu- - ments, trap prints the list of commands associated with - each signal number. The -l option causes the shell to - print a list of signal names and their corresponding - numbers. An argument of -- disables option checking - for the rest of the arguments. Signals ignored upon - entry to the shell cannot be trapped or reset. Trapped - signals are reset to their original values in a child - process when it is created. The return status is false - if either the trap name or number is invalid; otherwise - trap returns true. - - - - -GNU Last change: 1995 May 5 55 - - - - - - -BASH(1) USER COMMANDS BASH(1) - - - - type [-all] [-type | -path] _n_a_m_e [_n_a_m_e ...] - With no options, indicate how each _n_a_m_e would be inter- - preted if used as a command name. If the -type flag is - used, type prints a phrase which is one of _a_l_i_a_s, _k_e_y_- - _w_o_r_d, _f_u_n_c_t_i_o_n, _b_u_i_l_t_i_n, or _f_i_l_e if _n_a_m_e is an alias, - shell reserved word, function, builtin, or disk file, - respectively. If the name is not found, then nothing is - printed, and an exit status of false is returned. If - the -path flag is used, type either returns the name of - the disk file that would be executed if _n_a_m_e were - specified as a command name, or nothing if -type would - not return _f_i_l_e. If a command is hashed, -path prints - the hashed value, not necessarily the file that appears - first in PATH. If the -all flag is used, type prints - all of the places that contain an executable named - _n_a_m_e. This includes aliases and functions, if and only - if the -path flag is not also used. The table of - hashed commands is not consulted when using -all. type - accepts -a, -t, and -p in place of -all, -type, and - -path, respectively. An argument of -- disables option - checking for the rest of the arguments. type returns - true if any of the arguments are found, false if none - are found. - - ulimit [-SHacdfmstpnuv [_l_i_m_i_t]] - Ulimit provides control over the resources available to - the shell and to processes started by it, on systems - that allow such control. The value of _l_i_m_i_t can be a - number in the unit specified for the resource, or the - value unlimited. The H and S options specify that the - hard or soft limit is set for the given resource. A - hard limit cannot be increased once it is set; a soft - limit may be increased up to the value of the hard - limit. If neither H nor S is specified, the command - applies to the soft limit. If _l_i_m_i_t is omitted, the - current value of the soft limit of the resource is - printed, unless the H option is given. When more than - one resource is specified, the limit name and unit is - printed before the value. Other options are inter- - preted as follows: - -a all current limits are reported - -c the maximum size of core files created - -d the maximum size of a process's data segment - -f the maximum size of files created by the shell - -m the maximum resident set size - -s the maximum stack size - -t the maximum amount of cpu time in seconds - -p the pipe size in 512-byte blocks (this may not be - set) - -n the maximum number of open file descriptors (most - systems do not allow this value to be set, only - displayed) - - - -GNU Last change: 1995 May 5 56 - - - - - - -BASH(1) USER COMMANDS BASH(1) - - - - -u the maximum number of processes available to a - single user - -v The maximum amount of virtual memory available to - the shell - - An argument of -- disables option checking for the rest - of the arguments. If _l_i_m_i_t is given, it is the new - value of the specified resource (the -a option is - display only). If no option is given, then -f is - assumed. Values are in 1024-byte increments, except - for -t, which is in seconds, -p, which is in units of - 512-byte blocks, and -n and -u, which are unscaled - values. The return status is 0 unless an illegal - option is encountered, a non-numeric argument other - than unlimited is supplied as _l_i_m_i_t, or an error occurs - while setting a new limit. - - umask [-S] [_m_o_d_e] - The user file-creation mask is set to _m_o_d_e. If _m_o_d_e - begins with a digit, it is interpreted as an octal - number; otherwise it is interpreted as a symbolic mode - mask similar to that accepted by _c_h_m_o_d(1). If _m_o_d_e is - omitted, or if the -S option is supplied, the current - value of the mask is printed. The -S option causes the - mask to be printed in symbolic form; the default output - is an octal number. An argument of -- disables option - checking for the rest of the arguments. The return - status is 0 if the mode was successfully changed or if - no _m_o_d_e argument was supplied, and false otherwise. - - unalias [-a] [_n_a_m_e ...] - Remove _n_a_m_es from the list of defined aliases. If -a - is supplied, all alias definitions are removed. The - return value is true unless a supplied _n_a_m_e is not a - defined alias. - - unset [-fv] [_n_a_m_e ...] - For each _n_a_m_e, remove the corresponding variable or, - given the -f option, function. An argument of -- dis- - ables option checking for the rest of the arguments. - Note that PATH, IFS, PPID, PS1, PS2, UID, and EUID can- - not be unset. If any of RANDOM, SECONDS, LINENO, or - HISTCMD are unset, they lose their special properties, - even if they are subsequently reset. The exit status - is true unless a _n_a_m_e does not exist or is non- - unsettable. - - wait [_n] - Wait for the specified process and return its termina- - tion status. _n may be a process ID or a job specifica- - tion; if a job spec is given, all processes in that - job's pipeline are waited for. If _n is not given, all - - - -GNU Last change: 1995 May 5 57 - - - - - - -BASH(1) USER COMMANDS BASH(1) - - - - currently active child processes are waited for, and - the return status is zero. If _n specifies a non- - existant process or job, the return status is 127. - Otherwise, the return status is the exit status of the - last process or job waited for. - -INVOCATION - A _l_o_g_i_n _s_h_e_l_l is one whose first character of argument zero - is a -, or one started with the -login flag. - - An _i_n_t_e_r_a_c_t_i_v_e shell is one whose standard input and output - are both connected to terminals (as determined by - _i_s_a_t_t_y(3)), or one started with the -i option. PS1 is set - and $- includes i if bash is interactive, allowing a shell - script or a startup file to test this state. - - Login shells: - On login (subject to the -noprofile option): - if /_e_t_c/_p_r_o_f_i_l_e exists, source it. - - if ~/._b_a_s_h__p_r_o_f_i_l_e exists, source it, - else if ~/._b_a_s_h__l_o_g_i_n exists, source it, - else if ~/._p_r_o_f_i_l_e exists, source it. - - On exit: - if ~/._b_a_s_h__l_o_g_o_u_t exists, source it. - - Non-login interactive shells: - On startup (subject to the -norc and -rcfile options): - if ~/._b_a_s_h_r_c exists, source it. - - Non-interactive shells: - On startup: - if the environment variable ENV is non-null, expand - it and source the file it names, as if the command - if [ "$ENV" ]; then . $ENV; fi - had been executed, but do not use PATH to search - for the pathname. When not started in Posix mode, bash - looks for BASH_ENV before ENV. - - If Bash is invoked as sh, it tries to mimic the behavior of - sh as closely as possible. For a login shell, it attempts - to source only /_e_t_c/_p_r_o_f_i_l_e and ~/._p_r_o_f_i_l_e, in that order. - The -noprofile option may still be used to disable this - behavior. A shell invoked as sh does not attempt to source - any other startup files. - - When bash is started in _p_o_s_i_x mode, as with the -posix com- - mand line option, it follows the Posix standard for startup - files. In this mode, the ENV variable is expanded and that - file sourced; no other startup files are read. - - - - -GNU Last change: 1995 May 5 58 - - - - - - -BASH(1) USER COMMANDS BASH(1) - - - -SEE ALSO - _B_a_s_h _F_e_a_t_u_r_e_s, Brian Fox and Chet Ramey - _T_h_e _G_n_u _R_e_a_d_l_i_n_e _L_i_b_r_a_r_y, Brian Fox and Chet Ramey - _T_h_e _G_n_u _H_i_s_t_o_r_y _L_i_b_r_a_r_y, Brian Fox and Chet Ramey -Lennert - _A _S_y_s_t_e_m _V _C_o_m_p_a_t_i_b_l_e _I_m_p_l_e_m_e_n_t_a_t_i_o_n _o_f _4._2_B_S_D _J_o_b _C_o_n_t_r_o_l, David -_U_t_i_l_i_t_i_e_s, IEEE - _P_o_r_t_a_b_l_e _O_p_e_r_a_t_i_n_g _S_y_s_t_e_m _I_n_t_e_r_f_a_c_e (_P_O_S_I_X) _P_a_r_t _2: _S_h_e_l_l _a_n_d - _s_h(1), _k_s_h(1), _c_s_h(1) - _e_m_a_c_s(1), _v_i(1) - _r_e_a_d_l_i_n_e(3) - -FILES - /_b_i_n/_b_a_s_h - The bash executable - /_e_t_c/_p_r_o_f_i_l_e - The systemwide initialization file, executed for login - shells - ~/._b_a_s_h__p_r_o_f_i_l_e - The personal initialization file, executed for login - shells - ~/._b_a_s_h_r_c - The individual per-interactive-shell startup file - ~/._i_n_p_u_t_r_c - Individual _r_e_a_d_l_i_n_e initialization file - -AUTHORS - Brian Fox, Free Software Foundation (primary author) - bfox@ai.MIT.Edu - - Chet Ramey, Case Western Reserve University - chet@ins.CWRU.Edu - -BUG REPORTS - If you find a bug in bash, you should report it. But first, - you should make sure that it really is a bug, and that it - appears in the latest version of bash that you have. - - Once you have determined that a bug actually exists, use the - _b_a_s_h_b_u_g command to submit a bug report. If you have a fix, - you are welcome to mail that as well! Suggestions and `phi- - losophical' bug reports may be mailed to _b_u_g- - _b_a_s_h@_p_r_e_p._a_i._M_I_T._E_d_u or posted to the Usenet newsgroup - gnu.bash.bug. - - ALL bug reports should include: - - The version number of bash - The hardware and operating system - The compiler used to compile - A description of the bug behaviour - A short script or `recipe' which exercises the bug - - - -GNU Last change: 1995 May 5 59 - - - - - - -BASH(1) USER COMMANDS BASH(1) - - - - _b_a_s_h_b_u_g inserts the first three items automatically into the - template it provides for filing a bug report. - - Comments and bug reports concerning this manual page should - be directed to _c_h_e_t@_i_n_s._C_W_R_U._E_d_u. - -BUGS - It's too big and too slow. - - There are some subtle differences between bash and tradi- - tional versions of sh, mostly because of the POSIX specifi- - cation. - - Aliases are confusing in some uses. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -GNU Last change: 1995 May 5 60 - - - diff --git a/documentation/builtins.1 b/documentation/builtins.1 deleted file mode 100644 index 553c107..0000000 --- a/documentation/builtins.1 +++ /dev/null @@ -1,15 +0,0 @@ -.\" This is a hack to force bash builtins into the whatis database -.\" and to get the list of builtins to come up with the man command. -.TH BASH_BUILTINS 1 "1993 September 16" GNU -.SH NAME -bash, :, ., alias, bg, bind, break, builtin, bye, case, cd, command, -continue, declare, dirs, echo, enable, eval, exec, exit, export, fc, -fg, for, getopts, hash, help, history, if, jobs, kill, let, local, -logout, popd, pushd, pwd, read, readonly, return, set, shift, source, -suspend, test, times, trap, type, typeset, ulimit, umask, unalias, -unset, until, wait, while \- bash built-in commands, see \fBbash\fR(1) -.SH BASH BUILTIN COMMANDS -.nr zZ 1 -.so bash.1 -.SH SEE ALSO -bash(1), sh(1) diff --git a/documentation/builtins.ps b/documentation/builtins.ps deleted file mode 100644 index ebac7d1..0000000 --- a/documentation/builtins.ps +++ /dev/null @@ -1,1367 +0,0 @@ -%!PS-Adobe-3.0 -%%Creator: groff version 1.08 -%%DocumentNeededResources: font Times-Roman -%%+ font Times-Bold -%%+ font Times-Italic -%%+ font Symbol -%%DocumentSuppliedResources: procset grops 1.08 0 -%%Pages: 11 -%%PageOrder: Ascend -%%Orientation: Portrait -%%EndComments -%%BeginProlog -%%BeginResource: procset grops 1.08 0 -/setpacking where{ -pop -currentpacking -true setpacking -}if -/grops 120 dict dup begin -/SC 32 def -/A/show load def -/B{0 SC 3 -1 roll widthshow}bind def -/C{0 exch ashow}bind def -/D{0 exch 0 SC 5 2 roll awidthshow}bind def -/E{0 rmoveto show}bind def -/F{0 rmoveto 0 SC 3 -1 roll widthshow}bind def -/G{0 rmoveto 0 exch ashow}bind def -/H{0 rmoveto 0 exch 0 SC 5 2 roll awidthshow}bind def -/I{0 exch rmoveto show}bind def -/J{0 exch rmoveto 0 SC 3 -1 roll widthshow}bind def -/K{0 exch rmoveto 0 exch ashow}bind def -/L{0 exch rmoveto 0 exch 0 SC 5 2 roll awidthshow}bind def -/M{rmoveto show}bind def -/N{rmoveto 0 SC 3 -1 roll widthshow}bind def -/O{rmoveto 0 exch ashow}bind def -/P{rmoveto 0 exch 0 SC 5 2 roll awidthshow}bind def -/Q{moveto show}bind def -/R{moveto 0 SC 3 -1 roll widthshow}bind def -/S{moveto 0 exch ashow}bind def -/T{moveto 0 exch 0 SC 5 2 roll awidthshow}bind def -/SF{ -findfont exch -[exch dup 0 exch 0 exch neg 0 0]makefont -dup setfont -[exch/setfont cvx]cvx bind def -}bind def -/MF{ -findfont -[5 2 roll -0 3 1 roll -neg 0 0]makefont -dup setfont -[exch/setfont cvx]cvx bind def -}bind def -/level0 0 def -/RES 0 def -/PL 0 def -/LS 0 def -/PLG{ -gsave newpath clippath pathbbox grestore -exch pop add exch pop -}bind def -/BP{ -/level0 save def -1 setlinecap -1 setlinejoin -72 RES div dup scale -LS{ -90 rotate -}{ -0 PL translate -}ifelse -1 -1 scale -}bind def -/EP{ -level0 restore -showpage -}bind def -/DA{ -newpath arcn stroke -}bind def -/SN{ -transform -.25 sub exch .25 sub exch -round .25 add exch round .25 add exch -itransform -}bind def -/DL{ -SN -moveto -SN -lineto stroke -}bind def -/DC{ -newpath 0 360 arc closepath -}bind def -/TM matrix def -/DE{ -TM currentmatrix pop -translate scale newpath 0 0 .5 0 360 arc closepath -TM setmatrix -}bind def -/RC/rcurveto load def -/RL/rlineto load def -/ST/stroke load def -/MT/moveto load def -/CL/closepath load def -/FL{ -currentgray exch setgray fill setgray -}bind def -/BL/fill load def -/LW/setlinewidth load def -/RE{ -findfont -dup maxlength 1 index/FontName known not{1 add}if dict begin -{ -1 index/FID ne{def}{pop pop}ifelse -}forall -/Encoding exch def -dup/FontName exch def -currentdict end definefont pop -}bind def -/DEFS 0 def -/EBEGIN{ -moveto -DEFS begin -}bind def -/EEND/end load def -/CNT 0 def -/level1 0 def -/PBEGIN{ -/level1 save def -translate -div 3 1 roll div exch scale -neg exch neg exch translate -0 setgray -0 setlinecap -1 setlinewidth -0 setlinejoin -10 setmiterlimit -[]0 setdash -/setstrokeadjust where{ -pop -false setstrokeadjust -}if -/setoverprint where{ -pop -false setoverprint -}if -newpath -/CNT countdictstack def -userdict begin -/showpage{}def -}bind def -/PEND{ -clear -countdictstack CNT sub{end}repeat -level1 restore -}bind def -end def -/setpacking where{ -pop -setpacking -}if -%%EndResource -%%IncludeResource: font Times-Roman -%%IncludeResource: font Times-Bold -%%IncludeResource: font Times-Italic -%%IncludeResource: font Symbol -grops begin/DEFS 1 dict def DEFS begin/u{.001 mul}bind def end/RES 72 def/PL -792 def/LS false def/ENC0[/asciicircum/asciitilde/Scaron/Zcaron/scaron/zcaron -/Ydieresis/trademark/quotesingle/.notdef/.notdef/.notdef/.notdef/.notdef -/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef -/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/space -/exclam/quotedbl/numbersign/dollar/percent/ampersand/quoteright/parenleft -/parenright/asterisk/plus/comma/hyphen/period/slash/zero/one/two/three/four -/five/six/seven/eight/nine/colon/semicolon/less/equal/greater/question/at/A/B/C -/D/E/F/G/H/I/J/K/L/M/N/O/P/Q/R/S/T/U/V/W/X/Y/Z/bracketleft/backslash -/bracketright/circumflex/underscore/quoteleft/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q -/r/s/t/u/v/w/x/y/z/braceleft/bar/braceright/tilde/.notdef/quotesinglbase -/guillemotleft/guillemotright/bullet/florin/fraction/perthousand/dagger -/daggerdbl/endash/emdash/ff/fi/fl/ffi/ffl/dotlessi/dotlessj/grave/hungarumlaut -/dotaccent/breve/caron/ring/ogonek/quotedblleft/quotedblright/oe/lslash -/quotedblbase/OE/Lslash/.notdef/exclamdown/cent/sterling/currency/yen/brokenbar -/section/dieresis/copyright/ordfeminine/guilsinglleft/logicalnot/minus -/registered/macron/degree/plusminus/twosuperior/threesuperior/acute/mu -/paragraph/periodcentered/cedilla/onesuperior/ordmasculine/guilsinglright -/onequarter/onehalf/threequarters/questiondown/Agrave/Aacute/Acircumflex/Atilde -/Adieresis/Aring/AE/Ccedilla/Egrave/Eacute/Ecircumflex/Edieresis/Igrave/Iacute -/Icircumflex/Idieresis/Eth/Ntilde/Ograve/Oacute/Ocircumflex/Otilde/Odieresis -/multiply/Oslash/Ugrave/Uacute/Ucircumflex/Udieresis/Yacute/Thorn/germandbls -/agrave/aacute/acircumflex/atilde/adieresis/aring/ae/ccedilla/egrave/eacute -/ecircumflex/edieresis/igrave/iacute/icircumflex/idieresis/eth/ntilde/ograve -/oacute/ocircumflex/otilde/odieresis/divide/oslash/ugrave/uacute/ucircumflex -/udieresis/yacute/thorn/ydieresis]def/Times-Italic@0 ENC0/Times-Italic RE -/Times-Bold@0 ENC0/Times-Bold RE/Times-Roman@0 ENC0/Times-Roman RE -%%EndProlog -%%Page: 1 1 -%%BeginPageSetup -BP -%%EndPageSetup -/F0 10/Times-Roman@0 SF -.35(BA)72 48 S(SH_B).35 E(UIL)-.1 E 290.48 -(TINS\(1\) B)-.92 F(ASH_B)-.35 E(UIL)-.1 E(TINS\(1\))-.92 E/F1 9/Times-Bold@0 -SF -.18(NA)72 84 S(ME).18 E F0 .393(bash, :, ., alias, bg, bind, break, b)108 -96 R .392 -(uiltin, bye, case, cd, command, continue, declare, dirs, echo, enable, e)-.2 F --.25(va)-.25 G(l,).25 E -.15(exe)108 108 S .559(c, e).15 F .559(xit, e)-.15 F -.559(xport, fc, fg, for)-.15 F 3.059(,g)-.4 G .559(etopts, hash, help, history) -231.984 108 R 3.059(,i)-.65 G .56 -(f, jobs, kill, let, local, logout, popd, pushd, pwd,)343.57 108 R 1.562 -(read, readonly)108 120 R 4.062(,r)-.65 G 1.561(eturn, set, shift, source, sus\ -pend, test, times, trap, type, typeset, ulimit, umask, unalias,)176.004 120 R -(unset, until, w)108 132 Q(ait, while \255 bash b)-.1 E(uilt-in commands, see) --.2 E/F2 10/Times-Bold@0 SF(bash)2.5 E F0(\(1\))A F1 -.27(BA)72 148.8 S(SH B) -.27 E(UIL)-.09 E(TIN COMMANDS)-.828 E F2(:)108 160.8 Q F0([)2.5 E/F3 10 -/Times-Italic@0 SF(ar)A(guments)-.37 E F0(])A .501(No ef)144 172.8 R .501 -(fect; the command does nothing be)-.25 F .502(yond e)-.15 F(xpanding)-.15 E F3 -(ar)3.002 E(guments)-.37 E F0 .502(and performing an)3.002 F 3.002(ys)-.15 G -(peci\214ed)508.34 172.8 Q 2.5(redirections. A)144 184.8 R(zero e)2.5 E -(xit code is returned.)-.15 E F2(.)110.5 201.6 Q F3(\214lename)6.666 E F0([)2.5 -E F3(ar)A(guments)-.37 E F0(])A F2(sour)108 213.6 Q(ce)-.18 E F3(\214lename)2.5 -E F0([)2.5 E F3(ar)A(guments)-.37 E F0(])A 1.17(Read and e)144 225.6 R -.15(xe) --.15 G 1.17(cute commands from).15 F F3(\214lename)3.669 E F0 1.169 -(in the current shell en)3.669 F 1.169(vironment and return the e)-.4 F(xit) --.15 E 1.301(status of the last command e)144 237.6 R -.15(xe)-.15 G 1.301 -(cuted from).15 F F3(\214lename)3.801 E F0 6.301(.I).18 G(f)368.138 237.6 Q F3 -(\214lename)3.801 E F0 1.302(does not contain a slash, path-)3.801 F .608 -(names in)144 249.6 R F1 -.666(PA)3.108 G(TH)-.189 E F0 .608 -(are used to \214nd the directory containing)2.858 F F3(\214lename)3.108 E F0 -5.608(.T).18 G .608(he \214le searched for in)424.339 249.6 R F1 -.666(PA)3.108 -G(TH)-.189 E F0 .201(need not be e)144 261.6 R -.15(xe)-.15 G 2.701 -(cutable. The).15 F .201 -(current directory is searched if no \214le is found in)2.701 F F1 -.666(PA) -2.701 G(TH)-.189 E/F4 9/Times-Roman@0 SF(.)A F0 .201(If an)4.701 F(y)-.15 E F3 -(ar)2.702 E(gu-)-.37 E(ments)144 273.6 Q F0 1.058(are supplied, the)3.558 F -3.558(yb)-.15 G 1.058(ecome the positional parameters when)252.232 273.6 R F3 -(\214le)3.558 E F0 1.057(is e)3.557 F -.15(xe)-.15 G 3.557(cuted. Otherwise).15 -F(the)3.557 E 1.078(positional parameters are unchanged.)144 285.6 R 1.079 -(The return status is the status of the last command e)6.078 F(xited)-.15 E -(within the script \(0 if no commands are e)144 297.6 Q -.15(xe)-.15 G -(cuted\), and f).15 E(alse if)-.1 E F3(\214lename)2.5 E F0(is not found.)2.5 E -F2(alias)108 314.4 Q F0([)2.5 E F3(name)A F0([=)A F3(value)A F0 2.5(].)C(..]) -193.9 314.4 Q F2(Alias)144 326.4 Q F0 1.668(with no ar)4.168 F 1.667 -(guments prints the list of aliases in the form)-.18 F F3(name)4.167 E F0(=)A -F3(value)A F0 1.667(on standard output.)4.167 F .606(When ar)144 338.4 R .607 -(guments are supplied, an alias is de\214ned for each)-.18 F F3(name)3.107 E F0 -(whose)3.107 E F3(value)3.107 E F0 .607(is gi)3.107 F -.15(ve)-.25 G 3.107 -(n. A).15 F(trailing)3.107 E 2.693(space in)144 350.4 R F3(value)5.193 E F0 -2.693(causes the ne)5.193 F 2.693(xt w)-.15 F 2.693(ord to be check)-.1 F 2.692 -(ed for alias substitution when the alias is)-.1 F -.15(ex)144 362.4 S 2.867 -(panded. F).15 F .367(or each)-.15 F F3(name)2.867 E F0 .367(in the ar)2.867 F -.367(gument list for which no)-.18 F F3(value)2.867 E F0 .367 -(is supplied, the name and v)2.867 F(alue)-.25 E 1.717 -(of the alias is printed.)144 374.4 R F2(Alias)6.717 E F0 1.717 -(returns true unless a)4.217 F F3(name)4.217 E F0 1.717(is gi)4.217 F -.15(ve) --.25 G 4.216(nf).15 G 1.716(or which no alias has been)425.61 374.4 R -(de\214ned.)144 386.4 Q F2(bg)108 403.2 Q F0([)2.5 E F3(jobspec)A F0(])A(Place) -144 415.2 Q F3(jobspec)3.485 E F0 .985 -(in the background, as if it had been started with)3.485 F F2(&)3.485 E F0 -5.985(.I)C(f)425.645 415.2 Q F3(jobspec)3.485 E F0 .985(is not present, the) -3.485 F(shell')144 427.2 Q 3.102(sn)-.55 G .602(otion of the)177.662 427.2 R F3 -(curr)3.102 E .602(ent job)-.37 F F0 .602(is used.)3.102 F F2(bg)5.602 E F3 -(jobspec)3.102 E F0 .601(returns 0 unless run when job control is dis-)3.102 F -.565(abled or)144 439.2 R 3.065(,w)-.4 G .565 -(hen run with job control enabled, if)189.44 439.2 R F3(jobspec)3.065 E F0 -.1 -(wa)3.065 G 3.065(sn).1 G .566(ot found or started without job con-)394.395 -439.2 R(trol.)144 451.2 Q F2(bind)108 468 Q F0([)2.5 E F2A F3 -.1(ke)2.5 -G(ymap)-.2 E F0 2.5(][)C F2(\255lvd)189.12 468 Q F0 2.5(][)C F2(-q)217.32 468 Q -F3(name)2.5 E F0(])A F2(bind)108 480 Q F0([)2.5 E F2A F3 -.1(ke)2.5 G -(ymap)-.2 E F0(])A F2(-f)2.5 E F3(\214lename)2.5 E F2(bind)108 492 Q F0([)2.5 E -F2A F3 -.1(ke)2.5 G(ymap)-.2 E F0(])A F3 -.1(ke)2.5 G(yseq)-.2 E F0(:)A -F3(function-name)A F0 .239(Display current)144 504 R F2 -.18(re)2.739 G(adline) -.18 E F0 -.1(ke)2.739 G 2.739(ya)-.05 G .239(nd function bindings, or bind a k) -267.836 504 R .538 -.15(ey s)-.1 H .238(equence to a).15 F F2 -.18(re)2.738 G -(adline).18 E F0(function)2.738 E .88(or macro.)144 516 R .88 -(The binding syntax accepted is identical to that of)5.88 F F3(.inputr)3.38 E -(c)-.37 E F0 3.38(,b).31 G .88(ut each binding must be)440.93 516 R .381 -(passed as a separate ar)144 528 R .381 -(gument; e.g., '"\\C-x\\C-r": re\255read\255init\255\214le'.)-.18 F .381 -(Options, if supplied, ha)5.381 F .68 -.15(ve t)-.2 H(he).15 E(follo)144 540 Q -(wing meanings:)-.25 E F2144 552 Q F3 -.1(ke)2.5 G(ymap)-.2 E F0(Use)180 -564 Q F3 -.1(ke)5.174 G(ymap)-.2 E F0 2.674(as the k)5.174 F -.15(ey)-.1 G -2.674(map to be af).15 F 2.674(fected by the subsequent bindings.)-.25 F -(Acceptable)7.675 E F3 -.1(ke)180 576 S(ymap)-.2 E F0 2.929(names are)5.429 F -F3 2.929(emacs, emacs-standar)5.429 F 2.929 -(d, emacs-meta, emacs-ctlx, vi, vi-mo)-.37 F(ve)-.1 E 5.428(,v)-.1 G(i-)533.89 -576 Q(command)180 588 Q F0 3.434(,a)C(nd)229.254 588 Q F3(vi-insert)3.434 E F0 -(.).68 E F3(vi)5.934 E F0 .934(is equi)3.434 F -.25(va)-.25 G .934(lent to).25 -F F3(vi-command)3.434 E F0(;)A F3(emacs)3.434 E F0 .934(is equi)3.434 F -.25 -(va)-.25 G .935(lent to).25 F F3(emacs-)3.435 E(standar)180 600 Q(d)-.37 E F0 -(.)A F2144 612 Q F0(List the names of all)180 612 Q F2 -.18(re)2.5 G -(adline).18 E F0(functions)2.5 E F2144 624 Q F0 -(List current function names and bindings)180 624 Q F2144 636 Q F0 -(Dump function names and bindings in such a w)180 636 Q(ay that the)-.1 E 2.5 -(yc)-.15 G(an be re-read)423.89 636 Q F2144 648 Q F3(\214lename)2.5 E F0 -(Read k)180 660 Q .3 -.15(ey b)-.1 H(indings from).15 E F3(\214lename)2.5 E F2 -144 672 Q F3(function)2.5 E F0(Query about which k)180 684 Q -.15(ey)-.1 -G 2.5(si).15 G -1.9 -.4(nv o)282.51 684 T .2 -.1(ke t).4 H(he named).1 E F3 -(function)2.5 E F0(The return v)144 700.8 Q -(alue is 0 unless an unrecognized option is gi)-.25 E -.15(ve)-.25 G 2.5(no).15 -G 2.5(ra)391.37 700.8 S 2.5(ne)401.64 700.8 S(rror occurred.)413.58 700.8 Q -170.955(GNU 1993)72 768 R(September 16)2.5 E(1)535 768 Q EP -%%Page: 2 2 -%%BeginPageSetup -BP -%%EndPageSetup -/F0 10/Times-Roman@0 SF -.35(BA)72 48 S(SH_B).35 E(UIL)-.1 E 290.48 -(TINS\(1\) B)-.92 F(ASH_B)-.35 E(UIL)-.1 E(TINS\(1\))-.92 E/F1 10/Times-Bold@0 -SF(br)108 84 Q(eak)-.18 E F0([)2.5 E/F2 10/Times-Italic@0 SF(n)A F0(])A .076 -(Exit from within a)144 96 R F1 -.25(fo)2.576 G(r).25 E F0(,)A F1(while)2.576 E -F0 2.576(,o)C(r)270.866 96 Q F1(until)2.576 E F0 2.576(loop. If)2.576 F F2(n) -2.576 E F0 .076(is speci\214ed, break)2.576 F F2(n)2.576 E F0(le)2.576 E -.15 -(ve)-.25 G(ls.).15 E F2(n)5.075 E F0 .075(must be)2.575 F/F3 10/Symbol SF -2.575 E F0 2.575(1. If)2.575 F F2(n)2.575 E F0(is)2.575 E .838 -(greater than the number of enclosing loops, all enclosing loops are e)144 108 -R 3.338(xited. The)-.15 F .838(return v)3.338 F .839(alue is 0)-.25 F -(unless the shell is not e)144 120 Q -.15(xe)-.15 G(cuting a loop when).15 E F1 -(br)2.5 E(eak)-.18 E F0(is e)2.5 E -.15(xe)-.15 G(cuted.).15 E F1 -.2(bu)108 -136.8 S(iltin).2 E F2(shell\255b)2.5 E(uiltin)-.2 E F0([)2.5 E F2(ar)A(guments) --.37 E F0(])A(Ex)144 148.8 Q .793(ecute the speci\214ed shell b)-.15 F .793 -(uiltin, passing it)-.2 F F2(ar)3.293 E(guments)-.37 E F0 3.293(,a).27 G .793 -(nd return its e)382.104 148.8 R .792(xit status.)-.15 F .792(This is useful) -5.792 F .603 -(when you wish to de\214ne a function whose name is the same as a shell b)144 -160.8 R .603(uiltin, b)-.2 F .603(ut need the func-)-.2 F .773 -(tionality of the b)144 172.8 R .773(uiltin within the function itself.)-.2 F -(The)5.773 E F1(cd)3.273 E F0 -.2(bu)3.273 G .772 -(iltin is commonly rede\214ned this w).2 F(ay)-.1 E(.)-.65 E -(The return status is f)144 184.8 Q(alse if)-.1 E F2(shell\255b)2.5 E(uiltin) --.2 E F0(is not a shell b)2.5 E(uiltin command.)-.2 E F1(cd)108 201.6 Q F0([) -2.5 E F2(dir)A F0 5.17(]C)C .21(hange the current directory to)150.67 201.6 R -F2(dir)2.71 E F0 5.21(.T)C .21(he v)298.01 201.6 R(ariable)-.25 E/F4 9 -/Times-Bold@0 SF(HOME)2.71 E F0 .21(is the def)2.46 F(ault)-.1 E F2(dir)2.71 E -F0 5.21(.T).73 G .21(he v)456.703 201.6 R(ariable)-.25 E F4(CDP)2.71 E -.855 -(AT)-.666 G(H).855 E F0 .337 -(de\214nes the search path for the directory containing)144 213.6 R F2(dir) -2.837 E F0 5.337(.A).73 G(lternati)379.663 213.6 Q .637 -.15(ve d)-.25 H .337 -(irectory names are separated).15 F .309(by a colon \(:\).)144 225.6 R 2.809 -(An)5.309 G .309(ull directory name in)221.365 225.6 R F4(CDP)2.809 E -.855(AT) --.666 G(H).855 E F0 .309(is the same as the current directory)2.559 F 2.809(,i) --.65 G .31(.e., `)496.44 225.6 R(`)-.74 E F1(.)A F0 -.74('')C 5.31(.I).74 G(f) -536.67 225.6 Q F2(dir)144 237.6 Q F0(be)3.419 E .919 -(gins with a slash \(/\), then)-.15 F F4(CDP)3.419 E -.855(AT)-.666 G(H).855 E -F0 .919(is not used.)3.169 F .918(An ar)5.918 F .918(gument of)-.18 F F1 -3.418 E F0 .918(is equi)3.418 F -.25(va)-.25 G .918(lent to).25 F F4($OLD-) -3.418 E(PWD)144 249.6 Q/F5 9/Times-Roman@0 SF(.)A F0(The return v)4.5 E -(alue is true if the directory w)-.25 E(as successfully changed; f)-.1 E -(alse otherwise.)-.1 E F1(command)108 266.4 Q F0([)2.5 E F1(-pVv)A F0(])A F2 -(command)2.5 E F0([)2.5 E F2(ar)A(g)-.37 E F0(...])2.5 E(Run)144 278.4 Q F2 -(command)2.877 E F0(with)2.877 E F2(ar)2.877 E(gs)-.37 E F0 .378 -(suppressing the normal shell function lookup. Only b)2.877 F .378 -(uiltin commands or)-.2 F .559(commands found in the)144 290.4 R F4 -.666(PA) -3.059 G(TH)-.189 E F0 .559(are e)2.809 F -.15(xe)-.15 G 3.059(cuted. If).15 F -(the)3.059 E F13.059 E F0 .559(option is gi)3.059 F -.15(ve)-.25 G .558 -(n, the search for).15 F F2(command)3.058 E F0(is)3.058 E .231 -(performed using a def)144 302.4 R .231(ault v)-.1 F .231(alue for)-.25 F F1 --.74(PA)2.731 G(TH)-.21 E F0 .231 -(that is guaranteed to \214nd all of the standard utilities.)2.731 F(If)5.232 E -.232(either the)144 314.4 R F12.732 E F0(or)2.732 E F12.732 E F0 -.232(option is supplied, a description of)2.732 F F2(command)2.732 E F0 .232 -(is printed.)2.732 F(The)5.231 E F12.731 E F0 .231(option causes)2.731 F -2.71(as)144 326.4 S .21(ingle w)155.04 326.4 R .21 -(ord indicating the command or pathname used to in)-.1 F -.2(vo)-.4 G -.1(ke).2 -G F2(command)2.811 E F0 .211(to be printed; the)2.711 F F12.711 E F0 .476 -(option produces a more v)144 338.4 R .476(erbose description.)-.15 F .476 -(An ar)5.476 F .476(gument of)-.18 F F12.976 E F0 .475 -(disables option checking for the)2.976 F 1.348(rest of the ar)144 350.4 R -3.848(guments. If)-.18 F(the)3.848 E F13.848 E F0(or)3.848 E F1 -3.848 E F0 1.348(option is supplied, the e)3.848 F 1.349(xit status is 0 if) --.15 F F2(command)3.849 E F0 -.1(wa)3.849 G(s).1 E 1.306(found, and 1 if not.) -144 362.4 R 1.305(If neither option is supplied and an error occurred or)6.306 -F F2(command)3.805 E F0 1.305(cannot be)3.805 F .092(found, the e)144 374.4 R -.092(xit status is 127.)-.15 F .092(Otherwise, the e)5.092 F .092 -(xit status of the)-.15 F F1(command)2.592 E F0 -.2(bu)2.592 G .093 -(iltin is the e).2 F .093(xit status of)-.15 F F2(command)144 386.4 Q F0(.).77 -E F1(continue)108 403.2 Q F0([)2.5 E F2(n)A F0(])A .065(Resume the ne)144 415.2 -R .065(xt iteration of the enclosing)-.15 F F1 -.25(fo)2.565 G(r).25 E F0(,)A -F1(while)2.565 E F0 2.564(,o)C(r)366.104 415.2 Q F1(until)2.564 E F0 2.564 -(loop. If)2.564 F F2(n)2.564 E F0 .064(is speci\214ed, resume at the)2.564 F F2 -(n)144 427.2 Q F0 1.168(th enclosing loop.)B F2(n)6.169 E F0 1.169(must be) -3.669 F F33.669 E F0 3.669(1. If)3.669 F F2(n)3.669 E F0 1.169 -(is greater than the number of enclosing loops, the last)3.669 F 1.594 -(enclosing loop \(the `top\255le)144 439.2 R -.15(ve)-.25 G 1.593 -(l' loop\) is resumed.).15 F 1.593(The return v)6.593 F 1.593 -(alue is 0 unless the shell is not)-.25 F -.15(exe)144 451.2 S -(cuting a loop when).15 E F1(continue)2.5 E F0(is e)2.5 E -.15(xe)-.15 G -(cuted.).15 E F1(declar)108 468 Q(e)-.18 E F0([)2.5 E F1(\255frxi)A F0 2.5(][)C -F2(name)175.16 468 Q F0([=)A F2(value)A F0(]])A F1(typeset)108 480 Q F0([)2.5 E -F1(\255frxi)A F0 2.5(][)C F2(name)174.23 480 Q F0([=)A F2(value)A F0(]])A 1.098 -(Declare v)144 492 R 1.098(ariables and/or gi)-.25 F 1.398 -.15(ve t)-.25 H -1.098(hem attrib).15 F 3.598(utes. If)-.2 F(no)3.598 E F2(name)3.598 E F0 3.598 -(sa)C 1.098(re gi)394.362 492 R -.15(ve)-.25 G 1.098(n, then display the v).15 -F 1.098(alues of)-.25 F -.25(va)144 504 S 2.492(riables instead.).25 F 2.491 -(The options can be used to restrict output to v)7.492 F 2.491 -(ariables with the speci\214ed)-.25 F(attrib)144 516 Q(ute.)-.2 E F1144 -528 Q F0(Use function names only)180 528 Q F1144 540 Q F0(Mak)180 540 Q -(e)-.1 E F2(name)5.046 E F0 5.046(sr)C(eadonly)241.642 540 Q 7.546(.T)-.65 G -2.546(hese names cannot then be assigned v)288.808 540 R 2.547 -(alues by subsequent)-.25 F(assignment statements.)180 552 Q F1144 564 Q -F0(Mark)180 564 Q F2(name)2.5 E F0 2.5(sf)C(or e)235.54 564 Q -(xport to subsequent commands via the en)-.15 E(vironment.)-.4 E F1144 -576 Q F0 .558(The v)180 576 R .558(ariable is treated as an inte)-.25 F .558 -(ger; arithmetic e)-.15 F -.25(va)-.25 G .558(luation \(see).25 F F4 .557 -(ARITHMETIC EV)3.058 F(ALU)-1.215 E(A-)-.54 E(TION \))180 588 Q F0 -(is performed when the v)2.25 E(ariable is assigned a v)-.25 E(alue.)-.25 E -1.218(Using `+' instead of `\255' turns of)144 604.8 R 3.719(ft)-.25 G 1.219 -(he attrib)289.369 604.8 R 1.219(ute instead.)-.2 F 1.219 -(When used in a function, mak)6.219 F(es)-.1 E F2(name)3.719 E F0(s)A .236 -(local, as with the)144 616.8 R F1(local)2.736 E F0 2.735(command. The)2.736 F -.235(return v)2.735 F .235(alue is 0 unless an ille)-.25 F -.05(ga)-.15 G 2.735 -(lo).05 G .235(ption is encountered, an)443.755 616.8 R .435 -(attempt is made to de\214ne a function using "-f foo=bar", one of the)144 -628.8 R F2(names)2.935 E F0 .435(is not a le)2.935 F -.05(ga)-.15 G 2.935(ls) -.05 G .435(hell v)503.435 628.8 R(ari-)-.25 E .52 -(able name, an attempt is made to turn of)144 640.8 R 3.019(fr)-.25 G .519 -(eadonly status for a readonly v)318.399 640.8 R .519 -(ariable, or an attempt is)-.25 F(made to display a non-e)144 652.8 Q -(xistant function with -f.)-.15 E F1(dirs [-l] [+/\255n])108 669.6 Q F0 1.505 -(Display the list of currently remembered directories.)144 681.6 R 1.505 -(Directories are added to the list with the)6.505 F F1(pushd)144 693.6 Q F0 -(command; the)2.5 E F1(popd)2.5 E F0(command mo)2.5 E -.15(ve)-.15 G 2.5(sb).15 -G(ack up through the list.)331.5 693.6 Q F1(+n)144 705.6 Q F0 .13(displays the) -180 705.6 R F2(n)2.63 E F0 .13(th entry counting from the left of the list sho) -B .13(wn by)-.25 F F1(dirs)2.63 E F0 .13(when in)2.63 F -.2(vo)-.4 G -.1(ke).2 -G 2.63(dw).1 G(ith-)526.11 705.6 Q(out options, starting with zero.)180 717.6 Q -170.955(GNU 1993)72 768 R(September 16)2.5 E(2)535 768 Q EP -%%Page: 3 3 -%%BeginPageSetup -BP -%%EndPageSetup -/F0 10/Times-Roman@0 SF -.35(BA)72 48 S(SH_B).35 E(UIL)-.1 E 290.48 -(TINS\(1\) B)-.92 F(ASH_B)-.35 E(UIL)-.1 E(TINS\(1\))-.92 E/F1 10/Times-Bold@0 -SF144 84 Q F0 1.342(displays the)180 84 R/F2 10/Times-Italic@0 SF(n)3.842 -E F0 1.342(th entry counting from the right of the list sho)B 1.342(wn by)-.25 -F F1(dirs)3.842 E F0 1.342(when in)3.842 F -.2(vo)-.4 G -.1(ke).2 G(d).1 E -(without options, starting with zero.)180 96 Q F1144 108 Q F0 .362 -(produces a longer listing; the def)180 108 R .361 -(ault listing format uses a tilde to denote the home direc-)-.1 F(tory)180 120 -Q(.)-.65 E .38(The return v)144 136.8 R .38(alue is 0 unless an ille)-.25 F --.05(ga)-.15 G 2.88(lo).05 G .381(ption is supplied or)303.79 136.8 R F2(n) -2.881 E F0(inde)2.881 E -.15(xe)-.15 G 2.881(sb).15 G -.15(ey)430.775 136.8 S -.381(ond the end of the direc-).15 F(tory stack.)144 148.8 Q F1(echo)108 165.6 -Q F0([)2.5 E F1(\255neE)A F0 2.5(][)C F2(ar)164.8 165.6 Q(g)-.37 E F0(...])2.5 -E .267(Output the)144 177.6 R F2(ar)2.767 E(g)-.37 E F0 .267 -(s, separated by spaces.)B .267(The return status is al)5.267 F -.1(wa)-.1 G -.266(ys 0.).1 F(If)5.266 E F12.766 E F0 .266 -(is speci\214ed, the trailing)2.766 F(ne)144 189.6 Q .31(wline is suppressed.) --.25 F .311(If the)5.31 F F12.811 E F0 .311(option is gi)2.811 F -.15(ve) --.25 G .311(n, interpretation of the follo).15 F .311(wing backslash-escaped) --.25 F .874(characters is enabled.)144 201.6 R(The)5.874 E F13.374 E F0 -.874(option disables the interpretation of these escape characters, e)3.374 F --.15(ve)-.25 G(n).15 E(on systems where the)144 213.6 Q 2.5(ya)-.15 G -(re interpreted by def)241.61 213.6 Q(ault.)-.1 E F1(\\a)144 225.6 Q F0 -(alert \(bell\))180 225.6 Q F1(\\b)144 237.6 Q F0(backspace)180 237.6 Q F1(\\c) -144 249.6 Q F0(suppress trailing ne)180 249.6 Q(wline)-.25 E F1(\\f)144 261.6 Q -F0(form feed)180 261.6 Q F1(\\n)144 273.6 Q F0(ne)180 273.6 Q 2.5(wl)-.25 G -(ine)201.69 273.6 Q F1(\\r)144 285.6 Q F0(carriage return)180 285.6 Q F1(\\t) -144 297.6 Q F0(horizontal tab)180 297.6 Q F1(\\v)144 309.6 Q F0 -.15(ve)180 -309.6 S(rtical tab).15 E F1(\\\\)144 321.6 Q F0(backslash)180 321.6 Q F1(\\nnn) -144 333.6 Q F0(the character whose ASCII code is)180 333.6 Q F2(nnn)2.5 E F0 -(\(octal\))2.5 E F1(enable)108 350.4 Q F0([)2.5 E F1A F0 2.5(][)C F1 -(\255all)162.03 350.4 Q F0 2.5(][)C F2(name)187.45 350.4 Q F0(...])2.5 E .682 -(Enable and disable b)144 362.4 R .683(uiltin shell commands.)-.2 F .683 -(This allo)5.683 F .683(ws the e)-.25 F -.15(xe)-.15 G .683 -(cution of a disk command which).15 F .324(has the same name as a shell b)144 -374.4 R .324(uiltin without specifying a full pathname.)-.2 F(If)5.324 E F1 -2.824 E F0 .324(is used, each)2.824 F F2(name)2.823 E F0 .18 -(is disabled; otherwise,)144 386.4 R F2(names)2.68 E F0 .18(are enabled.)2.68 F --.15(Fo)5.18 G 2.68(re).15 G .181(xample, to use the)338.81 386.4 R F1(test) -2.681 E F0 .181(binary found via the)2.681 F/F3 9/Times-Bold@0 SF -.666(PA) -2.681 G(TH)-.189 E F0 .749(instead of the shell b)144 398.4 R .749(uiltin v)-.2 -F .749(ersion, type `)-.15 F .748(`enable -n test')-.74 F 3.248('. If)-.74 F -.748(no ar)3.248 F .748(guments are gi)-.18 F -.15(ve)-.25 G .748 -(n, a list of all).15 F .424(enabled shell b)144 410.4 R .424 -(uiltins is printed.)-.2 F .424(If only)5.424 F F12.924 E F0 .425 -(is supplied, a list of all disabled b)2.924 F .425(uiltins is printed.)-.2 F -(If)5.425 E(only)144 422.4 Q F1(\255all)2.547 E F0 .047 -(is supplied, the list printed includes all b)2.547 F .046 -(uiltins, with an indication of whether or not each)-.2 F .28(is enabled.)144 -434.4 R F1(enable)5.28 E F0(accepts)2.78 E F12.78 E F0 .28(as a synon) -2.78 F .28(ym for)-.15 F F1(\255all)2.78 E F0 5.28(.T)C .281(he return v)370.8 -434.4 R .281(alue is 0 unless a)-.25 F F2(name)2.781 E F0 .281(is not a)2.781 F -(shell b)144 446.4 Q(uiltin.)-.2 E F1 -2.3 -.15(ev a)108 463.2 T(l).15 E F0([) -2.5 E F2(ar)A(g)-.37 E F0(...])2.5 E(The)144 475.2 Q F2(ar)3.171 E(g)-.37 E F0 -3.171(sa)C .671(re read and concatenated together into a single command.) -187.742 475.2 R .67(This command is then read)5.67 F .164(and e)144 487.2 R --.15(xe)-.15 G .164(cuted by the shell, and its e).15 F .165 -(xit status is returned as the v)-.15 F .165(alue of the)-.25 F F1 -2.3 -.15 -(ev a)2.665 H(l).15 E F0 2.665(command. If)2.665 F(there)2.665 E(are no)144 -499.2 Q F2(ar)2.5 E(gs)-.37 E F0 2.5(,o).27 G 2.5(ro)198.89 499.2 S -(nly null ar)209.72 499.2 Q(guments,)-.18 E F1 -2.3 -.15(ev a)2.5 H(l).15 E F0 -(returns true.)2.5 E F1(exec)108 516 Q F0([[)2.5 E F1A F0(])A F2(command) -2.5 E F0([)2.5 E F2(ar)A(guments)-.37 E F0(]])A(If)144 528 Q F2(command)2.91 E -F0 .41(is speci\214ed, it replaces the shell.)2.91 F .41(No ne)5.41 F 2.91(wp) --.25 G .41(rocess is created.)371.42 528 R(The)5.41 E F2(ar)2.91 E(guments)-.37 -E F0(become)2.91 E 1.238(the ar)144 540 R 1.238(guments to)-.18 F F2(command) -3.738 E F0 6.238(.I)C 3.738(ft)267.642 540 S 1.238(he \214rst ar)277.49 540 R -1.238(gument is)-.18 F F13.738 E F0 3.738(,t)C 1.239 -(he shell places a dash in the zeroth ar)376.42 540 R(g)-.18 E 1.049(passed to) -144 552 R F2(command)3.549 E F0 6.049(.T).77 G 1.048(his is what login does.) -239.847 552 R 1.048(If the \214le cannot be e)6.048 F -.15(xe)-.15 G 1.048 -(cuted for some reason, a).15 F(non-interacti)144 564 Q .91 -.15(ve s)-.25 H -.611(hell e).15 F .611(xits, unless the shell v)-.15 F(ariable)-.25 E F1 -(no_exit_on_failed_exec)3.111 E F0 -.15(ex)3.111 G .611(ists, in which case).15 -F .333(it returns f)144 576 R 2.833(ailure. An)-.1 F(interacti)2.833 E .633 --.15(ve s)-.25 H .333(hell returns f).15 F .332 -(ailure if the \214le cannot be e)-.1 F -.15(xe)-.15 G 2.832(cuted. If).15 F F2 -(command)2.832 E F0(is)2.832 E(not speci\214ed, an)144 588 Q 2.5(yr)-.15 G -(edirections tak)219.95 588 Q 2.5(ee)-.1 G -.25(ff)289.83 588 S -(ect in the current shell, and the return status is 0.).25 E F1(exit)108 604.8 -Q F0([)2.5 E F2(n)A F0 6.29(]C)C .122(ause the shell to e)150.67 604.8 R .122 -(xit with a status of)-.15 F F2(n)2.623 E F0 5.123(.I)C(f)315.064 604.8 Q F2(n) -2.623 E F0 .123(is omitted, the e)2.623 F .123 -(xit status is that of the last command)-.15 F -.15(exe)144 616.8 S 2.5 -(cuted. A).15 F(trap on)2.5 E F3(EXIT)2.5 E F0(is e)2.25 E -.15(xe)-.15 G -(cuted before the shell terminates.).15 E F1(export)108 633.6 Q F0([)2.5 E F1 -(\255nf)A F0 2.5(][).833 G F2(name)166.183 633.6 Q F0([=)A F2(wor)A(d)-.37 E F0 -(]] ...)A F1(export \255p)108 645.6 Q F0 .306(The supplied)144 657.6 R F2 -(names)2.806 E F0 .306(are mark)2.806 F .305(ed for automatic e)-.1 F .305 -(xport to the en)-.15 F .305(vironment of subsequently e)-.4 F -.15(xe)-.15 G -(cuted).15 E 2.693(commands. If)144 669.6 R(the)2.693 E F12.693 E F0 .193 -(option is gi)2.693 F -.15(ve)-.25 G .193(n, the).15 F F2(names)2.693 E F0 .193 -(refer to functions.)2.693 F .193(If no)5.193 F F2(names)2.693 E F0 .193 -(are gi)2.693 F -.15(ve)-.25 G .194(n, or if the).15 F F1144 681.6 Q F0 -.66(option is supplied, a list of all names that are e)3.16 F .659 -(xported in this shell is printed.)-.15 F(The)5.659 E F13.159 E F0 -(option)3.159 E .537(causes the e)144 693.6 R .537(xport property to be remo) --.15 F -.15(ve)-.15 G 3.037(df).15 G .537(rom the named v)318.099 693.6 R 3.038 -(ariables. An)-.25 F(ar)3.038 E .538(gument of)-.18 F F13.038 E F0 -(disables)3.038 E .666(option checking for the rest of the ar)144 705.6 R -(guments.)-.18 E F1(export)5.665 E F0 .665(returns an e)3.165 F .665 -(xit status of 0 unless an ille)-.15 F -.05(ga)-.15 G(l).05 E .32 -(option is encountered, one of the)144 717.6 R F2(names)2.82 E F0 .32 -(is not a le)2.82 F -.05(ga)-.15 G 2.82(ls).05 G .32(hell v)366.18 717.6 R .32 -(ariable name, or)-.25 F F12.82 E F0 .32(is supplied with a)2.82 F F2 -(name)144 729.6 Q F0(that is not a function.)2.5 E 170.955(GNU 1993)72 768 R -(September 16)2.5 E(3)535 768 Q EP -%%Page: 4 4 -%%BeginPageSetup -BP -%%EndPageSetup -/F0 10/Times-Roman@0 SF -.35(BA)72 48 S(SH_B).35 E(UIL)-.1 E 290.48 -(TINS\(1\) B)-.92 F(ASH_B)-.35 E(UIL)-.1 E(TINS\(1\))-.92 E/F1 10/Times-Bold@0 -SF(fc)108 84 Q F0([)2.5 E F1A/F2 10/Times-Italic@0 SF(ename)2.5 E F0 2.5 -(][)C F1(\255nlr)169.5 84 Q F0 2.5(][)C F2<8c72>197.14 84 Q(st)-.1 E F0 2.5(][) -C F2(last)221.76 84 Q F0(])A F1(fc \255s)108 96 Q F0([)2.5 E F2(pat)A F0(=)A F2 --.37(re)C(p).37 E F0 2.5(][)C F2(cmd)174.23 96 Q F0(])A .665(Fix Command.)144 -108 R .665(In the \214rst form, a range of commands from)5.665 F F2<8c72>3.164 -E(st)-.1 E F0(to)3.164 E F2(last)3.164 E F0 .664(is selected from the his-) -3.164 F .967(tory list.)144 120 R F2 -.45(Fi)5.967 G -.1(rs).45 G(t).1 E F0 -(and)3.467 E F2(last)3.467 E F0 .967 -(may be speci\214ed as a string \(to locate the last command be)3.467 F .968 -(ginning with)-.15 F .797(that string\) or as a number \(an inde)144 132 R -3.297(xi)-.15 G .797(nto the history list, where a ne)300.756 132 R -.05(ga) --.15 G(ti).05 E 1.097 -.15(ve n)-.25 H .796(umber is used as an).15 F(of)144 -144 Q .321(fset from the current command number\).)-.25 F(If)5.322 E F2(last) -2.822 E F0 .322(is not speci\214ed it is set to the current command)2.822 F -.019(for listing \(so that)144 156 R F1 .019(fc \255l \25510)2.519 F F0 .019 -(prints the last 10 commands\) and to)2.519 F F2<8c72>2.519 E(st)-.1 E F0 2.519 -(otherwise. If)2.519 F F2<8c72>2.519 E(st)-.1 E F0 .019(is not spec-)2.519 F -(i\214ed it is set to the pre)144 168 Q -(vious command for editing and \25516 for listing.)-.25 E(The)144 192 Q F1 -2.92 E F0 .42(\215ag suppresses the command numbers when listing.)2.92 F -(The)5.421 E F12.921 E F0 .421(\215ag re)2.921 F -.15(ve)-.25 G .421 -(rses the order of the).15 F 3.642(commands. If)144 204 R(the)3.642 E F1 -3.642 E F0 1.142(\215ag is gi)3.642 F -.15(ve)-.25 G 1.142 -(n, the commands are listed on standard output.).15 F 1.142(Otherwise, the) -6.142 F .378(editor gi)144 216 R -.15(ve)-.25 G 2.878(nb).15 G(y)199.906 216 Q -F2(ename)2.878 E F0 .378(is in)2.878 F -.2(vo)-.4 G -.1(ke).2 G 2.878(do).1 G -2.878(na\214)285.708 216 S .378(le containing those commands.)306.464 216 R(If) -5.378 E F2(ename)2.878 E F0 .379(is not gi)2.879 F -.15(ve)-.25 G .379(n, the) -.15 F -.25(va)144 228 S .805(lue of the).25 F/F3 9/Times-Bold@0 SF(FCEDIT)3.305 -E F0 -.25(va)3.055 G .805(riable is used, and the v).25 F .805(alue of)-.25 F -F3(EDIT)3.305 E(OR)-.162 E F0(if)3.054 E F3(FCEDIT)3.304 E F0 .804(is not set.) -3.054 F .804(If neither)5.804 F -.25(va)144 240 S(riable is set, is used.).25 E -(When editing is complete, the edited commands are echoed and e)5 E -.15(xe) --.15 G(cuted.).15 E .039(In the second form,)144 264 R F2(command)2.539 E F0 -.039(is re-e)2.539 F -.15(xe)-.15 G .039(cuted after each instance of).15 F F2 -(pat)2.54 E F0 .04(is replaced by)2.54 F F2 -.37(re)2.54 G(p).37 E F0 5.04(.A)C -(useful)515.56 264 Q 1.009(alias to use with this is `)144 276 R 1.008 -(`r=fc \255s')-.74 F 1.008(', so that typing `)-.74 F 1.008(`r cc')-.74 F 3.508 -('r)-.74 G 1.008(uns the last command be)385.39 276 R 1.008(ginning with)-.15 F --.74(``)144 288 S(cc').74 E 2.5('a)-.74 G(nd typing `)171.66 288 Q(`r')-.74 E -2.5('r)-.74 G(e-e)233.22 288 Q -.15(xe)-.15 G(cutes the last command.).15 E -.426(If the \214rst form is used, the return v)144 312 R .427 -(alue is 0 unless an ille)-.25 F -.05(ga)-.15 G 2.927(lo).05 G .427 -(ption is encountered or)399.768 312 R F2<8c72>2.927 E(st)-.1 E F0(or)2.927 E -F2(last)2.927 E F0 .455(specify history lines out of range.)144 324 R .454 -(If the)5.454 F F12.954 E F0 .454(option is supplied, the return v)2.954 -F .454(alue is the v)-.25 F .454(alue of the)-.25 F .787(last command e)144 336 -R -.15(xe)-.15 G .787(cuted or f).15 F .788 -(ailure if an error occurs with the temporary \214le of commands.)-.1 F .788 -(If the)5.788 F 1.196 -(second form is used, the return status is that of the command re-e)144 348 R --.15(xe)-.15 G 1.196(cuted, unless).15 F F2(cmd)3.696 E F0 1.196(does not)3.696 -F(specify a v)144 360 Q(alid history line, in which case)-.25 E F1(fc)2.5 E F0 -(returns f)2.5 E(ailure.)-.1 E F1(fg)108 376.8 Q F0([)2.5 E F2(jobspec)A F0(])A -(Place)144 388.8 Q F2(jobspec)3.041 E F0 .541(in the fore)3.041 F .542 -(ground, and mak)-.15 F 3.042(ei)-.1 G 3.042(tt)323.06 388.8 S .542 -(he current job)331.662 388.8 R 5.542(.I)-.4 G(f)399.258 388.8 Q F2(jobspec) -3.042 E F0 .542(is not present, the shell')3.042 F(s)-.55 E .958(notion of the) -144 400.8 R F2(curr)3.458 E .958(ent job)-.37 F F0 .957(is used.)3.457 F .957 -(The return v)5.957 F .957(alue is that of the command placed into the fore-) --.25 F .194(ground, or f)144 412.8 R .194 -(ailure if run when job control is disabled or)-.1 F 2.695(,w)-.4 G .195 -(hen run with job control enabled, if)378.655 412.8 R F2(job-)2.695 E(spec)144 -424.8 Q F0(does not specify a v)2.5 E(alid job or)-.25 E F2(jobspec)2.5 E F0 -(speci\214es a job that w)2.5 E(as started without job control.)-.1 E F1 -(getopts)108 441.6 Q F2(optstring name)2.5 E F0([)2.5 E F2(ar)A(gs)-.37 E F0(]) -A F1(getopts)144 453.6 Q F0 .828 -(is used by shell procedures to parse positional parameters.)3.328 F F2 -(optstring)5.827 E F0 .827(contains the option)3.327 F .602 -(letters to be recognized; if a letter is follo)144 465.6 R .603 -(wed by a colon, the option is e)-.25 F .603(xpected to ha)-.15 F .903 -.15 -(ve a)-.2 H 3.103(na).15 G -.18(rg)523.52 465.6 S(u-).18 E .7 -(ment, which should be separated from it by white space.)144 477.6 R .7 -(Each time it is in)5.7 F -.2(vo)-.4 G -.1(ke).2 G(d,).1 E F1(getopts)3.2 E F0 -(places)3.2 E .008(the ne)144 489.6 R .008(xt option in the shell v)-.15 F -(ariable)-.25 E F2(name)2.508 E F0 2.508(,i).18 G(nitializing)316.884 489.6 Q -F2(name)2.508 E F0 .009(if it does not e)2.508 F .009(xist, and the inde)-.15 F -2.509(xo)-.15 G 2.509(ft)521.941 489.6 S(he)530.56 489.6 Q(ne)144 501.6 Q .199 -(xt ar)-.15 F .199(gument to be processed into the v)-.18 F(ariable)-.25 E F3 -(OPTIND)2.699 E/F4 9/Times-Roman@0 SF(.)A F3(OPTIND)4.699 E F0 .198 -(is initialized to 1 each time the)2.449 F .497(shell or a shell script is in) -144 513.6 R -.2(vo)-.4 G -.1(ke).2 G 2.997(d. When).1 F .498 -(an option requires an ar)2.997 F(gument,)-.18 E F1(getopts)2.998 E F0 .498 -(places that ar)2.998 F(gu-)-.18 E .028(ment into the v)144 525.6 R(ariable) --.25 E F3(OPT)2.528 E(ARG)-.81 E F4(.)A F0 .028(The shell does not reset)4.528 -F F3(OPTIND)2.528 E F0 .027(automatically; it must be manu-)2.278 F .161 -(ally reset between multiple calls to)144 537.6 R F1(getopts)2.661 E F0 .161 -(within the same shell in)2.661 F -.2(vo)-.4 G .161(cation if a ne).2 F 2.662 -(ws)-.25 G .162(et of param-)490.806 537.6 R(eters is to be used.)144 549.6 Q -F1(getopts)144 573.6 Q F0 1.252(can report errors in tw)3.752 F 3.752(ow)-.1 G -3.752(ays. If)287.942 573.6 R 1.252(the \214rst character of)3.752 F F2 -(optstring)3.752 E F0 1.251(is a colon,)3.752 F F2(silent)3.751 E F0(error) -3.751 E 1.442(reporting is used.)144 585.6 R 1.442 -(In normal operation diagnostic messages are printed when ille)6.442 F -.05(ga) --.15 G 3.943(lo).05 G 1.443(ptions or)503.277 585.6 R .654(missing option ar) -144 597.6 R .653(guments are encountered.)-.18 F .653(If the v)5.653 F(ariable) --.25 E F3(OPTERR)3.153 E F0 .653(is set to 0, no error message)2.903 F -(will be displayed, e)144 609.6 Q -.15(ve)-.25 G 2.5(ni).15 G 2.5(ft)241.09 -609.6 S(he \214rst character of)249.7 609.6 Q F2(optstring)2.5 E F0 -(is not a colon.)2.5 E .826(If an ille)144 633.6 R -.05(ga)-.15 G 3.326(lo).05 -G .826(ption is seen,)199.878 633.6 R F1(getopts)3.326 E F0 .826(places ? into) -3.326 F F2(name)3.326 E F0 .826(and, if not silent, prints an error message) -3.326 F .4(and unsets)144 645.6 R F3(OPT)2.9 E(ARG)-.81 E F4(.)A F0(If)4.899 E -F1(getopts)2.899 E F0 .399(is silent, the option character found is placed in) -2.899 F F3(OPT)2.899 E(ARG)-.81 E F0 .399(and no)2.649 F -(diagnostic message is printed.)144 657.6 Q 1.241(If a required ar)144 681.6 R -1.241(gument is not found, and)-.18 F F1(getopts)3.741 E F0 1.241 -(is not silent, a question mark \()3.741 F F1(?).833 E F0 3.742(\)i).833 G -3.742(sp)494.746 681.6 S 1.242(laced in)507.378 681.6 R F2(name)144 693.6 Q F0 -(,).18 E F1(OPT)3.357 E(ARG)-.9 E F0 .856 -(is unset, and a diagnostic message is printed.)3.357 F(If)5.856 E F1(getopts) -3.356 E F0 .856(is silent, then a colon)3.356 F(\()144 705.6 Q F1(:).833 E F0 -2.5(\)i).833 G 2.5(sp)160.936 705.6 S(laced in)172.326 705.6 Q F2(name)2.5 E F0 -(and)2.5 E F3(OPT)2.5 E(ARG)-.81 E F0(is set to the option character found.) -2.25 E F1(getopts)144 729.6 Q F0 2.392 -(normally parses the positional parameters, b)4.892 F 2.392(ut if more ar)-.2 F -2.393(guments are gi)-.18 F -.15(ve)-.25 G 4.893(ni).15 G(n)509.927 729.6 Q F2 -(ar)4.893 E(gs)-.37 E F0(,).27 E 170.955(GNU 1993)72 768 R(September 16)2.5 E -(4)535 768 Q EP -%%Page: 5 5 -%%BeginPageSetup -BP -%%EndPageSetup -/F0 10/Times-Roman@0 SF -.35(BA)72 48 S(SH_B).35 E(UIL)-.1 E 290.48 -(TINS\(1\) B)-.92 F(ASH_B)-.35 E(UIL)-.1 E(TINS\(1\))-.92 E/F1 10/Times-Bold@0 -SF(getopts)144 84 Q F0 .651(parses those instead.)3.151 F F1(getopts)5.651 E F0 -.651(returns true if an option, speci\214ed or unspeci\214ed, is found.)3.151 F -(It returns f)144 96 Q -(alse if the end of options is encountered or an error occurs.)-.1 E F1(hash) -108 112.8 Q F0([)2.5 E F1A F0 2.5(][)C/F2 10/Times-Italic@0 SF(name) -153.14 112.8 Q F0(])A -.15(Fo)144 124.8 S 2.819(re).15 G(ach)164.999 124.8 Q F2 -(name)2.819 E F0 2.819(,t).18 G .319 -(he full pathname of the command is determined and remembered.)211.637 124.8 R -(The)5.32 E F12.82 E F0(option)2.82 E .508(causes the shell to for)144 -136.8 R .508(get all remembered locations.)-.18 F .508(If no ar)5.508 F .508 -(guments are gi)-.18 F -.15(ve)-.25 G .507(n, information about).15 F .193 -(remembered commands is printed.)144 148.8 R .193(An ar)5.193 F .193(gument of) --.18 F F12.693 E F0 .194(disables option checking for the rest of the) -2.693 F(ar)144 160.8 Q 2.5(guments. The)-.18 F(return status is true unless a) -2.5 E F2(name)2.5 E F0(is not found or an ille)2.5 E -.05(ga)-.15 G 2.5(lo).05 -G(ption is supplied.)453.86 160.8 Q F1(help)108 177.6 Q F0([)2.5 E F2(pattern)A -F0(])A .991(Display helpful information about b)144 189.6 R .991 -(uiltin commands.)-.2 F(If)5.991 E F2(pattern)3.491 E F0 .991(is speci\214ed,) -3.491 F F1(help)3.491 E F0(gi)3.49 E -.15(ve)-.25 G 3.49(sd).15 G(etailed) -513.34 189.6 Q .408(help on all commands matching)144 201.6 R F2(pattern)2.909 -E F0 2.909(;o).24 G .409(therwise a list of the b)316.13 201.6 R .409 -(uiltins is printed.)-.2 F .409(The return sta-)5.409 F -(tus is 0 unless no command matches)144 213.6 Q F2(pattern)2.5 E F0(.).24 E F1 -(history)108 230.4 Q F0([)2.5 E F2(n)A F0(])A F1(history \255rwan)108 242.4 Q -F0([)2.5 E F2(\214lename)A F0(])A -.4(Wi)144 254.4 S .752 -(th no options, display the command history list with line numbers.).4 F .752 -(Lines listed with a)5.752 F F1(*)3.251 E F0(ha)3.251 E -.15(ve)-.2 G .375 -(been modi\214ed.)144 266.4 R .375(An ar)5.375 F .375(gument of)-.18 F F2(n) -2.875 E F0 .375(lists only the last)2.875 F F2(n)2.875 E F0 2.875(lines. If) -2.875 F 2.876(an)2.876 G .376(on-option ar)411.832 266.4 R .376 -(gument is supplied,)-.18 F .811 -(it is used as the name of the history \214le; if not, the v)144 278.4 R .811 -(alue of)-.25 F/F3 9/Times-Bold@0 SF(HISTFILE)3.311 E F0 .811(is used.)3.061 F -.811(Options, if sup-)5.811 F(plied, ha)144 290.4 Q .3 -.15(ve t)-.2 H -(he follo).15 E(wing meanings:)-.25 E F1144 302.4 Q F0 .598(Append the `) -180 302.4 R(`ne)-.74 E(w')-.25 E 3.098('h)-.74 G .598 -(istory lines \(history lines entered since the be)266.424 302.4 R .599 -(ginning of the current)-.15 F F1(bash)180 314.4 Q F0 -(session\) to the history \214le)2.5 E F1144 326.4 Q F0 .854(Read the hi\ -story lines not already read from the history \214le into the current history \ -list.)180 326.4 R .772 -(These are lines appended to the history \214le since the be)180 338.4 R .773 -(ginning of the current)-.15 F F1(bash)3.273 E F0(ses-)3.273 E(sion.)180 350.4 -Q F1144 362.4 Q F0 -(Read the contents of the history \214le and use them as the current history) -180 362.4 Q F1144 374.4 Q F0 -(Write the current history to the history \214le, o)180 374.4 Q -.15(ve)-.15 G -(rwriting the history \214le').15 E 2.5(sc)-.55 G(ontents.)474.4 374.4 Q .989 -(The return v)144 391.2 R .989(alue is 0 unless an ille)-.25 F -.05(ga)-.15 G -3.489(lo).05 G .989(ption is encountered or an error occurs while reading or) -308.662 391.2 R(writing the history \214le.)144 403.2 Q F1(jobs)108 420 Q F0([) -2.5 E F1(\255lnp)A F0 2.5(][)C F2(jobspec)A F0(... ])2.5 E F1(jobs \255x)108 -432 Q F2(command)2.5 E F0([)2.5 E F2(ar)2.5 E(gs)-.37 E F0(... ])2.5 E .297 -(The \214rst form lists the acti)144 444 R .598 -.15(ve j)-.25 H 2.798 -(obs. The).15 F F12.798 E F0 .298 -(option lists process IDs in addition to the normal infor)2.798 F(-)-.2 E .746 -(mation; the)144 456 R F13.246 E F0 .745 -(option lists only the process ID of the job')3.246 F 3.245(sp)-.55 G .745 -(rocess group leader)394.205 456 R 5.745(.T)-.55 G(he)487.25 456 Q F1 -3.245 E F0(option)3.245 E 2.08(displays only jobs that ha)144 468 R 2.38 -.15 -(ve c)-.2 H 2.081(hanged status since last noti\214ed.).15 F(If)7.081 E F2 -(jobspec)4.581 E F0 2.081(is gi)4.581 F -.15(ve)-.25 G 2.081(n, output is).15 F -.727(restricted to information about that job)144 480 R 5.727(.T)-.4 G .727 -(he return status is 0 unless an ille)316.282 480 R -.05(ga)-.15 G 3.227(lo).05 -G .726(ption is encoun-)474.108 480 R(tered or an ille)144 492 Q -.05(ga)-.15 G -(l).05 E F2(jobspec)2.5 E F0(is supplied.)2.5 E .607(If the)144 516 R F1 -3.107 E F0 .607(option is supplied,)3.107 F F1(jobs)3.107 E F0 .607 -(replaces an)3.107 F(y)-.15 E F2(jobspec)3.107 E F0 .607(found in)3.107 F F2 -(command)3.107 E F0(or)3.107 E F2(ar)3.107 E(gs)-.37 E F0 .607(with the corre-) -3.107 F(sponding process group ID, and e)144 528 Q -.15(xe)-.15 G(cutes).15 E -F2(command)2.5 E F0(passing it)2.5 E F2(ar)2.5 E(gs)-.37 E F0 2.5(,r).27 G -(eturning its e)418.56 528 Q(xit status.)-.15 E F1(kill)108 544.8 Q F0([)2.5 E -F1(-s sigspec)A F0(|)2.5 E F1(\255sigspec)2.5 E F0 2.5(][)C F2(pid)219.31 544.8 -Q F0(|)2.5 E F2(jobspec)2.5 E F0 2.5(].)C(..)277.97 544.8 Q F1(kill \255l)108 -556.8 Q F0([)2.5 E F2(signum)A F0(])A .943(Send the signal named by)144 568.8 R -F2(sigspec)3.443 E F0 .942(to the processes named by)3.443 F F2(pid)3.442 E F0 -(or)3.442 E F2(jobspec)3.442 E F0(.).31 E F2(sigspec)5.942 E F0 .942 -(is either a)3.442 F .908(signal name such as)144 580.8 R F3(SIGKILL)3.408 E F0 -.908(or a signal number)3.158 F 5.908(.I)-.55 G(f)359.638 580.8 Q F2(sigspec) -3.408 E F0 .908(is a signal name, the name is case)3.408 F(insensiti)144 592.8 -Q 2.43 -.15(ve a)-.25 H 2.13(nd may be gi).15 F -.15(ve)-.25 G 4.63(nw).15 G -2.13(ith or without the)279.67 592.8 R F3(SIG)4.63 E F0 4.629(pre\214x. If) -4.379 F F2(sigspec)4.629 E F0 2.129(is not present, then)4.629 F F3(SIGTERM)144 -604.8 Q F0 .813(is assumed.)3.063 F .813(An ar)5.813 F .813(gument of)-.18 F F1 -3.313 E F0 .814(lists the signal names.)3.313 F .814(If an)5.814 F 3.314 -(ya)-.15 G -.18(rg)450.232 604.8 S .814(uments are supplied).18 F(when)144 -616.8 Q F12.827 E F0 .327(is gi)2.827 F -.15(ve)-.25 G .327(n, the names\ - of the speci\214ed signals are listed, and the return status is 0.).15 F .326 -(An ar)5.326 F(gu-)-.18 E .484(ment of)144 628.8 R F12.984 E F0 .484 -(disables option checking for the rest of the ar)2.984 F(guments.)-.18 E F1 -(kill)5.485 E F0 .485(returns true if at least one)2.985 F(signal w)144 640.8 Q -(as successfully sent, or f)-.1 E(alse if an error occurs or an ille)-.1 E -.05 -(ga)-.15 G 2.5(lo).05 G(ption is encountered.)419.09 640.8 Q F1(let)108 657.6 Q -F2(ar)2.5 E(g)-.37 E F0([)2.5 E F2(ar)A(g)-.37 E F0(...])2.5 E(Each)144 669.6 Q -F2(ar)3.677 E(g)-.37 E F0 1.177(is an arithmetic e)3.677 F 1.177 -(xpression to be e)-.15 F -.25(va)-.25 G 1.177(luated \(see).25 F F3 1.176 -(ARITHMETIC EV)3.677 F(ALU)-1.215 E -.855(AT)-.54 G(ION).855 E/F4 9 -/Times-Roman@0 SF(\).)A F0 1.176(If the)5.676 F(last)144 681.6 Q F2(ar)2.5 E(g) --.37 E F0 -.25(eva)2.5 G(luates to 0,).25 E F1(let)2.5 E F0 -(returns 1; 0 is returned otherwise.)2.5 E F1(local)108 698.4 Q F0([)2.5 E F2 -(name)A F0([=)A F2(value)A F0 2.5(].)C(..])194.45 698.4 Q -.15(Fo)144 710.4 S -3.276(re).15 G .776(ach ar)165.456 710.4 R .776(gument, create a local v)-.18 F -.776(ariable named)-.25 F F2(name)3.276 E F0 3.276(,a).18 G .776(nd assign it) -380.784 710.4 R F2(value)3.276 E F0 5.777(.W).18 G(hen)470.729 710.4 Q F1 -(local)3.277 E F0 .777(is used)3.277 F .131(within a function, it causes the v) -144 722.4 R(ariable)-.25 E F2(name)2.631 E F0 .131(to ha)2.631 F .431 -.15 -(ve a v)-.2 H .13(isible scope restricted to that function and).15 F 170.955 -(GNU 1993)72 768 R(September 16)2.5 E(5)535 768 Q EP -%%Page: 6 6 -%%BeginPageSetup -BP -%%EndPageSetup -/F0 10/Times-Roman@0 SF -.35(BA)72 48 S(SH_B).35 E(UIL)-.1 E 290.48 -(TINS\(1\) B)-.92 F(ASH_B)-.35 E(UIL)-.1 E(TINS\(1\))-.92 E .232(its children.) -144 84 R -.4(Wi)5.232 G .232(th no operands,).4 F/F1 10/Times-Bold@0 SF(local) -2.733 E F0 .233(writes a list of local v)2.733 F .233 -(ariables to the standard output.)-.25 F .233(It is an)5.233 F .42 -(error to use)144 96 R F1(local)2.92 E F0 .42(when not within a function.)2.92 -F .42(The return status is 0 unless)5.42 F F1(local)2.92 E F0 .42 -(is used outside a)2.92 F(function, or an ille)144 108 Q -.05(ga)-.15 G(l).05 E -/F2 10/Times-Italic@0 SF(name)2.5 E F0(is supplied.)2.5 E F1(logout)108 124.8 Q -F0(Exit a login shell.)9.33 E F1(popd)108 141.6 Q F0([)2.5 E F1(+/\255n)A F0(]) -A(Remo)144 153.6 Q -.15(ve)-.15 G 2.799(se).15 G .299 -(ntries from the directory stack.)188.159 153.6 R -.4(Wi)5.299 G .299(th no ar) -.4 F .299(guments, remo)-.18 F -.15(ve)-.15 G 2.799(st).15 G .3 -(he top directory from the)438.82 153.6 R(stack, and performs a)144 165.6 Q F1 -(cd)2.5 E F0(to the ne)2.5 E 2.5(wt)-.25 G(op directory)291.22 165.6 Q(.)-.65 E -F1(+n)144 177.6 Q F0(remo)180 177.6 Q -.15(ve)-.15 G 2.849(st).15 G(he)219.209 -177.6 Q F2(n)2.849 E F0 .349(th entry counting from the left of the list sho)B -.349(wn by)-.25 F F1(dirs)2.848 E F0 2.848(,s)C .348(tarting with zero.)470.704 -177.6 R -.15(Fo)180 189.6 S 2.5(re).15 G(xample: `)200.53 189.6 Q(`popd +0') --.74 E 2.5('r)-.74 G(emo)286.06 189.6 Q -.15(ve)-.15 G 2.5(st).15 G -(he \214rst directory)321.59 189.6 Q 2.5(,`)-.65 G(`popd +1')394.63 189.6 Q 2.5 -('t)-.74 G(he second.)442.3 189.6 Q F1144 201.6 Q F0(remo)180 201.6 Q --.15(ve)-.15 G 2.501(st).15 G(he)218.861 201.6 Q F2(n)2.501 E F0 .001 -(th entry counting from the right of the list sho)B .001(wn by)-.25 F F1(dirs) -2.502 E F0 2.502(,s)C .002(tarting with zero.)471.396 201.6 R -.15(Fo)180 213.6 -S 2.5(re).15 G(xample: `)200.53 213.6 Q(`popd -0')-.74 E 2.5('r)-.74 G(emo) -283.75 213.6 Q -.15(ve)-.15 G 2.5(st).15 G(he last directory)319.28 213.6 Q 2.5 -(,`)-.65 G(`popd -1')390.65 213.6 Q 2.5('t)-.74 G(he ne)436.01 213.6 Q -(xt to last.)-.15 E .644(If the)144 230.4 R F1(popd)3.144 E F0 .644 -(command is successful, a)3.144 F F1(dirs)3.143 E F0 .643 -(is performed as well, and the return status is 0.)3.143 F F1(popd)5.643 E F0 -.57(returns f)144 242.4 R .57(alse if an ille)-.1 F -.05(ga)-.15 G 3.07(lo).05 -G .571(ption is encountered, the directory stack is empty)251.25 242.4 R 3.071 -(,an)-.65 G(on-e)469.319 242.4 Q .571(xistent direc-)-.15 F -(tory stack entry is speci\214ed, or the directory change f)144 254.4 Q(ails.) --.1 E F1(pushd)108 271.2 Q F0([)2.5 E F2(dir)A F0(])A F1(pushd +/\255n)108 -283.2 Q F0 .64(Adds a directory to the top of the directory stack, or rotates \ -the stack, making the ne)144 295.2 R 3.139(wt)-.25 G .639(op of the)503.172 -295.2 R 1.315(stack the current w)144 307.2 R 1.315(orking directory)-.1 F -6.315(.W)-.65 G 1.315(ith no ar)306.885 307.2 R 1.315(guments, e)-.18 F 1.316 -(xchanges the top tw)-.15 F 3.816(od)-.1 G 1.316(irectories and)484.534 307.2 R -(returns 0, unless the directory stack is empty)144 319.2 Q(.)-.65 E F1(+n)144 -331.2 Q F0 1.268(Rotates the stack so that the)180 331.2 R F2(n)3.768 E F0 -1.267(th directory \(counting from the left of the list sho)B 1.267(wn by)-.25 -F F1(dirs)180 343.2 Q F0 2.5(\)i)C 2.5(sa)205.28 343.2 S 2.5(tt)216.11 343.2 S -(he top.)224.17 343.2 Q F1144 355.2 Q F0(Rotates the stack so that the) -180 355.2 Q F2(n)2.5 E F0 -(th directory \(counting from the right\) is at the top.)A F1(dir)144 367.2 Q -F0(adds)180 367.2 Q F2(dir)2.5 E F0 -(to the directory stack at the top, making it the ne)2.5 E 2.5(wc)-.25 G -(urrent w)422.5 367.2 Q(orking directory)-.1 E(.)-.65 E .488(If the)144 384 R -F1(pushd)2.988 E F0 .488(command is successful, a)2.988 F F1(dirs)2.988 E F0 -.488(is performed as well.)2.988 F .489(If the \214rst form is used,)5.488 F F1 -(pushd)2.989 E F0 1.103(returns 0 unless the cd to)144 396 R F2(dir)3.603 E F0 --.1(fa)3.603 G 3.603(ils. W).1 F 1.103(ith the second form,)-.4 F F1(pushd) -3.603 E F0 1.103(returns 0 unless the directory)3.603 F .846(stack is empty)144 -408 R 3.346(,an)-.65 G(on-e)220.894 408 Q .847(xistant directory stack element\ - is speci\214ed, or the directory change to the)-.15 F(speci\214ed ne)144 420 Q -2.5(wc)-.25 G(urrent directory f)205.4 420 Q(ails.)-.1 E F1(pwd)108 436.8 Q F0 -.725(Print the absolute pathname of the current w)144 436.8 R .724 -(orking directory)-.1 F 5.724(.T)-.65 G .724(he path printed contains no sym-) -405.56 436.8 R .521(bolic links if the)144 448.8 R F13.021 E F0 .521 -(option to the)3.021 F F1(set)3.021 E F0 -.2(bu)3.021 G .521 -(iltin command is set.).2 F .521(See also the description of)5.521 F F1 -(nolinks)3.022 E F0(under)144 460.8 Q F1 .074(Shell V)2.574 F(ariables)-.92 E -F0(abo)2.574 E -.15(ve)-.15 G 2.574(\). The).15 F .074 -(return status is 0 unless an error occurs while reading the path-)2.574 F -(name of the current directory)144 472.8 Q(.)-.65 E F1 -.18(re)108 489.6 S(ad) -.18 E F0([)2.5 E F1A F0 2.5(][)C F2(name)152.39 489.6 Q F0(...])2.5 E -.036(One line is read from the standard input, and the \214rst w)144 501.6 R -.037(ord is assigned to the \214rst)-.1 F F2(name)2.537 E F0 2.537(,t).18 G -.037(he second)500.253 501.6 R -.1(wo)144 513.6 S .109(rd to the second).1 F F2 -(name)2.609 E F0 2.609(,a).18 G .109(nd so on, with lefto)254.045 513.6 R -.15 -(ve)-.15 G 2.609(rw).15 G .109(ords assigned to the last)354.18 513.6 R F2 -(name)2.609 E F0 5.109(.O).18 G .108(nly the char)489.444 513.6 R(-)-.2 E .143 -(acters in)144 525.6 R/F3 9/Times-Bold@0 SF(IFS)2.643 E F0 .143 -(are recognized as w)2.393 F .143(ord delimiters.)-.1 F .143(If no)5.143 F F2 -(names)2.643 E F0 .144(are supplied, the line read is assigned)2.643 F .194 -(to the v)144 537.6 R(ariable)-.25 E F3(REPL)2.694 E(Y)-.828 E/F4 9 -/Times-Roman@0 SF(.)A F0 .194 -(The return code is zero, unless end-of-\214le is encountered.)4.694 F .193 -(If the)5.193 F F12.693 E F0(option)2.693 E .444(is gi)144 549.6 R -.15 -(ve)-.25 G .444(n, a backslash-ne).15 F .444 -(wline pair is not ignored, and the backslash is considered to be part of the) --.25 F(line.)144 561.6 Q F1 -.18(re)108 578.4 S(adonly).18 E F0([)2.5 E F1 -A F0 2.5(][)C F2(name)169.62 578.4 Q F0(...])2.5 E F1 -.18(re)108 590.4 S -(adonly -p).18 E F0 .419(The gi)144 602.4 R -.15(ve)-.25 G(n).15 E F2(names) -2.919 E F0 .419(are mark)2.919 F .419(ed readonly and the v)-.1 F .419 -(alues of these)-.25 F F2(names)2.919 E F0 .418(may not be changed by sub-) -2.919 F .541(sequent assignment.)144 614.4 R .541(If the)5.541 F F13.041 -E F0 .541(option is supplied, the functions corresponding to the)3.041 F F2 -(names)3.042 E F0 .542(are so)3.042 F(mark)144 626.4 Q 3.037(ed. If)-.1 F .537 -(no ar)3.037 F .537(guments are gi)-.18 F -.15(ve)-.25 G .536(n, or if the).15 -F F13.036 E F0 .536(option is supplied, a list of all readonly names is) -3.036 F 2.501(printed. An)144 638.4 R(ar)2.501 E .002(gument of)-.18 F F1 -2.502 E F0 .002(disables option checking for the rest of the ar)2.502 F 2.502 -(guments. The)-.18 F .002(return sta-)2.502 F .192(tus is 0 unless an ille)144 -650.4 R -.05(ga)-.15 G 2.692(lo).05 G .192(ption is encountered, one of the) -247.732 650.4 R F2(names)2.691 E F0 .191(is not a le)2.691 F -.05(ga)-.15 G -2.691(ls).05 G .191(hell v)463.498 650.4 R .191(ariable name,)-.25 F(or)144 -662.4 Q F12.5 E F0(is supplied with a)2.5 E F2(name)2.5 E F0 -(that is not a function.)2.5 E F1 -.18(re)108 679.2 S(tur).18 E(n)-.15 E F0([) -2.5 E F2(n)A F0(])A .618(Causes a function to e)144 691.2 R .618 -(xit with the return v)-.15 F .618(alue speci\214ed by)-.25 F F2(n)3.118 E F0 -5.619(.I).24 G(f)404.557 691.2 Q F2(n)3.119 E F0 .619 -(is omitted, the return status is)3.119 F 1.335(that of the last command e)144 -703.2 R -.15(xe)-.15 G 1.335(cuted in the function body).15 F 6.335(.I)-.65 G -3.835(fu)387.48 703.2 S 1.335(sed outside a function, b)399.645 703.2 R 1.335 -(ut during)-.2 F -.15(exe)144 715.2 S .794(cution of a script by the).15 F F1 -(.)3.294 E F0(\()5.794 E F1(sour)A(ce)-.18 E F0 3.294(\)c)C .794 -(ommand, it causes the shell to stop e)309.832 715.2 R -.15(xe)-.15 G .795 -(cuting that script).15 F 1.234(and return either)144 727.2 R F2(n)3.734 E F0 -1.234(or the e)3.734 F 1.234(xit status of the last command e)-.15 F -.15(xe) --.15 G 1.234(cuted within the script as the e).15 F(xit)-.15 E 170.955 -(GNU 1993)72 768 R(September 16)2.5 E(6)535 768 Q EP -%%Page: 7 7 -%%BeginPageSetup -BP -%%EndPageSetup -/F0 10/Times-Roman@0 SF -.35(BA)72 48 S(SH_B).35 E(UIL)-.1 E 290.48 -(TINS\(1\) B)-.92 F(ASH_B)-.35 E(UIL)-.1 E(TINS\(1\))-.92 E .393 -(status of the script.)144 84 R .393 -(If used outside a function and not during e)5.393 F -.15(xe)-.15 G .393 -(cution of a script by).15 F/F1 10/Times-Bold@0 SF(.)2.893 E F0 2.893(,t).833 G -.393(he return)503.787 84 R(status is f)144 96 Q(alse.)-.1 E F1(set)108 112.8 Q -F0([)2.5 E F1(\255\255abefhkmnptuvxldCHP)A F0 2.5(][)C F1(-o)243.29 112.8 Q/F2 -10/Times-Italic@0 SF(option)2.5 E F0 2.5(][)C F2(ar)288.84 112.8 Q(g)-.37 E F0 -(...])2.5 E F1144 124.8 Q F0 1.036(Automatically mark v)184 124.8 R 1.036 -(ariables which are modi\214ed or created for e)-.25 F 1.035(xport to the en) --.15 F(viron-)-.4 E(ment of subsequent commands.)184 136.8 Q F1144 148.8 -Q F0 .721 -(Cause the status of terminated background jobs to be reported immediately)184 -148.8 R 3.221(,r)-.65 G .721(ather than)499.569 148.8 R(before the ne)184 160.8 -Q(xt primary prompt.)-.15 E(\(Also see)5 E F1(notify)2.5 E F0(under)2.5 E F1 -(Shell V)2.5 E(ariables)-.92 E F0(abo)2.5 E -.15(ve)-.15 G(\).).15 E F1 -144 172.8 Q F0 1.772(Exit immediately if a)184 172.8 R F2(simple-command)4.272 -E F0(\(see)4.272 E/F3 9/Times-Bold@0 SF 1.772(SHELL GRAMMAR)4.272 F F0(abo) -4.022 E -.15(ve)-.15 G 4.271(\)e).15 G 1.771(xits with a)494.788 172.8 R .642 -(non\255zero status.)184 184.8 R .642(The shell does not e)5.642 F .642 -(xit if the command that f)-.15 F .643(ails is part of an)-.1 F F2(until)3.143 -E F0(or)3.143 E F2(while)184 196.8 Q F0 .728(loop, part of an)3.228 F F2(if) -3.228 E F0 .728(statement, part of a)3.228 F F1(&&)3.228 E F0(or)3.228 E/F4 10 -/Symbol SF 1.6663.228 G F0 .728(list, or if the command')1.562 F 3.228 -(sr)-.55 G(eturn)519.45 196.8 Q -.25(va)184 208.8 S(lue is being in).25 E -.15 -(ve)-.4 G(rted via).15 E F1(!)2.5 E F0(.)A F1144 220.8 Q F0 -(Disable pathname e)184 220.8 Q(xpansion.)-.15 E F1144 232.8 Q F0 .106 -(Locate and remember function commands as functions are de\214ned.)184 232.8 R -.106(Function commands)5.106 F(are normally look)184 244.8 Q -(ed up when the function is e)-.1 E -.15(xe)-.15 G(cuted.).15 E F1144 -256.8 Q F0 .162(All k)184 256.8 R -.15(ey)-.1 G -.1(wo).15 G .162(rd ar).1 F -.162(guments are placed in the en)-.18 F .161 -(vironment for a command, not just those that)-.4 F(precede the command name.) -184 268.8 Q F1144 280.8 Q F0 .009(Monitor mode.)184 280.8 R .009 -(Job control is enabled.)5.009 F .009(This \215ag is on by def)5.009 F .01 -(ault for interacti)-.1 F .31 -.15(ve s)-.25 H .01(hells on).15 F .124 -(systems that support it \(see)184 292.8 R F3 .124(JOB CONTR)2.624 F(OL)-.27 E -F0(abo)2.374 E -.15(ve)-.15 G 2.624(\). Background).15 F .124 -(processes run in a sep-)2.624 F .72 -(arate process group and a line containing their e)184 304.8 R .721 -(xit status is printed upon their comple-)-.15 F(tion.)184 316.8 Q F1144 -328.8 Q F0 .653(Read commands b)184 328.8 R .653(ut do not e)-.2 F -.15(xe)-.15 -G .653(cute them.).15 F .652(This may be used to check a shell script for)5.653 -F(syntax errors.)184 340.8 Q(This is ignored for interacti)5 E .3 -.15(ve s) --.25 H(hells.).15 E F1144 352.8 Q F2(option-name)2.5 E F0(The)184 364.8 Q -F2(option-name)2.5 E F0(can be one of the follo)2.5 E(wing:)-.25 E F1 -(allexport)184 376.8 Q F0(Same as)224 388.8 Q F12.5 E F0(.)A F1 -(braceexpand)184 400.8 Q F0 .312(The shell performs brace e)224 412.8 R .313 -(xpansion \(see)-.15 F F1 .313(Brace Expansion)2.813 F F0(abo)2.813 E -.15(ve) --.15 G 2.813(\). This).15 F .313(is on)2.813 F(by def)224 424.8 Q(ault.)-.1 E -F1(emacs)184 436.8 Q F0 .089(Use an emacs-style command line editing interf)224 -436.8 R 2.589(ace. This)-.1 F .089(is enabled by def)2.589 F(ault)-.1 E .128 -(when the shell is interacti)224 448.8 R -.15(ve)-.25 G 2.628(,u).15 G .128 -(nless the shell is started with the)345.89 448.8 R F1(\255nolineediting)2.629 -E F0(option.)224 460.8 Q F1(err)184 472.8 Q(exit)-.18 E F0(Same as)224 472.8 Q -F12.5 E F0(.)A F1(histexpand)184 484.8 Q F0(Same as)224 496.8 Q F1 -2.5 E F0(.)A F1(ignor)184 508.8 Q(eeof)-.18 E F0 1.024(The ef)224 520.8 R 1.024 -(fect is as if the shell command `IGNOREEOF=10' had been e)-.25 F -.15(xe)-.15 -G(cuted).15 E(\(see)224 532.8 Q F1(Shell V)2.5 E(ariables)-.92 E F0(abo)2.5 E --.15(ve)-.15 G(\).).15 E F1(interacti)184 544.8 Q -.1(ve)-.1 G(\255comments).1 -E F0(Allo)224 556.8 Q 2.52(waw)-.25 G .02(ord be)265.35 556.8 R .021 -(ginning with)-.15 F F1(#)2.521 E F0 .021(to cause that w)2.521 F .021 -(ord and all remaining characters)-.1 F -(on that line to be ignored in an interacti)224 568.8 Q .3 -.15(ve s)-.25 H -(hell \(see).15 E F3(COMMENTS)2.5 E F0(abo)2.25 E -.15(ve)-.15 G(\).).15 E F1 -(monitor)184 580.8 Q F0(Same as)5.56 E F12.5 E F0(.)A F1(noclob)184 592.8 -Q(ber)-.1 E F0(Same as)224 604.8 Q F12.5 E F0(.)A F1(noexec)184 616.8 Q -F0(Same as)224 616.8 Q F12.5 E F0(.)A F1(noglob)184 628.8 Q F0(Same as) -224 628.8 Q F12.5 E F0(.)A F1(nohash)184 640.8 Q F0(Same as)9.43 E F1 -2.5 E F0(.)A F1(notify)184 652.8 Q F0(Same as)224 652.8 Q F12.5 E -F0(.)A F1(nounset)184 664.8 Q F0(Same as)6.66 E F12.5 E F0(.)A F1(ph)184 -676.8 Q(ysical)-.15 E F0(Same as)5.14 E F12.5 E F0(.)A F1(posix)184 688.8 -Q F0 2.244(Change the beha)224 688.8 R 2.244(vior of bash where the def)-.2 F -2.243(ault operation dif)-.1 F 2.243(fers from the)-.25 F -(Posix 1003.2 standard to match the standard.)224 700.8 Q 170.955(GNU 1993)72 -768 R(September 16)2.5 E(7)535 768 Q EP -%%Page: 8 8 -%%BeginPageSetup -BP -%%EndPageSetup -/F0 10/Times-Roman@0 SF -.35(BA)72 48 S(SH_B).35 E(UIL)-.1 E 290.48 -(TINS\(1\) B)-.92 F(ASH_B)-.35 E(UIL)-.1 E(TINS\(1\))-.92 E/F1 10/Times-Bold@0 -SF(pri)184 84 Q(vileged)-.1 E F0(Same as)224 96 Q F12.5 E F0(.)A F1 -.1 -(ve)184 108 S(rbose).1 E F0(Same as)7.33 E F12.5 E F0(.)A F1(vi)184 120 Q -F0(Use a vi-style command line editing interf)224 120 Q(ace.)-.1 E F1(xtrace) -184 132 Q F0(Same as)224 132 Q F12.5 E F0(.)A(If no)184 144 Q/F2 10 -/Times-Italic@0 SF(option-name)2.5 E F0(is supplied, the v)2.5 E -(alues of the current options are printed.)-.25 E F1144 156 Q F0 -.45(Tu) -184 156 S .521(rn on).45 F F2(privile)3.021 E -.1(ge)-.4 G(d).1 E F0 3.021 -(mode. In)3.021 F .521(this mode, the)3.021 F F1($ENV)3.021 E F0 .522 -(\214le is not processed, and shell func-)3.021 F .26 -(tions are not inherited from the en)184 168 R 2.76(vironment. This)-.4 F .26 -(is enabled automatically on startup if)2.76 F .481(the ef)184 180 R(fecti)-.25 -E .781 -.15(ve u)-.25 H .482 -(ser \(group\) id is not equal to the real user \(group\) id.).15 F -.45(Tu) -5.482 G .482(rning this option).45 F(of)184 192 Q 2.5(fc)-.25 G(auses the ef) -202.35 192 Q(fecti)-.25 E .3 -.15(ve u)-.25 H -(ser and group ids to be set to the real user and group ids.).15 E F1144 -204 Q F0(Exit after reading and e)184 204 Q -.15(xe)-.15 G(cuting one command.) -.15 E F1144 216 Q F0 -.35(Tr)184 216 S .445(eat unset v).35 F .444 -(ariables as an error when performing parameter e)-.25 F 2.944(xpansion. If) --.15 F -.15(ex)2.944 G .444(pansion is).15 F .519(attempted on an unset v)184 -228 R .519(ariable, the shell prints an error message, and, if not interacti) --.25 F -.15(ve)-.25 G(,).15 E -.15(ex)184 240 S(its with a non\255zero status.) -.15 E F1144 252 Q F0(Print shell input lines as the)184 252 Q 2.5(ya)-.15 -G(re read.)306.63 252 Q F1144 264 Q F0 1.057(After e)184 264 R 1.056 -(xpanding each)-.15 F F2(simple-command)3.556 E F0(,).77 E F1(bash)3.556 E F0 -1.056(displays the e)3.556 F 1.056(xpanded v)-.15 F 1.056(alue of)-.25 F/F3 9 -/Times-Bold@0 SF(PS4)3.556 E/F4 9/Times-Roman@0 SF(,)A F0(fol-)3.306 E(lo)184 -276 Q(wed by the command and its e)-.25 E(xpanded ar)-.15 E(guments.)-.18 E F1 -144 288 Q F0(Sa)184 288 Q 1.398 -.15(ve a)-.2 H 1.098 -(nd restore the binding of).15 F F2(name)3.598 E F0 1.098(in a)3.598 F F1 -.25 -(fo)3.598 G(r).25 E F2(name)3.598 E F0([in)3.599 E F1 -.1(wo)3.599 G(rd).1 E F0 -3.599(]c)C 1.099(ommand \(see)451.687 288 R F3(SHELL)3.599 E(GRAMMAR)184 300 Q -F0(abo)2.25 E -.15(ve)-.15 G(\).).15 E F1144 312 Q F0 1.68 -(Disable the hashing of commands that are look)184 312 R 1.68(ed up for e)-.1 F --.15(xe)-.15 G 4.18(cution. Normally).15 F 4.18(,c)-.65 G(om-)523.89 312 Q -1.275(mands are remembered in a hash table, and once found, do not ha)184 324 R -1.576 -.15(ve t)-.2 H 3.776(ob).15 G 3.776(el)490.888 324 S(ook)501.884 324 Q -1.276(ed up)-.1 F(ag)184 336 Q(ain.)-.05 E F1144 348 Q F0 .812(The ef)184 -348 R .812(fect is as if the shell command `noclobber=' had been e)-.25 F -.15 -(xe)-.15 G .811(cuted \(see).15 F F1 .811(Shell V)3.311 F(ari-)-.92 E(ables)184 -360 Q F0(abo)2.5 E -.15(ve)-.15 G(\).).15 E F1144 372 Q F0(Enable)184 372 -Q F1(!)3.13 E F0 .63(style history substitution.)5.63 F .63 -(This \215ag is on by def)5.63 F .63(ault when the shell is interac-)-.1 F(ti) -184 384 Q -.15(ve)-.25 G(.).15 E F1144 396 Q F0 2.107 -(If set, do not follo)184 396 R 4.607(ws)-.25 G 2.107 -(ymbolic links when performing commands such as)279.835 396 R F1(cd)4.607 E F0 -(which)4.606 E(change the current directory)184 408 Q 5(.T)-.65 G(he ph)309.42 -408 Q(ysical directory is used instead.)-.05 E F1144 420 Q F0 .05 -(If no ar)184 420 R .05(guments follo)-.18 F 2.55(wt)-.25 G .05 -(his \215ag, then the positional parameters are unset.)280.98 420 R .05 -(Otherwise, the)5.05 F(positional parameters are set to the)184 432 Q F2(ar)2.5 -E(g)-.37 E F0(s, e)A -.15(ve)-.25 G 2.5(ni).15 G 2.5(fs)371.81 432 S -(ome of them be)381.53 432 Q(gin with a)-.15 E F12.5 E F0(.)A F1144 444 -Q F0 1.945(Signal the end of options, cause all remaining)184 444 R F2(ar)4.444 -E(g)-.37 E F0 4.444(st)C 4.444(ob)409.45 444 S 4.444(ea)423.894 444 S 1.944 -(ssigned to the positional)437.218 444 R 3.445(parameters. The)184 456 R F1 -3.445 E F0(and)3.445 E F13.445 E F0 .945(options are turned of) -3.445 F 3.445(f. If)-.25 F .946(there are no)3.445 F F2(ar)3.446 E(g)-.37 E F0 -.946(s, the positional)B(parameters remain unchanged.)184 468 Q .317 -(The \215ags are of)144 484.8 R 2.817(fb)-.25 G 2.817(yd)218.328 484.8 S(ef) -231.145 484.8 Q .317(ault unless otherwise noted.)-.1 F .316 -(Using + rather than \255 causes these \215ags to be)5.317 F .198(turned of)144 -496.8 R 2.698(f. The)-.25 F .199 -(\215ags can also be speci\214ed as options to an in)2.699 F -.2(vo)-.4 G .199 -(cation of the shell.).2 F .199(The current set)5.199 F .643 -(of \215ags may be found in)144 508.8 R F1<24ad>3.143 E F0 5.642(.A)C .642 -(fter the option ar)273.91 508.8 R .642(guments are processed, the remaining) --.18 F F2 3.142(na)3.142 G -.37(rg)512.238 508.8 S F0 3.142(sa).37 G(re)532.23 -508.8 Q .775(treated as v)144 520.8 R .775 -(alues for the positional parameters and are assigned, in order)-.25 F 3.275 -(,t)-.4 G(o)448.69 520.8 Q F1($1)3.275 E F0(,)A F1($2)3.275 E F0(,)A F1 3.275 -(... $)3.275 F F2(n)A F0 5.775(.I)C 3.275(fn)523.395 520.8 S(o)535 520.8 Q .309 -(options or)144 532.8 R F2(ar)2.809 E(g)-.37 E F0 2.808(sa)C .308 -(re supplied, all shell v)212.056 532.8 R .308(ariables are printed.)-.25 F -.308(The return status is al)5.308 F -.1(wa)-.1 G .308(ys true unless).1 F -(an ille)144 544.8 Q -.05(ga)-.15 G 2.5(lo).05 G(ption is encountered.)188.24 -544.8 Q F1(shift)108 561.6 Q F0([)2.5 E F2(n)A F0(])A .428 -(The positional parameters from)144 573.6 R F2(n)2.928 E F0 .429 -(+1 ... are renamed to)B F1 .429($1 ....)2.929 F F0 -.15(Pa)5.429 G .429 -(rameters represented by the num-).15 F(bers)144 585.6 Q F1($#)3.434 E F0(do) -3.434 E .934(wn to)-.25 F F1($#)3.434 E F0A F2(n)A F0 .934(+1 are unset.)B -(If)5.934 E F2(n)3.433 E F0 .933(is 0, no parameters are changed.)3.433 F(If) -5.933 E F2(n)3.433 E F0 .933(is not gi)3.433 F -.15(ve)-.25 G .933(n, it is).15 -F .026(assumed to be 1.)144 597.6 R F2(n)5.026 E F0 .026(must be a non-ne)2.526 -F -.05(ga)-.15 G(ti).05 E .326 -.15(ve n)-.25 H .026 -(umber less than or equal to).15 F F1($#)2.526 E F0 5.026(.I)C(f)454.886 597.6 -Q F2(n)2.526 E F0 .027(is greater than)2.527 F F1($#)2.527 E F0(,)A .03 -(the positional parameters are not changed.)144 609.6 R .029 -(The return status is greater than 0 if)5.03 F F2(n)2.529 E F0 .029 -(is greater than)2.529 F F1($#)2.529 E F0(or less than 0; otherwise 0.)144 -621.6 Q F1(suspend)108 638.4 Q F0([)2.5 E F1A F0(])A .492(Suspend the e) -144 650.4 R -.15(xe)-.15 G .492(cution of this shell until it recei).15 F -.15 -(ve)-.25 G 2.992(sa).15 G F3(SIGCONT).001 E F0 2.993(signal. The)2.743 F F1 -2.993 E F0 .493(option says not to)2.993 F .759 -(complain if this is a login shell; just suspend an)144 662.4 R(yw)-.15 E(ay) --.1 E 5.758(.T)-.65 G .758(he return status is 0 unless the shell is a)375.688 -662.4 R(login shell and)144 674.4 Q F12.5 E F0 -(is not supplied, or if job control is not enabled.)2.5 E F1(test)108 691.2 Q -F2 -.2(ex)2.5 G(pr).2 E F1([)108 703.2 Q F2 -.2(ex)2.5 G(pr).2 E F1(])2.5 E F0 -.877(Return a status of 0 \(true\) or 1 \(f)6.77 F .878 -(alse\) depending on the e)-.1 F -.25(va)-.25 G .878 -(luation of the conditional e).25 F(xpression)-.15 E F2 -.2(ex)144 715.2 S(pr) -.2 E F0 5.008(.E).73 G .008(xpressions may be unary or binary)175.918 715.2 R -5.007(.U)-.65 G .007(nary e)328.064 715.2 R .007 -(xpressions are often used to e)-.15 F .007(xamine the status)-.15 F .203 -(of a \214le.)144 727.2 R .203 -(There are string operators and numeric comparison operators as well.)5.203 F -.204(Each operator and)5.204 F 170.955(GNU 1993)72 768 R(September 16)2.5 E(8) -535 768 Q EP -%%Page: 9 9 -%%BeginPageSetup -BP -%%EndPageSetup -/F0 10/Times-Roman@0 SF -.35(BA)72 48 S(SH_B).35 E(UIL)-.1 E 290.48 -(TINS\(1\) B)-.92 F(ASH_B)-.35 E(UIL)-.1 E(TINS\(1\))-.92 E 1.592 -(operand must be a separate ar)144 84 R 4.091(gument. If)-.18 F/F1 10 -/Times-Italic@0 SF(\214le)4.091 E F0 1.591(is of the form /de)4.091 F(v/fd/) --.25 E F1(n)A F0 4.091(,t)C 1.591(hen \214le descriptor)444.756 84 R F1(n)4.091 -E F0(is)4.091 E(check)144 96 Q(ed.)-.1 E/F2 10/Times-Bold@0 SF144 108 Q -F1(\214le)2.5 E F0 -.35(Tr)180 108 S(ue if).35 E F1(\214le)2.5 E F0 -.15(ex)2.5 -G(ists and is block special.).15 E F2144 120 Q F1(\214le)2.5 E F0 -.35 -(Tr)180 120 S(ue if).35 E F1(\214le)2.5 E F0 -.15(ex)2.5 G -(ists and is character special.).15 E F2144 132 Q F1(\214le)2.5 E F0 -.35 -(Tr)180 132 S(ue if).35 E F1(\214le)2.5 E F0 -.15(ex)2.5 G -(ists and is a directory).15 E(.)-.65 E F2144 144 Q F1(\214le)2.5 E F0 --.35(Tr)180 144 S(ue if).35 E F1(\214le)2.5 E F0 -.15(ex)2.5 G(ists.).15 E F2 -144 156 Q F1(\214le)2.5 E F0 -.35(Tr)180 156 S(ue if).35 E F1(\214le)2.5 -E F0 -.15(ex)2.5 G(ists and is a re).15 E(gular \214le.)-.15 E F2144 168 -Q F1(\214le)2.5 E F0 -.35(Tr)180 168 S(ue if).35 E F1(\214le)2.5 E F0 -.15(ex) -2.5 G(ists and is set-group-id.).15 E F2144 180 Q F1(\214le)2.5 E F0 -.35 -(Tr)180 180 S(ue if).35 E F1(\214le)2.5 E F0(has its `)2.5 E(`stick)-.74 E(y') --.15 E 2.5('b)-.74 G(it set.)295.22 180 Q F2144 192 Q F1(\214le)2.5 E F0 --.35(Tr)8.91 G(ue if).35 E F1(\214le)2.5 E F0 -.15(ex)2.5 G -(ists and is a symbolic link.).15 E F2144 204 Q F1(\214le)2.5 E F0 -.35 -(Tr)180 204 S(ue if).35 E F1(\214le)2.5 E F0 -.15(ex)2.5 G -(ists and is a named pipe.).15 E F2144 216 Q F1(\214le)2.5 E F0 -.35(Tr) -180 216 S(ue if).35 E F1(\214le)2.5 E F0 -.15(ex)2.5 G(ists and is readable.) -.15 E F2144 228 Q F1(\214le)2.5 E F0 -.35(Tr)180 228 S(ue if).35 E F1 -(\214le)2.5 E F0 -.15(ex)2.5 G(ists and has a size greater than zero.).15 E F2 -144 240 Q F1(\214le)2.5 E F0 -.35(Tr)180 240 S(ue if).35 E F1(\214le)2.5 -E F0 -.15(ex)2.5 G(ists and is a sock).15 E(et.)-.1 E F2144 252 Q F1(fd) -2.5 E F0 -.35(Tr)180 252 S(ue if).35 E F1(fd)2.5 E F0(is opened on a terminal.) -2.5 E F2144 264 Q F1(\214le)2.5 E F0 -.35(Tr)180 264 S(ue if).35 E F1 -(\214le)2.5 E F0 -.15(ex)2.5 G(ists and its set-user).15 E(-id bit is set.)-.2 -E F2144 276 Q F1(\214le)2.5 E F0 -.35(Tr)8.36 G(ue if).35 E F1(\214le)2.5 -E F0 -.15(ex)2.5 G(ists and is writable.).15 E F2144 288 Q F1(\214le)2.5 -E F0 -.35(Tr)180 288 S(ue if).35 E F1(\214le)2.5 E F0 -.15(ex)2.5 G -(ists and is e).15 E -.15(xe)-.15 G(cutable.).15 E F2144 300 Q F1(\214le) -2.5 E F0 -.35(Tr)7.8 G(ue if).35 E F1(\214le)2.5 E F0 -.15(ex)2.5 G -(ists and is o).15 E(wned by the ef)-.25 E(fecti)-.25 E .3 -.15(ve u)-.25 H -(ser id.).15 E F2144 312 Q F1(\214le)2.5 E F0 -.35(Tr)7.8 G(ue if).35 E -F1(\214le)2.5 E F0 -.15(ex)2.5 G(ists and is o).15 E(wned by the ef)-.25 E -(fecti)-.25 E .3 -.15(ve g)-.25 H(roup id.).15 E F1(\214le1)144 324 Q F02.5 -E F2(nt)A F1(\214le2)2.5 E F0 -.35(Tr)180 336 S(ue if).35 E F1(\214le1)2.5 E F0 -(is ne)2.5 E(wer \(according to modi\214cation date\) than)-.25 E F1(\214le2) -2.5 E F0(.)A F1(\214le1)144 348 Q F02.5 E F2(ot)A F1(\214le2)2.5 E F0 -.35 -(Tr)180 360 S(ue if).35 E F1(\214le1)2.5 E F0(is older than \214le2.)2.5 E F1 -(\214le1)144 372 Q F2(\255ef)2.5 E F1(\214le)2.5 E F0 -.35(Tr)180 384 S(ue if) -.35 E F1(\214le1)2.5 E F0(and)2.5 E F1(\214le2)2.5 E F0(ha)2.5 E .3 -.15(ve t) --.2 H(he same de).15 E(vice and inode numbers.)-.25 E F2144 396 Q F1 -(string)2.5 E F0 -.35(Tr)180 408 S(ue if the length of).35 E F1(string)2.5 E F0 -(is zero.)2.5 E F2144 420 Q F1(string)2.5 E(string)144 432 Q F0 -.35(Tr) -180 432 S(ue if the length of).35 E F1(string)2.5 E F0(is non\255zero.)2.5 E F1 -(string1)144 444 Q F2(=)2.5 E F1(string2)2.5 E F0 -.35(Tr)180 456 S -(ue if the strings are equal.).35 E F1(string1)144 468 Q F2(!=)2.5 E F1 -(string2)2.5 E F0 -.35(Tr)180 480 S(ue if the strings are not equal.).35 E F2 -(!)144 492 Q F1 -.2(ex)2.5 G(pr).2 E F0 -.35(Tr)180 492 S(ue if).35 E F1 -.2 -(ex)2.5 G(pr).2 E F0(is f)2.5 E(alse.)-.1 E F1 -.2(ex)144 504 S(pr1).2 E F0 -2.5 E F2(a)A F1 -.2(ex)2.5 G(pr2).2 E F0 -.35(Tr)180 516 S(ue if both).35 E F1 --.2(ex)2.5 G(pr1).2 E F0(AND)2.5 E F1 -.2(ex)2.5 G(pr2).2 E F0(are true.)2.5 E -F1 -.2(ex)144 528 S(pr1).2 E F02.5 E F2(o)A F1 -.2(ex)2.5 G(pr2).2 E F0 --.35(Tr)180 540 S(ue if either).35 E F1 -.2(ex)2.5 G(pr1).2 E F0(OR)2.5 E F1 --.2(ex)2.5 G(pr2).2 E F0(is true.)2.5 E F1(ar)144 552 Q(g1)-.37 E F2(OP)2.5 E -F1(ar)2.5 E(g2)-.37 E/F3 9/Times-Bold@0 SF(OP)180 564 Q F0 .035(is one of)2.284 -F F2(\255eq)2.535 E F0(,)A F2(\255ne)2.535 E F0(,)A F2(\255lt)2.535 E F0(,)A F2 -(\255le)2.535 E F0(,)A F2(\255gt)2.535 E F0 2.535(,o)C(r)332.165 564 Q F2 -(\255ge)2.535 E F0 5.035(.T)C .035 -(hese arithmetic binary operators return true)366.815 564 R(if)180 576 Q F1(ar) -3.32 E(g1)-.37 E F0 .82(is equal, not-equal, less-than, less-than-or)3.32 F .82 -(-equal, greater)-.2 F .82(-than, or greater)-.2 F(-than-or)-.2 E(-)-.2 E .5 -(equal than)180 588 R F1(ar)3 E(g2)-.37 E F0 3.001(,r)C(especti)252.231 588 Q --.15(ve)-.25 G(ly).15 E(.)-.65 E F1(Ar)5.501 E(g1)-.37 E F0(and)3.001 E F1(ar) -3.001 E(g2)-.37 E F0 .501(may be positi)3.001 F .801 -.15(ve i)-.25 H(nte).15 E -.501(gers, ne)-.15 F -.05(ga)-.15 G(ti).05 E .801 -.15(ve i)-.25 H(nte).15 E -(gers,)-.15 E(or the special e)180 600 Q(xpression)-.15 E F22.5 E F1 -(string)2.5 E F0 2.5(,w)C(hich e)327.48 600 Q -.25(va)-.25 G -(luates to the length of).25 E F1(string)2.5 E F0(.).22 E F2(times)108 616.8 Q -F0 1.229(Print the accumulated user and system times for the shell and for pro\ -cesses run from the shell.)144 616.8 R(The return status is 0.)144 628.8 Q F2 -(trap)108 645.6 Q F0([)2.5 E F2A F0 2.5(][)C F1(ar)149.8 645.6 Q(g)-.37 E -F0 2.5(][)C F1(sigspec)172.48 645.6 Q F0(])A .767(The command)144 657.6 R F1 -(ar)3.267 E(g)-.37 E F0 .767(is to be read and e)3.267 F -.15(xe)-.15 G .767 -(cuted when the shell recei).15 F -.15(ve)-.25 G 3.267(ss).15 G(ignal\(s\)) -434.781 657.6 Q F1(sigspec)3.267 E F0 5.767(.I).31 G(f)509.945 657.6 Q F1(ar) -3.267 E(g)-.37 E F0(is)3.268 E 2.164(absent or)144 669.6 R F24.664 E F0 -4.664(,a)C 2.164(ll speci\214ed signals are reset to their original v)204.512 -669.6 R 2.164(alues \(the v)-.25 F 2.163(alues the)-.25 F 4.663(yh)-.15 G 2.163 -(ad upon)505.897 669.6 R .681(entrance to the shell\).)144 681.6 R(If)5.681 E -F1(ar)3.181 E(g)-.37 E F0 .681 -(is the null string this signal is ignored by the shell and by the com-)3.181 F -1.174(mands it in)144 693.6 R -.2(vo)-.4 G -.1(ke).2 G(s.).1 E F1(sigspec)6.174 -E F0 1.174(is either a signal name de\214ned in <)3.674 F F1(signal.h)A F0 -1.173(>, or a signal number)B 6.173(.I)-.55 G(f)536.67 693.6 Q F1(sigspec)144 -705.6 Q F0(is)2.769 E F3(EXIT)2.769 E F0 .269(\(0\) the command)2.519 F F1(ar) -2.769 E(g)-.37 E F0 .269(is e)2.769 F -.15(xe)-.15 G .269(cuted on e).15 F .269 -(xit from the shell.)-.15 F -.4(Wi)5.269 G .269(th no ar).4 F(guments,)-.18 E -F2(trap)2.77 E F0 .403 -(prints the list of commands associated with each signal number)144 717.6 R -5.402(.T)-.55 G(he)414.118 717.6 Q F22.902 E F0 .402 -(option causes the shell to)2.902 F .562 -(print a list of signal names and their corresponding numbers.)144 729.6 R .562 -(An ar)5.562 F .562(gument of)-.18 F F23.062 E F0 .562(disables option) -3.062 F 170.955(GNU 1993)72 768 R(September 16)2.5 E(9)535 768 Q EP -%%Page: 10 10 -%%BeginPageSetup -BP -%%EndPageSetup -/F0 10/Times-Roman@0 SF -.35(BA)72 48 S(SH_B).35 E(UIL)-.1 E 290.48 -(TINS\(1\) B)-.92 F(ASH_B)-.35 E(UIL)-.1 E(TINS\(1\))-.92 E .564 -(checking for the rest of the ar)144 84 R 3.064(guments. Signals)-.18 F .564 -(ignored upon entry to the shell cannot be trapped)3.064 F 1.144(or reset.)144 -96 R -.35(Tr)6.144 G 1.145(apped signals are reset to their original v).35 F -1.145(alues in a child process when it is created.)-.25 F -(The return status is f)144 108 Q(alse if either the trap name or number is in) --.1 E -.25(va)-.4 G(lid; otherwise).25 E/F1 10/Times-Bold@0 SF(trap)2.5 E F0 -(returns true.)2.5 E F1(type)108 124.8 Q F0([)2.5 E F1(\255all)A F0 2.5(][)C F1 -(\255type)157.58 124.8 Q F0(|)2.5 E F1(\255path)2.5 E F0(])A/F2 10 -/Times-Italic@0 SF(name)2.5 E F0([)2.5 E F2(name)A F0(...])2.5 E -.4(Wi)144 -136.8 S .206(th no options, indicate ho).4 F 2.706(we)-.25 G(ach)272.15 136.8 Q -F2(name)2.705 E F0 -.1(wo)2.705 G .205 -(uld be interpreted if used as a command name.).1 F .205(If the)5.205 F F1 -(\255type)144 148.8 Q F0 .527(\215ag is used,)3.027 F F1(type)3.027 E F0 .528 -(prints a phrase which is one of)3.028 F F2(alias)3.028 E F0(,).27 E F2 -.1(ke) -3.028 G(ywor)-.2 E(d)-.37 E F0(,).77 E F2(function)3.028 E F0(,).24 E F2 -.2 -(bu)3.028 G(iltin).2 E F0 3.028(,o).24 G(r)512.284 148.8 Q F2(\214le)3.028 E F0 -(if)3.028 E F2(name)144 160.8 Q F0 .297(is an alias, shell reserv)2.798 F .297 -(ed w)-.15 F .297(ord, function, b)-.1 F .297(uiltin, or disk \214le, respecti) --.2 F -.15(ve)-.25 G(ly).15 E 2.797(.I)-.65 G 2.797(ft)472.152 160.8 S .297 -(he name is not)481.059 160.8 R 1.097(found, then nothing is printed, and an e) -144 172.8 R 1.097(xit status of f)-.15 F 1.097(alse is returned.)-.1 F 1.097 -(If the)6.097 F F1(\255path)3.598 E F0 1.098(\215ag is used,)3.598 F F1(type) -144 184.8 Q F0 1.009(either returns the name of the disk \214le that w)3.509 F -1.008(ould be e)-.1 F -.15(xe)-.15 G 1.008(cuted if).15 F F2(name)3.508 E F0 -1.008(were speci\214ed as a)3.508 F .562(command name, or nothing if)144 196.8 -R F1(\255type)3.062 E F0 -.1(wo)3.062 G .562(uld not return).1 F F2(\214le) -3.063 E F0 5.563(.I).18 G 3.063(fac)389.542 196.8 S .563(ommand is hashed,) -407.878 196.8 R F1(\255path)3.063 E F0(prints)3.063 E .684(the hashed v)144 -208.8 R .684(alue, not necessarily the \214le that appears \214rst in)-.25 F/F3 -9/Times-Bold@0 SF -.666(PA)3.184 G(TH)-.189 E/F4 9/Times-Roman@0 SF(.)A F0 .684 -(If the)5.184 F F1(\255all)3.184 E F0 .683(\215ag is used,)3.184 F F1(type) -3.183 E F0 1.135(prints all of the places that contain an e)144 220.8 R -.15 -(xe)-.15 G 1.135(cutable named).15 F F2(name)3.635 E F0 6.136(.T).18 G 1.136 -(his includes aliases and func-)418.256 220.8 R 1.011 -(tions, if and only if the)144 232.8 R F1(\255path)3.511 E F0 1.011 -(\215ag is not also used.)3.511 F 1.011 -(The table of hashed commands is not con-)6.011 F .786(sulted when using)144 -244.8 R F1(\255all)3.286 E F0(.)A F1(type)5.786 E F0(accepts)3.286 E F1 -3.286 E F0(,)A F13.286 E F0 3.286(,a)C(nd)335.698 244.8 Q F13.286 E -F0 .787(in place of)3.287 F F1(\255all)3.287 E F0(,)A F1(\255type)3.287 E F0 -3.287(,a)C(nd)466.906 244.8 Q F1(\255path)3.287 E F0 3.287(,r)C(espec-)514.46 -244.8 Q(ti)144 256.8 Q -.15(ve)-.25 G(ly).15 E 6.127(.A)-.65 G 3.627(na)181.577 -256.8 S -.18(rg)194.644 256.8 S 1.127(ument of).18 F F13.627 E F0 1.127 -(disables option checking for the rest of the ar)3.627 F(guments.)-.18 E F1 -(type)6.126 E F0(returns)3.626 E(true if an)144 268.8 Q 2.5(yo)-.15 G 2.5(ft) -192.45 268.8 S(he ar)201.06 268.8 Q(guments are found, f)-.18 E -(alse if none are found.)-.1 E F1(ulimit)108 285.6 Q F0([)2.5 E F1 -(\255SHacdfmstpnuv)A F0([)2.5 E F2(limit)A F0(]])A F1(Ulimit)144 297.6 Q F0 -(pro)3.056 E .556(vides control o)-.15 F -.15(ve)-.15 G 3.057(rt).15 G .557 -(he resources a)266.316 297.6 R -.25(va)-.2 G .557 -(ilable to the shell and to processes started by it, on).25 F .765 -(systems that allo)144 309.6 R 3.265(ws)-.25 G .765(uch control.)226.325 309.6 -R .765(The v)5.765 F .765(alue of)-.25 F F2(limit)3.265 E F0 .765 -(can be a number in the unit speci\214ed for the)3.265 F .301 -(resource, or the v)144 321.6 R(alue)-.25 E F1(unlimited)2.801 E F0 5.301(.T)C -(he)288.565 321.6 Q F1(H)2.801 E F0(and)2.801 E F1(S)2.801 E F0 .302 -(options specify that the hard or soft limit is set for)2.802 F .005(the gi)144 -333.6 R -.15(ve)-.25 G 2.505(nr).15 G 2.505(esource. A)186.38 333.6 R .004(har\ -d limit cannot be increased once it is set; a soft limit may be increased up) -2.505 F .008(to the v)144 345.6 R .008(alue of the hard limit.)-.25 F .008 -(If neither)5.008 F F1(H)2.508 E F0(nor)2.508 E F1(S)2.508 E F0 .008 -(is speci\214ed, the command applies to the soft limit.)2.508 F(If)144 357.6 Q -F2(limit)2.758 E F0 .258(is omitted, the current v)2.758 F .257 -(alue of the soft limit of the resource is printed, unless the)-.25 F F1(H) -2.757 E F0(option)2.757 E .575(is gi)144 369.6 R -.15(ve)-.25 G 3.075(n. When) -.15 F .576(more than one resource is speci\214ed, the limit name and unit is p\ -rinted before the)3.076 F -.25(va)144 381.6 S 2.5(lue. Other).25 F -(options are interpreted as follo)2.5 E(ws:)-.25 E F1144 393.6 Q F0 -(all current limits are reported)180 393.6 Q F1144 405.6 Q F0 -(the maximum size of core \214les created)180 405.6 Q F1144 417.6 Q F0 -(the maximum size of a process')180 417.6 Q 2.5(sd)-.55 G(ata se)317.76 417.6 Q -(gment)-.15 E F1144 429.6 Q F0 -(the maximum size of \214les created by the shell)180 429.6 Q F1144 441.6 -Q F0(the maximum resident set size)180 441.6 Q F1144 453.6 Q F0 -(the maximum stack size)180 453.6 Q F1144 465.6 Q F0 -(the maximum amount of cpu time in seconds)180 465.6 Q F1144 477.6 Q F0 -(the pipe size in 512-byte blocks \(this may not be set\))180 477.6 Q F1 -144 489.6 Q F0 .164 -(the maximum number of open \214le descriptors \(most systems do not allo)180 -489.6 R 2.664(wt)-.25 G .164(his v)481.708 489.6 R .164(alue to be)-.25 F -(set, only displayed\))180 501.6 Q F1144 513.6 Q F0 -(the maximum number of processes a)180 513.6 Q -.25(va)-.2 G -(ilable to a single user).25 E F1144 525.6 Q F0 -(The maximum amount of virtual memory a)180 525.6 Q -.25(va)-.2 G -(ilable to the shell).25 E .778(An ar)144 542.4 R .778(gument of)-.18 F F1 -3.278 E F0 .778(disables option checking for the rest of the ar)3.278 F -3.279(guments. If)-.18 F F2(limit)3.279 E F0 .779(is gi)3.279 F -.15(ve)-.25 G -.779(n, it is).15 F .394(the ne)144 554.4 R 2.894(wv)-.25 G .394 -(alue of the speci\214ed resource \(the)183.168 554.4 R F12.893 E F0 .393 -(option is display only\).)2.893 F .393(If no option is gi)5.393 F -.15(ve)-.25 -G .393(n, then).15 F F1144 566.4 Q F0 .43(is assumed.)2.93 F -1.11(Va) -5.43 G .43(lues are in 1024-byte increments, e)1.11 F .431(xcept for)-.15 F F1 -2.931 E F0 2.931(,w)C .431(hich is in seconds,)421.315 566.4 R F1 -2.931 E F0 2.931(,w)C(hich)522.78 566.4 Q .828 -(is in units of 512-byte blocks, and)144 578.4 R F13.327 E F0(and)3.327 E -F13.327 E F0 3.327(,w)C .827(hich are unscaled v)344.784 578.4 R 3.327 -(alues. The)-.25 F .827(return status is 0)3.327 F .621(unless an ille)144 -590.4 R -.05(ga)-.15 G 3.121(lo).05 G .621 -(ption is encountered, a non-numeric ar)217.603 590.4 R .622(gument other than) --.18 F F1(unlimited)3.122 E F0 .622(is supplied)3.122 F(as)144 602.4 Q F2 -(limit)2.5 E F0 2.5(,o)C 2.5(ra)183.17 602.4 S 2.5(ne)193.44 602.4 S -(rror occurs while setting a ne)205.38 602.4 Q 2.5(wl)-.25 G(imit.)333.99 602.4 -Q F1(umask)108 619.2 Q F0([)2.5 E F1A F0 2.5(][)C F2(mode)162.59 619.2 Q -F0(])A .23(The user \214le-creation mask is set to)144 631.2 R F2(mode)2.73 E -F0 5.23(.I).18 G(f)323.21 631.2 Q F2(mode)2.73 E F0(be)2.729 E .229 -(gins with a digit, it is interpreted as an octal)-.15 F .066(number; otherwis\ -e it is interpreted as a symbolic mode mask similar to that accepted by)144 -643.2 R F2 -.15(ch)2.566 G(mod).15 E F0(\(1\).).77 E(If)144 655.2 Q F2(mode) -2.55 E F0 .05(is omitted, or if the)2.55 F F12.55 E F0 .049 -(option is supplied, the current v)2.55 F .049(alue of the mask is printed.) --.25 F(The)5.049 E F12.549 E F0 .475 -(option causes the mask to be printed in symbolic form; the def)144 667.2 R -.475(ault output is an octal number)-.1 F 5.475(.A)-.55 G(n)535 667.2 Q(ar)144 -679.2 Q .125(gument of)-.18 F F12.625 E F0 .125 -(disables option checking for the rest of the ar)2.625 F 2.624(guments. The) --.18 F .124(return status is 0 if the)2.624 F(mode w)144 691.2 Q -(as successfully changed or if no)-.1 E F2(mode)2.5 E F0(ar)2.5 E(gument w)-.18 -E(as supplied, and f)-.1 E(alse otherwise.)-.1 E 170.955(GNU 1993)72 768 R -(September 16)2.5 E(10)530 768 Q EP -%%Page: 11 11 -%%BeginPageSetup -BP -%%EndPageSetup -/F0 10/Times-Roman@0 SF -.35(BA)72 48 S(SH_B).35 E(UIL)-.1 E 290.48 -(TINS\(1\) B)-.92 F(ASH_B)-.35 E(UIL)-.1 E(TINS\(1\))-.92 E/F1 10/Times-Bold@0 -SF(unalias)108 84 Q F0<5bad>2.5 E F1(a)A F0 2.5(][)C/F2 10/Times-Italic@0 SF -(name)164.2 84 Q F0(...])2.5 E(Remo)144 96 Q -.15(ve)-.15 G F2(name)2.882 E F0 -2.732(sf)C .232(rom the list of de\214ned aliases.)211.374 96 R(If)5.232 E F1 -2.733 E F0 .233(is supplied, all alias de\214nitions are remo)2.733 F --.15(ve)-.15 G(d.).15 E(The return v)144 108 Q(alue is true unless a supplied) --.25 E F2(name)2.5 E F0(is not a de\214ned alias.)2.5 E F1(unset)108 124.8 Q F0 -<5bad>2.5 E F1(fv)A F0 2.5(][)C F2(name)159.74 124.8 Q F0(...])2.5 E -.15(Fo) -144 136.8 S 2.773(re).15 G(ach)164.953 136.8 Q F2(name)2.773 E F0 2.773(,r).18 -G(emo)212.049 136.8 Q .573 -.15(ve t)-.15 H .273(he corresponding v).15 F .273 -(ariable or)-.25 F 2.773(,g)-.4 G -2.15 -.25(iv e)369.094 136.8 T 2.773(nt).25 -G(he)391.467 136.8 Q F12.773 E F0 .273(option, function.)2.773 F .272 -(An ar)5.272 F(gument)-.18 E(of)144 148.8 Q F12.58 E F0 .08 -(disables option checking for the rest of the ar)2.58 F 2.58(guments. Note)-.18 -F(that)2.58 E/F3 9/Times-Bold@0 SF -.666(PA)2.58 G(TH)-.189 E/F4 9 -/Times-Roman@0 SF(,)A F3(IFS)2.33 E F4(,)A F3(PPID)2.33 E F4(,)A F3(PS1)2.331 E -F4(,)A F3(PS2)2.331 E F4(,)A F3(UID)144 160.8 Q F4(,)A F0(and)4.074 E F3(EUID) -4.324 E F0 1.824(cannot be unset.)4.074 F 1.824(If an)6.824 F 4.323(yo)-.15 G -(f)321.938 160.8 Q F3(RANDOM)4.323 E F4(,)A F3(SECONDS)4.073 E F4(,)A F3 -(LINENO)4.073 E F4(,)A F0(or)4.073 E F3(HISTCMD)4.323 E F0(are)4.073 E .328 -(unset, the)144 172.8 R 2.828(yl)-.15 G .328(ose their special properties, e) -193.116 172.8 R -.15(ve)-.25 G 2.828(ni).15 G 2.828(ft)330.436 172.8 S(he) -339.374 172.8 Q 2.828(ya)-.15 G .328(re subsequently reset.)360.932 172.8 R -.328(The e)5.328 F .329(xit status is true)-.15 F(unless a)144 184.8 Q F2(name) -2.5 E F0(does not e)2.5 E(xist or is non-unsettable.)-.15 E F1(wait)108 201.6 Q -F0([)2.5 E F2(n)A F0(])A -.8(Wa)144 213.6 S 1.061 -(it for the speci\214ed process and return its termination status.).8 F F2(n) -6.061 E F0 1.06(may be a process ID or a job)3.56 F .753 -(speci\214cation; if a job spec is gi)144 225.6 R -.15(ve)-.25 G .754 -(n, all processes in that job').15 F 3.254(sp)-.55 G .754(ipeline are w)404.012 -225.6 R .754(aited for)-.1 F 5.754(.I)-.55 G(f)502.458 225.6 Q F2(n)3.254 E F0 -.754(is not)3.254 F(gi)144 237.6 Q -.15(ve)-.25 G .027(n, all currently acti) -.15 F .327 -.15(ve c)-.25 H .027(hild processes are w).15 F .027(aited for)-.1 -F 2.526(,a)-.4 G .026(nd the return status is zero.)375.932 237.6 R(If)5.026 E -F2(n)2.526 E F0(speci\214es)2.526 E 2.595(an)144 249.6 S(on-e)156.035 249.6 Q -.095(xistant process or job, the return status is 127.)-.15 F .096 -(Otherwise, the return status is the e)5.095 F .096(xit status)-.15 F -(of the last process or job w)144 261.6 Q(aited for)-.1 E(.)-.55 E F3(SEE ALSO) -72 278.4 Q F0(bash\(1\), sh\(1\))108 290.4 Q 170.955(GNU 1993)72 768 R -(September 16)2.5 E(11)530 768 Q EP -%%Trailer -end -%%EOF diff --git a/documentation/builtins.txt b/documentation/builtins.txt deleted file mode 100644 index 3df6380..0000000 --- a/documentation/builtins.txt +++ /dev/null @@ -1,1188 +0,0 @@ - - - -BASH_BUILTINS(1) USER COMMANDS BASH_BUILTINS(1) - - - -NAME - bash, :, ., alias, bg, bind, break, builtin, bye, case, cd, - command, continue, declare, dirs, echo, enable, eval, exec, - exit, export, fc, fg, for, getopts, hash, help, history, if, - jobs, kill, let, local, logout, popd, pushd, pwd, read, - readonly, return, set, shift, source, suspend, test, times, - trap, type, typeset, ulimit, umask, unalias, unset, until, - wait, while - bash built-in commands, see bash(1) - -BASH BUILTIN COMMANDS - : [_a_r_g_u_m_e_n_t_s] - No effect; the command does nothing beyond expanding - _a_r_g_u_m_e_n_t_s and performing any specified redirections. A - zero exit code is returned. - - . _f_i_l_e_n_a_m_e [_a_r_g_u_m_e_n_t_s] - source _f_i_l_e_n_a_m_e [_a_r_g_u_m_e_n_t_s] - Read and execute commands from _f_i_l_e_n_a_m_e in the current - shell environment and return the exit status of the - last command executed from _f_i_l_e_n_a_m_e. If _f_i_l_e_n_a_m_e does - not contain a slash, pathnames in PATH are used to find - the directory containing _f_i_l_e_n_a_m_e. The file searched - for in PATH need not be executable. The current direc- - tory is searched if no file is found in PATH. If any - _a_r_g_u_m_e_n_t_s are supplied, they become the positional - parameters when _f_i_l_e is executed. Otherwise the posi- - tional parameters are unchanged. The return status is - the status of the last command exited within the script - (0 if no commands are executed), and false if _f_i_l_e_n_a_m_e - is not found. - - alias [_n_a_m_e[=_v_a_l_u_e] ...] - Alias with no arguments prints the list of aliases in - the form _n_a_m_e=_v_a_l_u_e on standard output. When arguments - are supplied, an alias is defined for each _n_a_m_e whose - _v_a_l_u_e is given. A trailing space in _v_a_l_u_e causes the - next word to be checked for alias substitution when the - alias is expanded. For each _n_a_m_e in the argument list - for which no _v_a_l_u_e is supplied, the name and value of - the alias is printed. Alias returns true unless a _n_a_m_e - is given for which no alias has been defined. - - bg [_j_o_b_s_p_e_c] - Place _j_o_b_s_p_e_c in the background, as if it had been - started with &. If _j_o_b_s_p_e_c is not present, the shell's - notion of the _c_u_r_r_e_n_t _j_o_b is used. bg _j_o_b_s_p_e_c returns - 0 unless run when job control is disabled or, when run - with job control enabled, if _j_o_b_s_p_e_c was not found or - started without job control. - - bind [-m _k_e_y_m_a_p] [-lvd] [-q _n_a_m_e] - bind [-m _k_e_y_m_a_p] -f _f_i_l_e_n_a_m_e - - - -GNU Last change: 1993 September 16 1 - - - - - - -BASH_BUILTINS(1) USER COMMANDS BASH_BUILTINS(1) - - - - bind [-m _k_e_y_m_a_p] _k_e_y_s_e_q:_f_u_n_c_t_i_o_n-_n_a_m_e - Display current readline key and function bindings, or - bind a key sequence to a readline function or macro. - The binding syntax accepted is identical to that of - ._i_n_p_u_t_r_c, but each binding must be passed as a separate - argument; e.g., '"\C-x\C-r": re-read-init-file'. - Options, if supplied, have the following meanings: - -m _k_e_y_m_a_p - Use _k_e_y_m_a_p as the keymap to be affected by the - subsequent bindings. Acceptable _k_e_y_m_a_p names are - _e_m_a_c_s, _e_m_a_c_s-_s_t_a_n_d_a_r_d, _e_m_a_c_s-_m_e_t_a, _e_m_a_c_s-_c_t_l_x, _v_i, - _v_i-_m_o_v_e, _v_i-_c_o_m_m_a_n_d, and _v_i-_i_n_s_e_r_t. _v_i is - equivalent to _v_i-_c_o_m_m_a_n_d; _e_m_a_c_s is equivalent to - _e_m_a_c_s-_s_t_a_n_d_a_r_d. - -l List the names of all readline functions - -v List current function names and bindings - -d Dump function names and bindings in such a way - that they can be re-read - -f _f_i_l_e_n_a_m_e - Read key bindings from _f_i_l_e_n_a_m_e - -q _f_u_n_c_t_i_o_n - Query about which keys invoke the named _f_u_n_c_t_i_o_n - - The return value is 0 unless an unrecognized option is - given or an error occurred. - - break [_n] - Exit from within a for, while, or until loop. If _n is - specified, break _n levels. _n must be >_ 1. If _n is - greater than the number of enclosing loops, all enclos- - ing loops are exited. The return value is 0 unless the - shell is not executing a loop when break is executed. - - builtin _s_h_e_l_l-_b_u_i_l_t_i_n [_a_r_g_u_m_e_n_t_s] - Execute the specified shell builtin, passing it _a_r_g_u_- - _m_e_n_t_s, and return its exit status. This is useful when - you wish to define a function whose name is the same as - a shell builtin, but need the functionality of the - builtin within the function itself. The cd builtin is - commonly redefined this way. The return status is - false if _s_h_e_l_l-_b_u_i_l_t_i_n is not a shell builtin command. - - cd [_d_i_r] - Change the current directory to _d_i_r. The variable HOME - is the default _d_i_r. The variable CDPATH defines the - search path for the directory containing _d_i_r. Alterna- - tive directory names are separated by a colon (:). A - null directory name in CDPATH is the same as the - current directory, i.e., ``.''. If _d_i_r begins with a - slash (/), then CDPATH is not used. An argument of - - is equivalent to $OLDPWD. The return value is true if - the directory was successfully changed; false - - - -GNU Last change: 1993 September 16 2 - - - - - - -BASH_BUILTINS(1) USER COMMANDS BASH_BUILTINS(1) - - - - otherwise. - - command [-pVv] _c_o_m_m_a_n_d [_a_r_g ...] - Run _c_o_m_m_a_n_d with _a_r_g_s suppressing the normal shell - function lookup. Only builtin commands or commands - found in the PATH are executed. If the -p option is - given, the search for _c_o_m_m_a_n_d is performed using a - default value for PATH that is guaranteed to find all - of the standard utilities. If either the -V or -v - option is supplied, a description of _c_o_m_m_a_n_d is - printed. The -v option causes a single word indicating - the command or pathname used to invoke _c_o_m_m_a_n_d to be - printed; the -V option produces a more verbose descrip- - tion. An argument of -- disables option checking for - the rest of the arguments. If the -V or -v option is - supplied, the exit status is 0 if _c_o_m_m_a_n_d was found, - and 1 if not. If neither option is supplied and an - error occurred or _c_o_m_m_a_n_d cannot be found, the exit - status is 127. Otherwise, the exit status of the com- - mand builtin is the exit status of _c_o_m_m_a_n_d. - - continue [_n] - Resume the next iteration of the enclosing for, while, - or until loop. If _n is specified, resume at the _nth - enclosing loop. _n must be >_ 1. If _n is greater than - the number of enclosing loops, the last enclosing loop - (the `top-level' loop) is resumed. The return value is - 0 unless the shell is not executing a loop when con- - tinue is executed. - - declare [-frxi] [_n_a_m_e[=_v_a_l_u_e]] - typeset [-frxi] [_n_a_m_e[=_v_a_l_u_e]] - Declare variables and/or give them attributes. If no - _n_a_m_es are given, then display the values of variables - instead. The options can be used to restrict output to - variables with the specified attribute. - -f Use function names only - -r Make _n_a_m_es readonly. These names cannot then be - assigned values by subsequent assignment state- - ments. - -x Mark _n_a_m_es for export to subsequent commands via - the environment. - -i The variable is treated as an integer; arithmetic - evaluation (see ARITHMETIC EVALUATION ) is per- - formed when the variable is assigned a value. - - Using `+' instead of `-' turns off the attribute - instead. When used in a function, makes _n_a_m_es local, - as with the local command. The return value is 0 - unless an illegal option is encountered, an attempt is - made to define a function using "-f foo=bar", one of - the _n_a_m_e_s is not a legal shell variable name, an - - - -GNU Last change: 1993 September 16 3 - - - - - - -BASH_BUILTINS(1) USER COMMANDS BASH_BUILTINS(1) - - - - attempt is made to turn off readonly status for a - readonly variable, or an attempt is made to display a - non-existant function with -f. - - dirs [-l] [+/-n] - Display the list of currently remembered directories. - Directories are added to the list with the pushd com- - mand; the popd command moves back up through the list. - +n displays the _nth entry counting from the left of - the list shown by dirs when invoked without - options, starting with zero. - -n displays the _nth entry counting from the right of - the list shown by dirs when invoked without - options, starting with zero. - -l produces a longer listing; the default listing - format uses a tilde to denote the home directory. - - The return value is 0 unless an illegal option is sup- - plied or _n indexes beyond the end of the directory - stack. - - echo [-neE] [_a_r_g ...] - Output the _a_r_gs, separated by spaces. The return - status is always 0. If -n is specified, the trailing - newline is suppressed. If the -e option is given, - interpretation of the following backslash-escaped char- - acters is enabled. The -E option disables the - interpretation of these escape characters, even on sys- - tems where they are interpreted by default. - \a alert (bell) - \b backspace - \c suppress trailing newline - \f form feed - \n new line - \r carriage return - \t horizontal tab - \v vertical tab - \\ backslash - \nnn the character whose ASCII code is _n_n_n (octal) - - enable [-n] [-all] [_n_a_m_e ...] - Enable and disable builtin shell commands. This allows - the execution of a disk command which has the same name - as a shell builtin without specifying a full pathname. - If -n is used, each _n_a_m_e is disabled; otherwise, _n_a_m_e_s - are enabled. For example, to use the test binary found - via the PATH instead of the shell builtin version, type - ``enable -n test''. If no arguments are given, a list - of all enabled shell builtins is printed. If only -n - is supplied, a list of all disabled builtins is - printed. If only -all is supplied, the list printed - includes all builtins, with an indication of whether or - - - -GNU Last change: 1993 September 16 4 - - - - - - -BASH_BUILTINS(1) USER COMMANDS BASH_BUILTINS(1) - - - - not each is enabled. enable accepts -a as a synonym - for -all. The return value is 0 unless a _n_a_m_e is not a - shell builtin. - - eval [_a_r_g ...] - The _a_r_gs are read and concatenated together into a sin- - gle command. This command is then read and executed by - the shell, and its exit status is returned as the value - of the eval command. If there are no _a_r_g_s, or only - null arguments, eval returns true. - - exec [[-] _c_o_m_m_a_n_d [_a_r_g_u_m_e_n_t_s]] - If _c_o_m_m_a_n_d is specified, it replaces the shell. No new - process is created. The _a_r_g_u_m_e_n_t_s become the arguments - to _c_o_m_m_a_n_d. If the first argument is -, the shell - places a dash in the zeroth arg passed to _c_o_m_m_a_n_d. - This is what login does. If the file cannot be exe- - cuted for some reason, a non-interactive shell exits, - unless the shell variable no_exit_on_failed_exec - exists, in which case it returns failure. An interac- - tive shell returns failure if the file cannot be exe- - cuted. If _c_o_m_m_a_n_d is not specified, any redirections - take effect in the current shell, and the return status - is 0. - - exit [_n] - Cause the shell to exit with a status of _n. If _n is - omitted, the exit status is that of the last command - executed. A trap on EXIT is executed before the shell - terminates. - - export [-nf] [_n_a_m_e[=_w_o_r_d]] ... - export -p - The supplied _n_a_m_e_s are marked for automatic export to - the environment of subsequently executed commands. If - the -f option is given, the _n_a_m_e_s refer to functions. - If no _n_a_m_e_s are given, or if the -p option is supplied, - a list of all names that are exported in this shell is - printed. The -n option causes the export property to - be removed from the named variables. An argument of -- - disables option checking for the rest of the arguments. - export returns an exit status of 0 unless an illegal - option is encountered, one of the _n_a_m_e_s is not a legal - shell variable name, or -f is supplied with a _n_a_m_e that - is not a function. - - fc [-e _e_n_a_m_e] [-nlr] [_f_i_r_s_t] [_l_a_s_t] - fc -s [_p_a_t=_r_e_p] [_c_m_d] - Fix Command. In the first form, a range of commands - from _f_i_r_s_t to _l_a_s_t is selected from the history list. - _F_i_r_s_t and _l_a_s_t may be specified as a string (to locate - the last command beginning with that string) or as a - - - -GNU Last change: 1993 September 16 5 - - - - - - -BASH_BUILTINS(1) USER COMMANDS BASH_BUILTINS(1) - - - - number (an index into the history list, where a nega- - tive number is used as an offset from the current com- - mand number). If _l_a_s_t is not specified it is set to - the current command for listing (so that fc -l -10 - prints the last 10 commands) and to _f_i_r_s_t otherwise. - If _f_i_r_s_t is not specified it is set to the previous - command for editing and -16 for listing. - - The -n flag suppresses the command numbers when list- - ing. The -r flag reverses the order of the commands. - If the -l flag is given, the commands are listed on - standard output. Otherwise, the editor given by _e_n_a_m_e - is invoked on a file containing those commands. If - _e_n_a_m_e is not given, the value of the FCEDIT variable is - used, and the value of EDITOR if FCEDIT is not set. If - neither variable is set, is used. When editing is com- - plete, the edited commands are echoed and executed. - - In the second form, _c_o_m_m_a_n_d is re-executed after each - instance of _p_a_t is replaced by _r_e_p. A useful alias to - use with this is ``r=fc -s'', so that typing ``r cc'' - runs the last command beginning with ``cc'' and typing - ``r'' re-executes the last command. - - If the first form is used, the return value is 0 unless - an illegal option is encountered or _f_i_r_s_t or _l_a_s_t - specify history lines out of range. If the -e option - is supplied, the return value is the value of the last - command executed or failure if an error occurs with the - temporary file of commands. If the second form is - used, the return status is that of the command re- - executed, unless _c_m_d does not specify a valid history - line, in which case fc returns failure. - - fg [_j_o_b_s_p_e_c] - Place _j_o_b_s_p_e_c in the foreground, and make it the - current job. If _j_o_b_s_p_e_c is not present, the shell's - notion of the _c_u_r_r_e_n_t _j_o_b is used. The return value is - that of the command placed into the foreground, or - failure if run when job control is disabled or, when - run with job control enabled, if _j_o_b_s_p_e_c does not - specify a valid job or _j_o_b_s_p_e_c specifies a job that was - started without job control. - - getopts _o_p_t_s_t_r_i_n_g _n_a_m_e [_a_r_g_s] - getopts is used by shell procedures to parse positional - parameters. _o_p_t_s_t_r_i_n_g contains the option letters to - be recognized; if a letter is followed by a colon, the - option is expected to have an argument, which should be - separated from it by white space. Each time it is - invoked, getopts places the next option in the shell - variable _n_a_m_e, initializing _n_a_m_e if it does not exist, - - - -GNU Last change: 1993 September 16 6 - - - - - - -BASH_BUILTINS(1) USER COMMANDS BASH_BUILTINS(1) - - - - and the index of the next argument to be processed into - the variable OPTIND. OPTIND is initialized to 1 each - time the shell or a shell script is invoked. When an - option requires an argument, getopts places that argu- - ment into the variable OPTARG. The shell does not - reset OPTIND automatically; it must be manually reset - between multiple calls to getopts within the same shell - invocation if a new set of parameters is to be used. - - getopts can report errors in two ways. If the first - character of _o_p_t_s_t_r_i_n_g is a colon, _s_i_l_e_n_t error report- - ing is used. In normal operation diagnostic messages - are printed when illegal options or missing option - arguments are encountered. If the variable OPTERR is - set to 0, no error message will be displayed, even if - the first character of _o_p_t_s_t_r_i_n_g is not a colon. - - If an illegal option is seen, getopts places ? into - _n_a_m_e and, if not silent, prints an error message and - unsets OPTARG. If getopts is silent, the option char- - acter found is placed in OPTARG and no diagnostic mes- - sage is printed. - - If a required argument is not found, and getopts is not - silent, a question mark (?) is placed in _n_a_m_e, OPTARG - is unset, and a diagnostic message is printed. If - getopts is silent, then a colon (:) is placed in _n_a_m_e - and OPTARG is set to the option character found. - - getopts normally parses the positional parameters, but - if more arguments are given in _a_r_g_s, getopts parses - those instead. getopts returns true if an option, - specified or unspecified, is found. It returns false - if the end of options is encountered or an error - occurs. - - hash [-r] [_n_a_m_e] - For each _n_a_m_e, the full pathname of the command is - determined and remembered. The -r option causes the - shell to forget all remembered locations. If no argu- - ments are given, information about remembered commands - is printed. An argument of -- disables option checking - for the rest of the arguments. The return status is - true unless a _n_a_m_e is not found or an illegal option is - supplied. - - help [_p_a_t_t_e_r_n] - Display helpful information about builtin commands. If - _p_a_t_t_e_r_n is specified, help gives detailed help on all - commands matching _p_a_t_t_e_r_n; otherwise a list of the - builtins is printed. The return status is 0 unless no - command matches _p_a_t_t_e_r_n. - - - -GNU Last change: 1993 September 16 7 - - - - - - -BASH_BUILTINS(1) USER COMMANDS BASH_BUILTINS(1) - - - - history [_n] - history -rwan [_f_i_l_e_n_a_m_e] - With no options, display the command history list with - line numbers. Lines listed with a * have been modi- - fied. An argument of _n lists only the last _n lines. - If a non-option argument is supplied, it is used as the - name of the history file; if not, the value of HISTFILE - is used. Options, if supplied, have the following - meanings: - -a Append the ``new'' history lines (history lines - entered since the beginning of the current bash - session) to the history file - -n Read the history lines not already read from the - history file into the current history list. These - are lines appended to the history file since the - beginning of the current bash session. - -r Read the contents of the history file and use them - as the current history - -w Write the current history to the history file, - overwriting the history file's contents. - - The return value is 0 unless an illegal option is - encountered or an error occurs while reading or writing - the history file. - - jobs [-lnp] [ _j_o_b_s_p_e_c ... ] - jobs -x _c_o_m_m_a_n_d [ _a_r_g_s ... ] - The first form lists the active jobs. The -l option - lists process IDs in addition to the normal informa- - tion; the -p option lists only the process ID of the - job's process group leader. The -n option displays - only jobs that have changed status since last notified. - If _j_o_b_s_p_e_c is given, output is restricted to informa- - tion about that job. The return status is 0 unless an - illegal option is encountered or an illegal _j_o_b_s_p_e_c is - supplied. - - If the -x option is supplied, jobs replaces any _j_o_b_s_p_e_c - found in _c_o_m_m_a_n_d or _a_r_g_s with the corresponding process - group ID, and executes _c_o_m_m_a_n_d passing it _a_r_g_s, return- - ing its exit status. - - kill [-s sigspec | -sigspec] [_p_i_d | _j_o_b_s_p_e_c] ... - kill -l [_s_i_g_n_u_m] - Send the signal named by _s_i_g_s_p_e_c to the processes named - by _p_i_d or _j_o_b_s_p_e_c. _s_i_g_s_p_e_c is either a signal name - such as SIGKILL or a signal number. If _s_i_g_s_p_e_c is a - signal name, the name is case insensitive and may be - given with or without the SIG prefix. If _s_i_g_s_p_e_c is - not present, then SIGTERM is assumed. An argument of - -l lists the signal names. If any arguments are sup- - plied when -l is given, the names of the specified - - - -GNU Last change: 1993 September 16 8 - - - - - - -BASH_BUILTINS(1) USER COMMANDS BASH_BUILTINS(1) - - - - signals are listed, and the return status is 0. An - argument of -- disables option checking for the rest of - the arguments. kill returns true if at least one sig- - nal was successfully sent, or false if an error occurs - or an illegal option is encountered. - - let _a_r_g [_a_r_g ...] - Each _a_r_g is an arithmetic expression to be evaluated - (see ARITHMETIC EVALUATION). If the last _a_r_g evaluates - to 0, let returns 1; 0 is returned otherwise. - - local [_n_a_m_e[=_v_a_l_u_e] ...] - For each argument, create a local variable named _n_a_m_e, - and assign it _v_a_l_u_e. When local is used within a func- - tion, it causes the variable _n_a_m_e to have a visible - scope restricted to that function and its children. - With no operands, local writes a list of local vari- - ables to the standard output. It is an error to use - local when not within a function. The return status is - 0 unless local is used outside a function, or an ille- - gal _n_a_m_e is supplied. - - logout - Exit a login shell. - - popd [+/-n] - Removes entries from the directory stack. With no - arguments, removes the top directory from the stack, - and performs a cd to the new top directory. - +n removes the _nth entry counting from the left of - the list shown by dirs, starting with zero. For - example: ``popd +0'' removes the first directory, - ``popd +1'' the second. - -n removes the _nth entry counting from the right of - the list shown by dirs, starting with zero. For - example: ``popd -0'' removes the last directory, - ``popd -1'' the next to last. - - If the popd command is successful, a dirs is performed - as well, and the return status is 0. popd returns - false if an illegal option is encountered, the direc- - tory stack is empty, a non-existent directory stack - entry is specified, or the directory change fails. - - pushd [_d_i_r] - pushd +/-n - Adds a directory to the top of the directory stack, or - rotates the stack, making the new top of the stack the - current working directory. With no arguments, - exchanges the top two directories and returns 0, unless - the directory stack is empty. - +n Rotates the stack so that the _nth directory - - - -GNU Last change: 1993 September 16 9 - - - - - - -BASH_BUILTINS(1) USER COMMANDS BASH_BUILTINS(1) - - - - (counting from the left of the list shown by dirs) - is at the top. - -n Rotates the stack so that the _nth directory - (counting from the right) is at the top. - dir adds _d_i_r to the directory stack at the top, making - it the new current working directory. - - If the pushd command is successful, a dirs is performed - as well. If the first form is used, pushd returns 0 - unless the cd to _d_i_r fails. With the second form, - pushd returns 0 unless the directory stack is empty, a - non-existant directory stack element is specified, or - the directory change to the specified new current - directory fails. - - pwd Print the absolute pathname of the current working - directory. The path printed contains no symbolic links - if the -P option to the set builtin command is set. - See also the description of nolinks under Shell Vari- - ables above). The return status is 0 unless an error - occurs while reading the pathname of the current direc- - tory. - - read [-r] [_n_a_m_e ...] - One line is read from the standard input, and the first - word is assigned to the first _n_a_m_e, the second word to - the second _n_a_m_e, and so on, with leftover words - assigned to the last _n_a_m_e. Only the characters in IFS - are recognized as word delimiters. If no _n_a_m_e_s are - supplied, the line read is assigned to the variable - REPLY. The return code is zero, unless end-of-file is - encountered. If the -r option is given, a backslash- - newline pair is not ignored, and the backslash is con- - sidered to be part of the line. - - readonly [-f] [_n_a_m_e ...] - readonly -p - The given _n_a_m_e_s are marked readonly and the values of - these _n_a_m_e_s may not be changed by subsequent assign- - ment. If the -f option is supplied, the functions - corresponding to the _n_a_m_e_s are so marked. If no argu- - ments are given, or if the -p option is supplied, a - list of all readonly names is printed. An argument of - -- disables option checking for the rest of the argu- - ments. The return status is 0 unless an illegal option - is encountered, one of the _n_a_m_e_s is not a legal shell - variable name, or -f is supplied with a _n_a_m_e that is - not a function. - - return [_n] - Causes a function to exit with the return value speci- - fied by _n. If _n is omitted, the return status is that - - - -GNU Last change: 1993 September 16 10 - - - - - - -BASH_BUILTINS(1) USER COMMANDS BASH_BUILTINS(1) - - - - of the last command executed in the function body. If - used outside a function, but during execution of a - script by the . (source) command, it causes the shell - to stop executing that script and return either _n or - the exit status of the last command executed within the - script as the exit status of the script. If used out- - side a function and not during execution of a script by - ., the return status is false. - - set [--abefhkmnptuvxldCHP] [-o _o_p_t_i_o_n] [_a_r_g ...] - -a Automatically mark variables which are modified - or created for export to the environment of - subsequent commands. - -b Cause the status of terminated background jobs - to be reported immediately, rather than before - the next primary prompt. (Also see notify - under Shell Variables above). - -e Exit immediately if a _s_i_m_p_l_e-_c_o_m_m_a_n_d (see SHELL - GRAMMAR above) exits with a non-zero status. - The shell does not exit if the command that - fails is part of an _u_n_t_i_l or _w_h_i_l_e loop, part - of an _i_f statement, part of a && or || list, or - if the command's return value is being inverted - via !. - -f Disable pathname expansion. - -h Locate and remember function commands as func- - tions are defined. Function commands are nor- - mally looked up when the function is executed. - -k All keyword arguments are placed in the - environment for a command, not just those that - precede the command name. - -m Monitor mode. Job control is enabled. This - flag is on by default for interactive shells on - systems that support it (see JOB CONTROL - above). Background processes run in a separate - process group and a line containing their exit - status is printed upon their completion. - -n Read commands but do not execute them. This - may be used to check a shell script for syntax - errors. This is ignored for interactive - shells. - -o _o_p_t_i_o_n-_n_a_m_e - The _o_p_t_i_o_n-_n_a_m_e can be one of the following: - allexport - Same as -a. - braceexpand - The shell performs brace expansion (see - Brace Expansion above). This is on by - default. - emacs Use an emacs-style command line editing - interface. This is enabled by default - when the shell is interactive, unless - - - -GNU Last change: 1993 September 16 11 - - - - - - -BASH_BUILTINS(1) USER COMMANDS BASH_BUILTINS(1) - - - - the shell is started with the -nol- - ineediting option. - errexit Same as -e. - histexpand - Same as -H. - ignoreeof - The effect is as if the shell command - `IGNOREEOF=10' had been executed (see - Shell Variables above). - interactive-comments - Allow a word beginning with # to cause - that word and all remaining characters - on that line to be ignored in an - interactive shell (see COMMENTS above). - monitor Same as -m. - noclobber - Same as -C. - noexec Same as -n. - noglob Same as -f. - nohash Same as -d. - notify Same as -b. - nounset Same as -u. - physical - Same as -P. - posix Change the behavior of bash where the - default operation differs from the - Posix 1003.2 standard to match the - standard. - privileged - Same as -p. - verbose Same as -v. - vi Use a vi-style command line editing - interface. - xtrace Same as -x. - If no _o_p_t_i_o_n-_n_a_m_e is supplied, the values of - the current options are printed. - -p Turn on _p_r_i_v_i_l_e_g_e_d mode. In this mode, the - $ENV file is not processed, and shell functions - are not inherited from the environment. This - is enabled automatically on startup if the - effective user (group) id is not equal to the - real user (group) id. Turning this option off - causes the effective user and group ids to be - set to the real user and group ids. - -t Exit after reading and executing one command. - -u Treat unset variables as an error when perform- - ing parameter expansion. If expansion is - attempted on an unset variable, the shell - prints an error message, and, if not interac- - tive, exits with a non-zero status. - -v Print shell input lines as they are read. - -x After expanding each _s_i_m_p_l_e-_c_o_m_m_a_n_d, bash - - - -GNU Last change: 1993 September 16 12 - - - - - - -BASH_BUILTINS(1) USER COMMANDS BASH_BUILTINS(1) - - - - displays the expanded value of PS4, followed by - the command and its expanded arguments. - -l Save and restore the binding of _n_a_m_e in a for - _n_a_m_e [in word] command (see SHELL GRAMMAR - above). - -d Disable the hashing of commands that are looked - up for execution. Normally, commands are - remembered in a hash table, and once found, do - not have to be looked up again. - -C The effect is as if the shell command - `noclobber=' had been executed (see Shell Vari- - ables above). - -H Enable ! style history substitution. This flag - is on by default when the shell is interactive. - -P If set, do not follow symbolic links when per- - forming commands such as cd which change the - current directory. The physical directory is - used instead. - -- If no arguments follow this flag, then the - positional parameters are unset. Otherwise, - the positional parameters are set to the _a_r_gs, - even if some of them begin with a -. - - Signal the end of options, cause all remaining - _a_r_gs to be assigned to the positional parame- - ters. The -x and -v options are turned off. - If there are no _a_r_gs, the positional parameters - remain unchanged. - - The flags are off by default unless otherwise noted. - Using + rather than - causes these flags to be turned - off. The flags can also be specified as options to an - invocation of the shell. The current set of flags may - be found in $-. After the option arguments are pro- - cessed, the remaining _n _a_r_gs are treated as values for - the positional parameters and are assigned, in order, - to $1, $2, ... $_n. If no options or _a_r_gs are supplied, - all shell variables are printed. The return status is - always true unless an illegal option is encountered. - - shift [_n] - The positional parameters from _n+1 ... are renamed to - $1 .... Parameters represented by the numbers $# down - to $#-_n+1 are unset. If _n is 0, no parameters are - changed. If _n is not given, it is assumed to be 1. _n - must be a non-negative number less than or equal to $#. - If _n is greater than $#, the positional parameters are - not changed. The return status is greater than 0 if _n - is greater than $# or less than 0; otherwise 0. - - suspend [-f] - Suspend the execution of this shell until it receives a - SIGCONT signal. The -f option says not to complain if - - - -GNU Last change: 1993 September 16 13 - - - - - - -BASH_BUILTINS(1) USER COMMANDS BASH_BUILTINS(1) - - - - this is a login shell; just suspend anyway. The return - status is 0 unless the shell is a login shell and -f is - not supplied, or if job control is not enabled. - - test _e_x_p_r - [ _e_x_p_r ] - Return a status of 0 (true) or 1 (false) depending on - the evaluation of the conditional expression _e_x_p_r. - Expressions may be unary or binary. Unary expressions - are often used to examine the status of a file. There - are string operators and numeric comparison operators - as well. Each operator and operand must be a separate - argument. If _f_i_l_e is of the form /dev/fd/_n, then file - descriptor _n is checked. - -b _f_i_l_e - True if _f_i_l_e exists and is block special. - -c _f_i_l_e - True if _f_i_l_e exists and is character special. - -d _f_i_l_e - True if _f_i_l_e exists and is a directory. - -e _f_i_l_e - True if _f_i_l_e exists. - -f _f_i_l_e - True if _f_i_l_e exists and is a regular file. - -g _f_i_l_e - True if _f_i_l_e exists and is set-group-id. - -k _f_i_l_e - True if _f_i_l_e has its ``sticky'' bit set. - -L _f_i_l_e - True if _f_i_l_e exists and is a symbolic link. - -p _f_i_l_e - True if _f_i_l_e exists and is a named pipe. - -r _f_i_l_e - True if _f_i_l_e exists and is readable. - -s _f_i_l_e - True if _f_i_l_e exists and has a size greater than - zero. - -S _f_i_l_e - True if _f_i_l_e exists and is a socket. - -t _f_d - True if _f_d is opened on a terminal. - -u _f_i_l_e - True if _f_i_l_e exists and its set-user-id bit is - set. - -w _f_i_l_e - True if _f_i_l_e exists and is writable. - -x _f_i_l_e - True if _f_i_l_e exists and is executable. - -O _f_i_l_e - True if _f_i_l_e exists and is owned by the effective - user id. - -G _f_i_l_e - - - -GNU Last change: 1993 September 16 14 - - - - - - -BASH_BUILTINS(1) USER COMMANDS BASH_BUILTINS(1) - - - - True if _f_i_l_e exists and is owned by the effective - group id. - _f_i_l_e_1 -nt _f_i_l_e_2 - True if _f_i_l_e_1 is newer (according to modification - date) than _f_i_l_e_2. - _f_i_l_e_1 -ot _f_i_l_e_2 - True if _f_i_l_e_1 is older than file2. - _f_i_l_e_1 -ef _f_i_l_e - True if _f_i_l_e_1 and _f_i_l_e_2 have the same device and - inode numbers. - -z _s_t_r_i_n_g - True if the length of _s_t_r_i_n_g is zero. - -n _s_t_r_i_n_g - _s_t_r_i_n_g - True if the length of _s_t_r_i_n_g is non-zero. - _s_t_r_i_n_g_1 = _s_t_r_i_n_g_2 - True if the strings are equal. - _s_t_r_i_n_g_1 != _s_t_r_i_n_g_2 - True if the strings are not equal. - ! _e_x_p_r - True if _e_x_p_r is false. - _e_x_p_r_1 -a _e_x_p_r_2 - True if both _e_x_p_r_1 AND _e_x_p_r_2 are true. - _e_x_p_r_1 -o _e_x_p_r_2 - True if either _e_x_p_r_1 OR _e_x_p_r_2 is true. - _a_r_g_1 OP _a_r_g_2 - OP is one of -eq, -ne, -lt, -le, -gt, or -ge. - These arithmetic binary operators return true if - _a_r_g_1 is equal, not-equal, less-than, less-than- - or-equal, greater-than, or greater-than-or-equal - than _a_r_g_2, respectively. _A_r_g_1 and _a_r_g_2 may be - positive integers, negative integers, or the spe- - cial expression -l _s_t_r_i_n_g, which evaluates to the - length of _s_t_r_i_n_g. - - times - Print the accumulated user and system times for the - shell and for processes run from the shell. The return - status is 0. - - trap [-l] [_a_r_g] [_s_i_g_s_p_e_c] - The command _a_r_g is to be read and executed when the - shell receives signal(s) _s_i_g_s_p_e_c. If _a_r_g is absent or - -, all specified signals are reset to their original - values (the values they had upon entrance to the - shell). If _a_r_g is the null string this signal is - ignored by the shell and by the commands it invokes. - _s_i_g_s_p_e_c is either a signal name defined in <_s_i_g_n_a_l._h>, - or a signal number. If _s_i_g_s_p_e_c is EXIT (0) the command - _a_r_g is executed on exit from the shell. With no argu- - ments, trap prints the list of commands associated with - each signal number. The -l option causes the shell to - - - -GNU Last change: 1993 September 16 15 - - - - - - -BASH_BUILTINS(1) USER COMMANDS BASH_BUILTINS(1) - - - - print a list of signal names and their corresponding - numbers. An argument of -- disables option checking - for the rest of the arguments. Signals ignored upon - entry to the shell cannot be trapped or reset. Trapped - signals are reset to their original values in a child - process when it is created. The return status is false - if either the trap name or number is invalid; otherwise - trap returns true. - - type [-all] [-type | -path] _n_a_m_e [_n_a_m_e ...] - With no options, indicate how each _n_a_m_e would be inter- - preted if used as a command name. If the -type flag is - used, type prints a phrase which is one of _a_l_i_a_s, _k_e_y_- - _w_o_r_d, _f_u_n_c_t_i_o_n, _b_u_i_l_t_i_n, or _f_i_l_e if _n_a_m_e is an alias, - shell reserved word, function, builtin, or disk file, - respectively. If the name is not found, then nothing is - printed, and an exit status of false is returned. If - the -path flag is used, type either returns the name of - the disk file that would be executed if _n_a_m_e were - specified as a command name, or nothing if -type would - not return _f_i_l_e. If a command is hashed, -path prints - the hashed value, not necessarily the file that appears - first in PATH. If the -all flag is used, type prints - all of the places that contain an executable named - _n_a_m_e. This includes aliases and functions, if and only - if the -path flag is not also used. The table of - hashed commands is not consulted when using -all. type - accepts -a, -t, and -p in place of -all, -type, and - -path, respectively. An argument of -- disables option - checking for the rest of the arguments. type returns - true if any of the arguments are found, false if none - are found. - - ulimit [-SHacdfmstpnuv [_l_i_m_i_t]] - Ulimit provides control over the resources available to - the shell and to processes started by it, on systems - that allow such control. The value of _l_i_m_i_t can be a - number in the unit specified for the resource, or the - value unlimited. The H and S options specify that the - hard or soft limit is set for the given resource. A - hard limit cannot be increased once it is set; a soft - limit may be increased up to the value of the hard - limit. If neither H nor S is specified, the command - applies to the soft limit. If _l_i_m_i_t is omitted, the - current value of the soft limit of the resource is - printed, unless the H option is given. When more than - one resource is specified, the limit name and unit is - printed before the value. Other options are inter- - preted as follows: - -a all current limits are reported - -c the maximum size of core files created - -d the maximum size of a process's data segment - - - -GNU Last change: 1993 September 16 16 - - - - - - -BASH_BUILTINS(1) USER COMMANDS BASH_BUILTINS(1) - - - - -f the maximum size of files created by the shell - -m the maximum resident set size - -s the maximum stack size - -t the maximum amount of cpu time in seconds - -p the pipe size in 512-byte blocks (this may not be - set) - -n the maximum number of open file descriptors (most - systems do not allow this value to be set, only - displayed) - -u the maximum number of processes available to a - single user - -v The maximum amount of virtual memory available to - the shell - - An argument of -- disables option checking for the rest - of the arguments. If _l_i_m_i_t is given, it is the new - value of the specified resource (the -a option is - display only). If no option is given, then -f is - assumed. Values are in 1024-byte increments, except - for -t, which is in seconds, -p, which is in units of - 512-byte blocks, and -n and -u, which are unscaled - values. The return status is 0 unless an illegal - option is encountered, a non-numeric argument other - than unlimited is supplied as _l_i_m_i_t, or an error occurs - while setting a new limit. - - umask [-S] [_m_o_d_e] - The user file-creation mask is set to _m_o_d_e. If _m_o_d_e - begins with a digit, it is interpreted as an octal - number; otherwise it is interpreted as a symbolic mode - mask similar to that accepted by _c_h_m_o_d(1). If _m_o_d_e is - omitted, or if the -S option is supplied, the current - value of the mask is printed. The -S option causes the - mask to be printed in symbolic form; the default output - is an octal number. An argument of -- disables option - checking for the rest of the arguments. The return - status is 0 if the mode was successfully changed or if - no _m_o_d_e argument was supplied, and false otherwise. - - unalias [-a] [_n_a_m_e ...] - Remove _n_a_m_es from the list of defined aliases. If -a - is supplied, all alias definitions are removed. The - return value is true unless a supplied _n_a_m_e is not a - defined alias. - - unset [-fv] [_n_a_m_e ...] - For each _n_a_m_e, remove the corresponding variable or, - given the -f option, function. An argument of -- dis- - ables option checking for the rest of the arguments. - Note that PATH, IFS, PPID, PS1, PS2, UID, and EUID can- - not be unset. If any of RANDOM, SECONDS, LINENO, or - HISTCMD are unset, they lose their special properties, - - - -GNU Last change: 1993 September 16 17 - - - - - - -BASH_BUILTINS(1) USER COMMANDS BASH_BUILTINS(1) - - - - even if they are subsequently reset. The exit status - is true unless a _n_a_m_e does not exist or is non- - unsettable. - - wait [_n] - Wait for the specified process and return its termina- - tion status. _n may be a process ID or a job specifica- - tion; if a job spec is given, all processes in that - job's pipeline are waited for. If _n is not given, all - currently active child processes are waited for, and - the return status is zero. If _n specifies a non- - existant process or job, the return status is 127. - Otherwise, the return status is the exit status of the - last process or job waited for. - -SEE ALSO - bash(1), sh(1) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -GNU Last change: 1993 September 16 18 - - - diff --git a/documentation/features.dvi b/documentation/features.dvi deleted file mode 100644 index 21e5327..0000000 Binary files a/documentation/features.dvi and /dev/null differ diff --git a/documentation/features.info b/documentation/features.info deleted file mode 100644 index 6398445..0000000 --- a/documentation/features.info +++ /dev/null @@ -1,3011 +0,0 @@ -This is Info file features.info, produced by Makeinfo-1.55 from the -input file features.texi. - -This text is a brief description of the features that are present in -the Bash shell. - -This is Edition 1.14, last updated 4 August 1994, -of `The GNU Bash Features Guide', -for `Bash', Version 1.14. - -Copyright (C) 1991, 1993 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 1, 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, 675 Mass Ave, Cambridge, MA 02139, USA. - - -File: features.info, Node: Top, Next: Bourne Shell Features, Prev: (DIR), Up: (DIR) - -Bash Features -************* - - Bash contains features that appear in other popular shells, and some -features that only appear in Bash. Some of the shells that Bash has -borrowed concepts from are the Bourne Shell (`sh'), the Korn Shell -(`ksh'), and the C-shell (`csh' and its successor, `tcsh'). The -following menu breaks the features up into categories based upon which -one of these other shells inspired the feature. - - This manual is meant as a brief introduction to features found in -Bash. The Bash manual page should be used as the definitive reference -on shell behavior. - -* Menu: - -* Bourne Shell Features:: Features originally found in the - Bourne shell. - -* Csh Features:: Features originally found in the - Berkeley C-Shell. - -* Korn Shell Features:: Features originally found in the Korn - Shell. - -* Bash Specific Features:: Features found only in Bash. - -* Job Control:: A chapter describing what job control is - and how bash allows you to use it. - -* Using History Interactively:: Chapter dealing with history expansion - rules. - -* Command Line Editing:: Chapter describing the command line - editing features. - -* Variable Index:: Quick reference helps you find the - variable you want. - -* Concept Index:: General index for this manual. - - -File: features.info, Node: Bourne Shell Features, Next: Csh Features, Prev: Top, Up: Top - -Bourne Shell Style Features -*************************** - - Bash is an acronym for Bourne Again SHell. The Bourne shell is the -traditional Unix shell originally written by Stephen Bourne. All of -the Bourne shell builtin commands are available in Bash, and the rules -for evaluation and quoting are taken from the Posix 1003.2 -specification for the `standard' Unix shell. - - This section briefly summarizes things which Bash inherits from the -Bourne shell: shell control structures, builtins, variables, and other -features. It also lists the significant differences between Bash and -the Bourne Shell. - -* Menu: - -* Looping Constructs:: Shell commands for iterative action. -* Conditional Constructs:: Shell commands for conditional execution. -* Shell Functions:: Grouping commands by name. -* Bourne Shell Builtins:: Builtin commands inherited from the Bourne - Shell. -* Bourne Shell Variables:: Variables which Bash uses in the same way - as the Bourne Shell. -* Other Bourne Shell Features:: Addtional aspects of Bash which behave in - the same way as the Bourne Shell. - - -File: features.info, Node: Looping Constructs, Next: Conditional Constructs, Up: Bourne Shell Features - -Looping Constructs -================== - - Note that wherever you see a `;' in the description of a command's -syntax, it may be replaced indiscriminately with one or more newlines. - - Bash supports the following looping constructs. - -`until' - The syntax of the `until' command is: - until TEST-COMMANDS; do CONSEQUENT-COMMANDS; done - Execute CONSEQUENT-COMMANDS as long as the final command in - TEST-COMMANDS has an exit status which is not zero. - -`while' - The syntax of the `while' command is: - while TEST-COMMANDS; do CONSEQUENT-COMMANDS; done - - Execute CONSEQUENT-COMMANDS as long as the final command in - TEST-COMMANDS has an exit status of zero. - -`for' - The syntax of the for command is: - - for NAME [in WORDS ...]; do COMMANDS; done - Execute COMMANDS for each member in WORDS, with NAME bound to the - current member. If "`in WORDS'" is not present, "`in "$@"'" is - assumed. - - -File: features.info, Node: Conditional Constructs, Next: Shell Functions, Prev: Looping Constructs, Up: Bourne Shell Features - -Conditional Constructs -====================== - -`if' - The syntax of the `if' command is: - - if TEST-COMMANDS; then - CONSEQUENT-COMMANDS; - [elif MORE-TEST-COMMANDS; then - MORE-CONSEQUENTS;] - [else ALTERNATE-CONSEQUENTS;] - fi - - Execute CONSEQUENT-COMMANDS only if the final command in - TEST-COMMANDS has an exit status of zero. Otherwise, each `elif' - list is executed in turn, and if its exit status is zero, the - corresponding MORE-CONSEQUENTS is executed and the command - completes. If "`else ALTERNATE-CONSEQUENTS'" is present, and the - final command in the final `if' or `elif' clause has a non-zero - exit status, then execute ALTERNATE-CONSEQUENTS. - -`case' - The syntax of the `case' command is: - - `case WORD in [PATTERN [| PATTERN]...) COMMANDS ;;]... esac' - - Selectively execute COMMANDS based upon WORD matching PATTERN. - The ``|'' is used to separate multiple patterns. - - Here is an example using `case' in a script that could be used to - describe an interesting feature of an animal: - - echo -n "Enter the name of an animal: " - read ANIMAL - echo -n "The $ANIMAL has " - case $ANIMAL in - horse | dog | cat) echo -n "four";; - man | kangaroo ) echo -n "two";; - *) echo -n "an unknown number of";; - esac - echo "legs." - - -File: features.info, Node: Shell Functions, Next: Bourne Shell Builtins, Prev: Conditional Constructs, Up: Bourne Shell Features - -Shell Functions -=============== - - Shell functions are a way to group commands for later execution -using a single name for the group. They are executed just like a -"regular" command. Shell functions are executed in the current shell -context; no new process is created to interpret them. - - Functions are declared using this syntax: - - [ `function' ] NAME () { COMMAND-LIST; } - - This defines a function named NAME. The BODY of the function is the -COMMAND-LIST between { and }. This list is executed whenever NAME is -specified as the name of a command. The exit status of a function is -the exit status of the last command executed in the body. - - When a function is executed, the arguments to the function become -the positional parameters during its execution. The special parameter -`#' that gives the number of positional parameters is updated to -reflect the change. Positional parameter 0 is unchanged. - - If the builtin command `return' is executed in a function, the -function completes and execution resumes with the next command after -the function call. When a function completes, the values of the -positional parameters and the special parameter `#' are restored to the -values they had prior to function execution. - - -File: features.info, Node: Bourne Shell Builtins, Next: Bourne Shell Variables, Prev: Shell Functions, Up: Bourne Shell Features - -Bourne Shell Builtins -===================== - - The following shell builtin commands are inherited from the Bourne -shell. These commands are implemented as specified by the Posix 1003.2 -standard. - -`:' - Do nothing beyond expanding any arguments and performing - redirections. - -`.' - Read and execute commands from the FILENAME argument in the - current shell context. - -`break' - Exit from a `for', `while', or `until' loop. - -`cd' - Change the current working directory. - -`continue' - Resume the next iteration of an enclosing `for', `while', or - `until' loop. - -`echo' - Print the arguments, separated by spaces, to the standard output. - -`eval' - The arguments are concatenated together into a single command, - which is then read and executed. - -`exec' - If a COMMAND argument is supplied, it replaces the shell. If no - COMMAND is specified, redirections may be used to affect the - current shell environment. - -`exit' - Exit the shell. - -`export' - Mark the arguments as variables to be passed to child processes in - the environment. - -`getopts' - Parse options to shell scripts or functions. - -`hash' - Remember the full pathnames of commands specified as arguments, so - they need not be searched for on subsequent invocations. - -`kill' - Send a signal to a process. - -`pwd' - Print the current working directory. - -`read' - Read a line from the shell input and use it to set the values of - specified variables. - -`readonly' - Mark variables as unchangable. - -`return' - Cause a shell function to exit with a specified value. - -`shift' - Shift positional parameters to the left. - -`test' -`[' - Evaluate a conditional expression. - -`times' - Print out the user and system times used by the shell and its - children. - -`trap' - Specify commands to be executed when the shell receives signals. - -`umask' - Set the shell process's file creation mask. - -`unset' - Cause shell variables to disappear. - -`wait' - Wait until child processes exit and report their exit status. - - -File: features.info, Node: Bourne Shell Variables, Next: Other Bourne Shell Features, Prev: Bourne Shell Builtins, Up: Bourne Shell Features - -Bourne Shell Variables -====================== - - Bash uses certain shell variables in the same way as the Bourne -shell. In some cases, Bash assigns a default value to the variable. - -`IFS' - A list of characters that separate fields; used when the shell - splits words as part of expansion. - -`PATH' - A colon-separated list of directories in which the shell looks for - commands. - -`HOME' - The current user's home directory. - -`CDPATH' - A colon-separated list of directories used as a search path for - the `cd' command. - -`MAILPATH' - A colon-separated list of files which the shell periodically checks - for new mail. You can also specify what message is printed by - separating the file name from the message with a `?'. When used - in the text of the message, `$_' stands for the name of the - current mailfile. - -`PS1' - The primary prompt string. - -`PS2' - The secondary prompt string. - -`OPTIND' - The index of the last option processed by the `getopts' builtin. - -`OPTARG' - The value of the last option argument processed by the `getopts' - builtin. - - -File: features.info, Node: Other Bourne Shell Features, Prev: Bourne Shell Variables, Up: Bourne Shell Features - -Other Bourne Shell Features -=========================== - -* Menu: - -* Major Differences from the Bourne Shell:: Major differences between - Bash and the Bourne shell. - - Bash implements essentially the same grammar, parameter and variable -expansion, redirection, and quoting as the Bourne Shell. Bash uses the -Posix 1003.2 standard as the specification of how these features are to -be implemented. There are some differences between the traditional -Bourne shell and the Posix standard; this section quickly details the -differences of significance. A number of these differences are -explained in greater depth in subsequent sections. - - -File: features.info, Node: Major Differences from the Bourne Shell, Up: Other Bourne Shell Features - -Major Differences from the Bourne Shell ---------------------------------------- - - Bash implements the `!' keyword to negate the return value of a -pipeline. Very useful when an `if' statement needs to act only if a -test fails. - - Bash includes brace expansion (*note Brace Expansion::.). - - Bash includes the Posix and `ksh'-style pattern removal `%%' and -`##' constructs to remove leading or trailing substrings from variables. - - The Posix and `ksh'-style `$()' form of command substitution is -implemented, and preferred to the Bourne shell's ```' (which is also -implemented for backwards compatibility). - - Variables present in the shell's initial environment are -automatically exported to child processes. The Bourne shell does not -normally do this unless the variables are explicitly marked using the -`export' command. - - The expansion `${#xx}', which returns the length of `$xx', is -supported. - - The `IFS' variable is used to split only the results of expansion, -not all words. This closes a longstanding shell security hole. - - It is possible to have a variable and a function with the same name; -`sh' does not separate the two name spaces. - - Bash functions are permitted to have local variables, and thus useful -recursive functions may be written. - - The `noclobber' option is available to avoid overwriting existing -files with output redirection. - - Bash allows you to write a function to override a builtin, and -provides access to that builtin's functionality within the function via -the `builtin' and `command' builtins. - - The `command' builtin allows selective disabling of functions when -command lookup is performed. - - Individual builtins may be enabled or disabled using the `enable' -builtin. - - Functions may be exported to children via the environment. - - The Bash `read' builtin will read a line ending in \ with the `-r' -option, and will use the `$REPLY' variable as a default if no arguments -are supplied. - - The `return' builtin may be used to abort execution of scripts -executed with the `.' or `source' builtins. - - The `umask' builtin allows symbolic mode arguments similar to those -accepted by `chmod'. - - The `test' builtin is slightly different, as it implements the Posix -1003.2 algorithm, which specifies the behavior based on the number of -arguments. - - -File: features.info, Node: Csh Features, Next: Korn Shell Features, Prev: Bourne Shell Features, Up: Top - -C-Shell Style Features -********************** - - The C-Shell ("`csh'") was created by Bill Joy at UC Berkeley. It is -generally considered to have better features for interactive use than -the original Bourne shell. Some of the `csh' features present in Bash -include job control, history expansion, `protected' redirection, and -several variables for controlling the interactive behaviour of the shell -(e.g. `IGNOREEOF'). - - *Note Using History Interactively:: for details on history expansion. - -* Menu: - -* Tilde Expansion:: Expansion of the ~ character. -* Brace Expansion:: Expansion of expressions within braces. -* C Shell Builtins:: Builtin commands adopted from the C Shell. -* C Shell Variables:: Variables which Bash uses in essentially - the same way as the C Shell. - - -File: features.info, Node: Tilde Expansion, Next: Brace Expansion, Up: Csh Features - -Tilde Expansion -=============== - - Bash has tilde (~) expansion, similar, but not identical, to that of -`csh'. The following table shows what unquoted words beginning with a -tilde expand to. - -`~' - The current value of `$HOME'. - -`~/foo' - `$HOME/foo' - -`~fred/foo' - The subdirectory `foo' of the home directory of the user `fred'. - -`~+/foo' - `$PWD/foo' - -`~-' - `$OLDPWD/foo' - - Bash will also tilde expand words following redirection operators -and words following `=' in assignment statements. - - -File: features.info, Node: Brace Expansion, Next: C Shell Builtins, Prev: Tilde Expansion, Up: Csh Features - -Brace Expansion -=============== - - Brace expansion is a mechanism by which arbitrary strings may be -generated. This mechanism is similar to PATHNAME EXPANSION (see the -Bash manual page for details), but the file names generated need not -exist. Patterns to be brace expanded take the form of an optional -PREAMBLE, followed by a series of comma-separated strings between a -pair of braces, followed by an optional POSTAMBLE. The preamble is -prepended to each string contained within the braces, and the postamble -is then appended to each resulting string, expanding left to right. - - Brace expansions may be nested. The results of each expanded string -are not sorted; left to right order is preserved. For example, - a{d,c,b}e - expands into ADE ACE ABE. - - Brace expansion is performed before any other expansions, and any -characters special to other expansions are preserved in the result. It -is strictly textual. Bash does not apply any syntactic interpretation -to the context of the expansion or the text between the braces. - - A correctly-formed brace expansion must contain unquoted opening and -closing braces, and at least one unquoted comma. Any incorrectly -formed brace expansion is left unchanged. - - This construct is typically used as shorthand when the common prefix -of the strings to be generated is longer than in the above example: - mkdir /usr/local/src/bash/{old,new,dist,bugs} - or - chown root /usr/{ucb/{ex,edit},lib/{ex?.?*,how_ex}} - - -File: features.info, Node: C Shell Builtins, Next: C Shell Variables, Prev: Brace Expansion, Up: Csh Features - -C Shell Builtins -================ - - Bash has several builtin commands whose definition is very similar -to `csh'. - -`pushd' - pushd [DIR | +N | -N] - - Save the current directory on a list and then `cd' to DIR. With no - arguments, exchanges the top two directories. - - `+N' - Brings the Nth directory (counting from the left of the list - printed by `dirs') to the top of the list by rotating the - stack. - - `-N' - Brings the Nth directory (counting from the right of the list - printed by `dirs') to the top of the list by rotating the - stack. - - `DIR' - Makes the current working directory be the top of the stack, - and then CDs to DIR. You can see the saved directory list - with the `dirs' command. - -`popd' - popd [+N | -N] - - Pops the directory stack, and `cd's to the new top directory. When - no arguments are given, removes the top directory from the stack - and `cd's to the new top directory. The elements are numbered - from 0 starting at the first directory listed with `dirs'; i.e. - `popd' is equivalent to `popd +0'. - `+N' - Removes the Nth directory (counting from the left of the list - printed by `dirs'), starting with zero. - - `-N' - Removes the Nth directory (counting from the right of the - list printed by `dirs'), starting with zero. - -`dirs' - dirs [+N | -N] [-L] - Display the list of currently remembered directories. Directories - find their way onto the list with the `pushd' command; you can get - back up through the list with the `popd' command. - `+N' - Displays the Nth directory (counting from the left of the - list printed by `dirs' when invoked without options), starting - with zero. - - `-N' - Displays the Nth directory (counting from the right of the - list printed by `dirs' when invoked without options), starting - with zero. - - `-L' - Produces a longer listing; the default listing format uses a - tilde to denote the home directory. - -`history' - history [N] [ [-w -r -a -n] [FILENAME]] - - Display the history list with line numbers. Lines prefixed with - with a `*' have been modified. An argument of N says to list only - the last N lines. Option `-w' means write out the current history - to the history file; `-r' means to read the current history file - and make its contents the history list. An argument of `-a' means - to append the new history lines (history lines entered since the - beginning of the current Bash session) to the history file. - Finally, the `-n' argument means to read the history lines not - already read from the history file into the current history list. - These are lines appended to the history file since the beginning - of the current Bash session. If FILENAME is given, then it is used - as the history file, else if `$HISTFILE' has a value, that is - used, otherwise `~/.bash_history' is used. - -`logout' - Exit a login shell. - -`source' - A synonym for `.' (*note Bourne Shell Builtins::.) - - -File: features.info, Node: C Shell Variables, Prev: C Shell Builtins, Up: Csh Features - -C Shell Variables -================= - -`IGNOREEOF' - If this variable is set, it represents the number of consecutive - `EOF's Bash will read before exiting. By default, Bash will exit - upon reading a single `EOF'. - -`cdable_vars' - If this variable is set, Bash treats arguments to the `cd' command - which are not directories as names of variables whose values are - the directories to change to. - - -File: features.info, Node: Korn Shell Features, Next: Bash Specific Features, Prev: Csh Features, Up: Top - -Korn Shell Style Features -************************* - - This section describes features primarily inspired by the Korn Shell -(`ksh'). In some cases, the Posix 1003.2 standard has adopted these -commands and variables from the Korn Shell; Bash implements those -features using the Posix standard as a guide. - -* Menu: - -* Korn Shell Constructs:: Shell grammar constructs adopted from the - Korn Shell -* Korn Shell Builtins:: Builtin commands adopted from the Korn Shell. -* Korn Shell Variables:: Variables which bash uses in essentially - the same way as the Korn Shell. -* Aliases:: Substituting one command for another. - - -File: features.info, Node: Korn Shell Constructs, Next: Korn Shell Builtins, Up: Korn Shell Features - -Korn Shell Constructs -===================== - - Bash includes the Korn Shell `select' construct. This construct -allows the easy generation of menus. It has almost the same syntax as -the `for' command. - - The syntax of the `select' command is: - select NAME [in WORDS ...]; do COMMANDS; done - - The list of words following `in' is expanded, generating a list of -items. The set of expanded words is printed on the standard error, -each preceded by a number. If the "`in WORDS'" is omitted, the -positional parameters are printed. The `PS3' prompt is then displayed -and a line is read from the standard input. If the line consists of the -number corresponding to one of the displayed words, then the value of -NAME is set to that word. If the line is empty, the words and prompt -are displayed again. If `EOF' is read, the `select' command completes. -Any other value read causes NAME to be set to null. The line read is -saved in the variable `REPLY'. - - The COMMANDS are executed after each selection until a `break' or -`return' command is executed, at which point the `select' command -completes. - - -File: features.info, Node: Korn Shell Builtins, Next: Korn Shell Variables, Prev: Korn Shell Constructs, Up: Korn Shell Features - -Korn Shell Builtins -=================== - - This section describes Bash builtin commands taken from `ksh'. - -`fc' - `fc [-e ENAME] [-nlr] [FIRST] [LAST]' - `fc -s [PAT=REP] [COMMAND]' - - Fix Command. In the first form, a range of commands from FIRST to - LAST is selected from the history list. Both FIRST and LAST may - be specified as a string (to locate the most recent command - beginning with that string) or as a number (an index into the - history list, where a negative number is used as an offset from the - current command number). If LAST is not specified it is set to - FIRST. If FIRST is not specified it is set to the previous - command for editing and -16 for listing. If the `-l' flag is - given, the commands are listed on standard output. The `-n' flag - suppresses the command numbers when listing. The `-r' flag - reverses the order of the listing. Otherwise, the editor given by - ENAME is invoked on a file containing those commands. If ENAME is - not given, the value of the following variable expansion is used: - `${FCEDIT:-${EDITOR:-vi}}'. This says to use the value of the - `FCEDIT' variable if set, or the value of the `EDITOR' variable if - that is set, or `vi' if neither is set. When editing is complete, - the edited commands are echoed and executed. - - In the second form, COMMAND is re-executed after each instance of - PAT in the selected command is replaced by REP. - - A useful alias to use with the `fc' command is `r='fc -s'', so - that typing `r cc' runs the last command beginning with `cc' and - typing `r' re-executes the last command (*note Aliases::.). - -`let' - The `let' builtin allows arithmetic to be performed on shell - variables. For details, refer to *Note Arithmetic Builtins::. - -`typeset' - The `typeset' command is supplied for compatibility with the Korn - shell; however, it has been made obsolete by the `declare' command - (*note Bash Builtins::.). - - -File: features.info, Node: Korn Shell Variables, Next: Aliases, Prev: Korn Shell Builtins, Up: Korn Shell Features - -Korn Shell Variables -==================== - -`REPLY' - The default variable for the `read' builtin. - -`RANDOM' - Each time this parameter is referenced, a random integer is - generated. Assigning a value to this variable seeds the random - number generator. - -`SECONDS' - This variable expands to the number of seconds since the shell was - started. Assignment to this variable resets the count to the - value assigned, and the expanded value becomes the value assigned - plus the number of seconds since the assignment. - -`PS3' - The value of this variable is used as the prompt for the `select' - command. - -`PS4' - This is the prompt printed before the command line is echoed when - the `-x' option is set (*note The Set Builtin::.). - -`PWD' - The current working directory as set by the `cd' builtin. - -`OLDPWD' - The previous working directory as set by the `cd' builtin. - -`TMOUT' - If set to a value greater than zero, the value is interpreted as - the number of seconds to wait for input after issuing the primary - prompt. Bash terminates after that number of seconds if input does - not arrive. - - -File: features.info, Node: Aliases, Prev: Korn Shell Variables, Up: Korn Shell Features - -Aliases -======= - -* Menu: - -* Alias Builtins:: Builtins commands to maniuplate aliases. - - The shell maintains a list of ALIASES that may be set and unset with -the `alias' and `unalias' builtin commands. - - 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 alias name and the replacement text may contain any valid shell -input, including shell metacharacters, with the exception that the -alias name may not contain =. 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 -`ls' to `"ls -F"', for instance, and Bash does not try to recursively -expand the replacement text. If the last character of the alias value -is a space or tab character, then the next command word following the -alias is also checked for alias expansion. - - Aliases are created and listed with the `alias' command, and removed -with the `unalias' command. - - There is no mechanism for using arguments in the replacement text, -as in `csh'. If arguments are needed, a shell function should be used. - - Aliases are not expanded when the shell is not interactive. - - The rules concerning the definition and use of aliases are somewhat -confusing. Bash always reads at least one complete line of input -before executing any of the commands on that line. Aliases are -expanded when a command is read, not when it is executed. Therefore, an -alias definition appearing on the same line as another command does not -take effect until the next line of input is read. This means that the -commands following the alias definition on that line are not affected -by the new alias. This behavior is also an issue when functions are -executed. Aliases are expanded when the function definition is read, -not when the function is executed, because a function definition is -itself a compound command. As a consequence, aliases defined in a -function are not available until after that function is executed. To -be safe, always put alias definitions on a separate line, and do not -use `alias' in compound commands. - - Note that for almost every purpose, aliases are superseded by shell -functions. - - -File: features.info, Node: Alias Builtins, Up: Aliases - -Alias Builtins --------------- - -`alias' - alias [NAME[=VALUE] ...] - - Without arguments, print the list of aliases on the standard - output. If arguments are supplied, an alias is defined for each - NAME whose VALUE is given. If no VALUE is given, the name and - value of the alias is printed. - -`unalias' - unalias [-a] [NAME ... ] - - Remove each NAME from the list of aliases. If `-a' is supplied, - all aliases are removed. - - -File: features.info, Node: Bash Specific Features, Next: Job Control, Prev: Korn Shell Features, Up: Top - -Bash Specific Features -********************** - - This section describes the features unique to Bash. - -* Menu: - -* Invoking Bash:: Command line options that you can give - to Bash. -* Bash Startup Files:: When and how Bash executes scripts. -* Is This Shell Interactive?:: Determining the state of a running Bash. -* Bash Builtins:: Table of builtins specific to Bash. -* The Set Builtin:: This builtin is so overloaded it - deserves its own section. -* Bash Variables:: List of variables that exist in Bash. -* Shell Arithmetic:: Arithmetic on shell variables. -* Printing a Prompt:: Controlling the PS1 string. - - -File: features.info, Node: Invoking Bash, Next: Bash Startup Files, Up: Bash Specific Features - -Invoking Bash -============= - - In addition to the single-character shell command-line options -(*note The Set Builtin::.), there are several multi-character options -that you can use. These options must appear on the command line before -the single-character options to be recognized. - -`-norc' - Don't read the `~/.bashrc' initialization file in an interactive - shell. This is on by default if the shell is invoked as `sh'. - -`-rcfile FILENAME' - Execute commands from FILENAME (instead of `~/.bashrc') in an - interactive shell. - -`-noprofile' - Don't load the system-wide startup file `/etc/profile' or any of - the personal initialization files `~/.bash_profile', - `~/.bash_login', or `~/.profile' when bash is invoked as a login - shell. - -`-version' - Display the version number of this shell. - -`-login' - Make this shell act as if it were directly invoked from login. - This is equivalent to `exec - bash' but can be issued from another - shell, such as `csh'. If you wanted to replace your current login - shell with a Bash login shell, you would say `exec bash -login'. - -`-nobraceexpansion' - Do not perform curly brace expansion (*note Brace Expansion::.). - -`-nolineediting' - Do not use the GNU Readline library (*note Command Line Editing::.) - to read interactive command lines. - -`-posix' - Change the behavior of Bash where the default operation differs - from the Posix 1003.2 standard to match the standard. This is - intended to make Bash behave as a strict superset of that standard. - - There are several single-character options you can give which are -not available with the `set' builtin. - -`-c STRING' - Read and execute commands from STRING after processing the - options, then exit. - -`-i' - Force the shell to run interactively. - -`-s' - If this flag is present, or if no arguments remain after option - processing, then commands are read from the standard input. This - option allows the positional parameters to be set when invoking an - interactive shell. - - An *interactive* shell is one whose input and output are both -connected to terminals (as determined by `isatty()'), or one started -with the `-i' option. - - -File: features.info, Node: Bash Startup Files, Next: Is This Shell Interactive?, Prev: Invoking Bash, Up: Bash Specific Features - -Bash Startup Files -================== - - When and how Bash executes startup files. - - For Login shells (subject to the -noprofile option): - - On logging in: - If `/etc/profile' exists, then source it. - - If `~/.bash_profile' exists, then source it, - else if `~/.bash_login' exists, then source it, - else if `~/.profile' exists, then source it. - - On logging out: - If `~/.bash_logout' exists, source it. - - For non-login interactive shells (subject to the -norc and -rcfile options): - On starting up: - If `~/.bashrc' exists, then source it. - - For non-interactive shells: - On starting up: - If the environment variable `ENV' is non-null, expand the - variable and source the file named by the value. If Bash is - not started in Posix mode, it looks for `BASH_ENV' before - `ENV'. - - So, typically, your `~/.bash_profile' contains the line - `if [ -f `~/.bashrc' ]; then source `~/.bashrc'; fi' - -after (or before) any login specific initializations. - - If Bash is invoked as `sh', it tries to mimic the behavior of `sh' -as closely as possible. For a login shell, it attempts to source only -`/etc/profile' and `~/.profile', in that order. The `-noprofile' -option may still be used to disable this behavior. A shell invoked as -`sh' does not attempt to source any other startup files. - - When Bash is started in POSIX mode, as with the `-posix' command -line option, it follows the Posix 1003.2 standard for startup files. -In this mode, the `ENV' variable is expanded and that file sourced; no -other startup files are read. - - -File: features.info, Node: Is This Shell Interactive?, Next: Bash Builtins, Prev: Bash Startup Files, Up: Bash Specific Features - -Is This Shell Interactive? -========================== - - You may wish to determine within a startup script whether Bash is -running interactively or not. To do this, examine the variable `$PS1'; -it is unset in non-interactive shells, and set in interactive shells. -Thus: - - if [ -z "$PS1" ]; then - echo This shell is not interactive - else - echo This shell is interactive - fi - - You can ask an interactive Bash to not run your `~/.bashrc' file -with the `-norc' flag. You can change the name of the `~/.bashrc' file -to any other file name with `-rcfile FILENAME'. You can ask Bash to -not run your `~/.bash_profile' file with the `-noprofile' flag. - - -File: features.info, Node: Bash Builtins, Next: The Set Builtin, Prev: Is This Shell Interactive?, Up: Bash Specific Features - -Bash Builtin Commands -===================== - - This section describes builtin commands which are unique to or have -been extended in Bash. - -`builtin' - builtin [SHELL-BUILTIN [ARGS]] - Run a shell builtin. This is useful when you wish to rename a - shell builtin to be a function, but need the functionality of the - builtin within the function itself. - -`bind' - bind [-m KEYMAP] [-lvd] [-q NAME] - bind [-m KEYMAP] -f FILENAME - bind [-m KEYMAP] KEYSEQ:FUNCTION-NAME - - Display current Readline (*note Command Line Editing::.) key and - function bindings, or bind a key sequence to a Readline function - or macro. The binding syntax accepted is identical to that of - `.inputrc' (*note Readline Init File::.), but each binding must be - passed as a separate argument: `"\C-x\C-r":re-read-init-file'. - Options, if supplied, have the following meanings: - - `-m keymap' - Use KEYMAP as the keymap to be affected by the subsequent - bindings. Acceptable KEYMAP names are `emacs', - `emacs-standard', `emacs-meta', `emacs-ctlx', `vi', `vi-move', - `vi-command', and `vi-insert'. `vi' is equivalent to - `vi-command'; `emacs' is equivalent to `emacs-standard'. - - `-l' - List the names of all readline functions - - `-v' - List current function names and bindings - - `-d' - Dump function names and bindings in such a way that they can - be re-read - - `-f filename' - Read key bindings from FILENAME - - `-q' - Query about which keys invoke the named FUNCTION - -`command' - command [-pVv] COMMAND [ARGS ...] - Runs COMMAND with ARG ignoring shell functions. If you have a - shell function called `ls', and you wish to call the command `ls', - you can say `command ls'. The `-p' option means to use a default - value for `$PATH' that is guaranteed to find all of the standard - utilities. - - If either the `-V' or `-v' option is supplied, a description of - COMMAND is printed. The `-v' option causes a single word - indicating the command or file name used to invoke COMMAND to be - printed; the `-V' option produces a more verbose description. - -`declare' - declare [-frxi] [NAME[=VALUE]] - - Declare variables and/or give them attributes. If no NAMEs are - given, then display the values of variables instead. `-f' means - to use function names only. `-r' says to make NAMEs readonly. - `-x' says to mark NAMEs for export. `-i' says that the variable - is to be treated as an integer; arithmetic evaluation (*note Shell - Arithmetic::.) is performed when the variable is assigned a value. - Using `+' instead of `-' turns off the attribute instead. When - used in a function, `declare' makes NAMEs local, as with the - `local' command. - -`enable' - enable [-n] [-a] [NAME ...] - Enable and disable builtin shell commands. This allows you to use - a disk command which has the same name as a shell builtin. If - `-n' is used, the NAMEs become disabled. Otherwise NAMEs are - enabled. For example, to use the `test' binary found via `$PATH' - instead of the shell builtin version, type `enable -n test'. The - `-a' option means to list each builtin with an indication of - whether or not it is enabled. - -`help' - help [PATTERN] - Display helpful information about builtin commands. If PATTERN is - specified, `help' gives detailed help on all commands matching - PATTERN, otherwise a list of the builtins is printed. - -`local' - local NAME[=VALUE] - For each argument, create a local variable called NAME, and give - it VALUE. `local' can only be used within a function; it makes - the variable NAME have a visible scope restricted to that function - and its children. - -`type' - type [-all] [-type | -path] [NAME ...] - For each NAME, indicate how it would be interpreted if used as a - command name. - - If the `-type' flag is used, `type' returns a single word which is - one of "alias", "function", "builtin", "file" or "keyword", if - NAME is an alias, shell function, shell builtin, disk file, or - shell reserved word, respectively. - - If the `-path' flag is used, `type' either returns the name of the - disk file that would be executed, or nothing if `-type' would not - return "file". - - If the `-all' flag is used, returns all of the places that contain - an executable named FILE. This includes aliases and functions, if - and only if the `-path' flag is not also used. - - `Type' accepts `-a', `-t', and `-p' as equivalent to `-all', - `-type', and `-path', respectively. - -`ulimit' - ulimit [-acdmstfpnuvSH] [LIMIT] - `Ulimit' provides control over the resources available to processes - started by the shell, on systems that allow such control. If an - option is given, it is interpreted as follows: - `-S' - change and report the soft limit associated with a resource - (the default if the `-H' option is not given). - - `-H' - change and report the hard limit associated with a resource. - - `-a' - all current limits are reported. - - `-c' - the maximum size of core files created. - - `-d' - the maximum size of a process's data segment. - - `-m' - the maximum resident set size. - - `-s' - the maximum stack size. - - `-t' - the maximum amount of cpu time in seconds. - - `-f' - the maximum size of files created by the shell. - - `-p' - the pipe buffer size. - - `-n' - the maximum number of open file descriptors. - - `-u' - the maximum number of processes available to a single user. - - `-v' - the maximum amount of virtual memory available to the process. - - If LIMIT is given, it is the new value of the specified resource. - Otherwise, the current value of the specified resource is printed. - If no option is given, then `-f' is assumed. Values are in - 1024-byte increments, except for `-t', which is in seconds, `-p', - which is in units of 512-byte blocks, and `-n' and `-u', which are - unscaled values. - - -File: features.info, Node: The Set Builtin, Next: Bash Variables, Prev: Bash Builtins, Up: Bash Specific Features - -The Set Builtin -=============== - - This builtin is so overloaded that it deserves its own section. - -`set' - set [-abefhkmnptuvxldCHP] [-o OPTION] [ARGUMENT ...] - - `-a' - Mark variables which are modified or created for export. - - `-b' - Cause the status of terminated background jobs to be reported - immediately, rather than before printing the next primary - prompt. - - `-e' - Exit immediately if a command exits with a non-zero status. - - `-f' - Disable file name generation (globbing). - - `-h' - Locate and remember (hash) commands as functions are defined, - rather than when the function is executed. - - `-k' - All keyword arguments are placed in the environment for a - command, not just those that precede the command name. - - `-m' - Job control is enabled (*note Job Control::.). - - `-n' - Read commands but do not execute them. - - `-o OPTION-NAME' - Set the flag corresponding to OPTION-NAME: - - `allexport' - same as `-a'. - - `braceexpand' - the shell will perform brace expansion (*note Brace - Expansion::.). - - `emacs' - use an emacs-style line editing interface (*note Command - Line Editing::.). - - `errexit' - same as `-e'. - - `histexpand' - same as `-H'. - - `ignoreeof' - the shell will not exit upon reading EOF. - - `interactive-comments' - allow a word beginning with a `#' to cause that word and - all remaining characters on that line to be ignored in an - interactive shell. - - `monitor' - same as `-m'. - - `noclobber' - same as `-C'. - - `noexec' - same as `-n'. - - `noglob' - same as `-f'. - - `nohash' - same as `-d'. - - `notify' - same as `-b'. - - `nounset' - same as `-u'. - - `physical' - same as `-P'. - - `posix' - change the behavior of Bash where the default operation - differs from the Posix 1003.2 standard to match the - standard. This is intended to make Bash behave as a - strict superset of that standard. - - `privileged' - same as `-p'. - - `verbose' - same as `-v'. - - `vi' - use a `vi'-style line editing interface. - - `xtrace' - same as `-x'. - - `-p' - Turn on privileged mode. In this mode, the `$ENV' file is - not processed, and shell functions are not inherited from the - environment. This is enabled automatically on startup if the - effective user (group) id is not equal to the real user - (group) id. Turning this option off causes the effective user - and group ids to be set to the real user and group ids. - - `-t' - Exit after reading and executing one command. - - `-u' - Treat unset variables as an error when substituting. - - `-v' - Print shell input lines as they are read. - - `-x' - Print commands and their arguments as they are executed. - - `-l' - Save and restore the binding of the NAME in a `for' command. - - `-d' - Disable the hashing of commands that are looked up for - execution. Normally, commands are remembered in a hash - table, and once found, do not have to be looked up again. - - `-C' - Disallow output redirection to existing files. - - `-H' - Enable ! style history substitution. This flag is on by - default. - - `-P' - If set, do not follow symbolic links when performing commands - such as `cd' which change the current directory. The - physical directory is used instead. - - `--' - If no arguments follow this flag, then the positional - parameters are unset. Otherwise, the positional parameters - are set to the ARGUMENTS, even if some of them begin with a - `-'. - - `-' - Signal the end of options, cause all remaining ARGUMENTS to - be assigned to the positional parameters. The `-x' and `-v' - options are turned off. If there are no arguments, the - positional parameters remain unchanged. - - Using `+' rather than `-' causes these flags to be turned off. - The flags can also be used upon invocation of the shell. The - current set of flags may be found in `$-'. The remaining N - ARGUMENTS are positional parameters and are assigned, in order, to - `$1', `$2', .. `$N'. If no arguments are given, all shell - variables are printed. - - -File: features.info, Node: Bash Variables, Next: Shell Arithmetic, Prev: The Set Builtin, Up: Bash Specific Features - -Bash Variables -============== - - These variables are set or used by bash, but other shells do not -normally treat them specially. - -`HISTCONTROL' -`history_control' - Set to a value of `ignorespace', it means don't enter lines which - begin with a space or tab into the history list. Set to a value - of `ignoredups', it means don't enter lines which match the last - entered line. A value of `ignoreboth' combines the two options. - Unset, or set to any other value than those above, means to save - all lines on the history list. - -`HISTFILE' - The name of the file to which the command history is saved. - -`HISTSIZE' - If set, this is the maximum number of commands to remember in the - history. - -`histchars' - Up to three characters which control history expansion, quick - substitution, and tokenization (*note History Interaction::.). - The first character is the "history-expansion-char", that is, the - character which signifies the start of a history expansion, - normally `!'. The second character is the character which - signifies `quick substitution' when seen as the first character on - a line, normally `^'. The optional third character is the - character which signifies the remainder of the line is a comment, - when found as the first character of a word, usually `#'. The - history comment character causes history substitution to be - skipped for the remaining words on the line. It does not - necessarily cause the shell parser to treat the rest of the line - as a comment. - -`HISTCMD' - The history number, or index in the history list, of the current - command. If `HISTCMD' is unset, it loses its special properties, - even if it is subsequently reset. - -`hostname_completion_file' -`HOSTFILE' - Contains the name of a file in the same format as `/etc/hosts' that - should be read when the shell needs to complete a hostname. You - can change the file interactively; the next time you attempt to - complete a hostname, Bash will add the contents of the new file to - the already existing database. - -`MAILCHECK' - How often (in seconds) that the shell should check for mail in the - files specified in `MAILPATH'. - -`PROMPT_COMMAND' - If present, this contains a string which is a command to execute - before the printing of each primary prompt (`$PS1'). - -`UID' - The numeric real user id of the current user. - -`EUID' - The numeric effective user id of the current user. - -`HOSTTYPE' - A string describing the machine Bash is running on. - -`OSTYPE' - A string describing the operating system Bash is running on. - -`FIGNORE' - A colon-separated list of suffixes to ignore when performing - filename completion A file name whose suffix matches one of the - entries in `FIGNORE' is excluded from the list of matched file - names. A sample value is `.o:~' - -`INPUTRC' - The name of the Readline startup file, overriding the default of - `~/.inputrc'. - -`BASH_VERSION' - The version number of the current instance of Bash. - -`IGNOREEOF' - Controls the action of the shell on receipt of an `EOF' character - as the sole input. If set, then the value of it is the number of - consecutive `EOF' characters that can be read as the first - characters on an input line before the shell will exit. If the - variable exists but does not have a numeric value (or has no - value) then the default is 10. If the variable does not exist, - then `EOF' signifies the end of input to the shell. This is only - in effect for interactive shells. - -`no_exit_on_failed_exec' - If this variable exists, the shell will not exit in the case that - it couldn't execute the file specified in the `exec' command. - -`nolinks' - If present, says not to follow symbolic links when doing commands - that change the current working directory. By default, bash - follows the logical chain of directories when performing commands - such as `cd' which change the current directory. - - For example, if `/usr/sys' is a link to `/usr/local/sys' then: - $ cd /usr/sys; echo $PWD - /usr/sys - $ cd ..; pwd - /usr - - If `nolinks' exists, then: - $ cd /usr/sys; echo $PWD - /usr/local/sys - $ cd ..; pwd - /usr/local - - See also the description of the `-P' option to the `set' builtin, - *Note The Set Builtin::. - - -File: features.info, Node: Shell Arithmetic, Next: Printing a Prompt, Prev: Bash Variables, Up: Bash Specific Features - -Shell Arithmetic -================ - -* Menu: - -* Arithmetic Evaluation:: How shell arithmetic works. -* Arithmetic Expansion:: How to use arithmetic in shell expansions. -* Arithmetic Builtins:: Builtin commands that use shell arithmetic. - - -File: features.info, Node: Arithmetic Evaluation, Next: Arithmetic Expansion, Up: Shell Arithmetic - -Arithmetic Evaluation ---------------------- - - The shell allows arithmetic expressions to be evaluated, as one of -the shell expansions or by the `let' builtin. - - Evaluation is done in long integers with no check for overflow, -though division by 0 is trapped and flagged as an error. The following -list of operators is grouped into levels of equal-precedence operators. -The levels are listed in order of decreasing precedence. - -`- +' - unary minus and plus - -`! ~' - logical and bitwise negation - -`* / %' - multiplication, division, remainder - -`+ -' - addition, subtraction - -`<< >>' - left and right bitwise shifts - -`<= >= < >' - comparison - -`== !=' - equality and inequality - -`&' - bitwise AND - -`^' - bitwise exclusive OR - -`|' - bitwise OR - -`&&' - logical AND - -`||' - logical OR - -`= *= /= %= += -= <<= >>= &= ^= |=' - assignment - - Shell variables are allowed as operands; parameter expansion is -performed before the expression is evaluated. The value of a parameter -is coerced to a long integer within an expression. A shell variable -need not have its integer attribute turned on to be used in an -expression. - - Constants with a leading 0 are interpreted as octal numbers. A -leading `0x' or `0X' denotes hexadecimal. Otherwise, numbers take the -form [BASE#]n, where BASE is a decimal number between 2 and 36 -representing the arithmetic base, and N is a number in that base. If -BASE is omitted, then base 10 is used. - - Operators are evaluated in order of precedence. Sub-expressions in -parentheses are evaluated first and may override the precedence rules -above. - - -File: features.info, Node: Arithmetic Expansion, Next: Arithmetic Builtins, Prev: Arithmetic Evaluation, Up: Shell Arithmetic - -Arithmetic Expansion --------------------- - - Arithmetic expansion allows the evaluation of an arithmetic -expression and the substitution of the result. There are two formats -for arithmetic expansion: - - $[ expression ] - $(( expression )) - - The expression is treated as if it were within double quotes, but a -double quote inside the braces or parentheses is not treated specially. -All tokens in the expression undergo parameter expansion, command -substitution, and quote removal. Arithmetic substitutions may be -nested. - - The evaluation is performed according to the rules listed above. If -the expression is invalid, Bash prints a message indicating failure and -no substitution occurs. - - -File: features.info, Node: Arithmetic Builtins, Prev: Arithmetic Expansion, Up: Shell Arithmetic - -Arithmetic Builtins -------------------- - -`let' - let EXPRESSION [EXPRESSION] - The `let' builtin allows arithmetic to be performed on shell - variables. Each EXPRESSION is evaluated according to the rules - given previously (*note Arithmetic Evaluation::.). If the last - EXPRESSION evaluates to 0, `let' returns 1; otherwise 0 is - returned. - - -File: features.info, Node: Printing a Prompt, Prev: Shell Arithmetic, Up: Bash Specific Features - -Controlling the Prompt -====================== - - The value of the variable `$PROMPT_COMMAND' is examined just before -Bash prints each primary prompt. If it is set and non-null, then the -value is executed just as if you had typed it on the command line. - - In addition, the following table describes the special characters -which can appear in the `PS1' variable: - -`\t' - the time, in HH:MM:SS format. - -`\d' - the date, in "Weekday Month Date" format (e.g. "Tue May 26"). - -`\n' - newline. - -`\s' - the name of the shell, the basename of `$0' (the portion following - the final slash). - -`\w' - the current working directory. - -`\W' - the basename of `$PWD'. - -`\u' - your username. - -`\h' - the hostname. - -`\#' - the command number of this command. - -`\!' - the history number of this command. - -`\nnn' - the character corresponding to the octal number `nnn'. - -`\$' - if the effective uid is 0, `#', otherwise `$'. - -`\\' - a backslash. - -`\[' - begin a sequence of non-printing characters. This could be used to - embed a terminal control sequence into the prompt. - -`\]' - end a sequence of non-printing characters. - - -File: features.info, Node: Job Control, Next: Using History Interactively, Prev: Bash Specific Features, Up: Top - -Job Control -*********** - - This chapter disusses what job control is, how it works, and how -Bash allows you to access its facilities. - -* Menu: - -* Job Control Basics:: How job control works. -* Job Control Builtins:: Bash builtin commands used to interact - with job control. -* Job Control Variables:: Variables Bash uses to customize job - control. - - -File: features.info, Node: Job Control Basics, Next: Job Control Builtins, Up: Job Control - -Job Control Basics -================== - - Job control refers to the ability to selectively stop (suspend) the -execution of processes and continue (resume) their execution at a later -point. A user typically employs this facility via an interactive -interface supplied jointly by the system's terminal driver and Bash. - - The shell associates a JOB with each pipeline. It keeps a table of -currently executing jobs, which may be listed with the `jobs' command. -When Bash starts a job asynchronously (in the background), it prints a -line that looks like: - [1] 25647 - indicating that this job is job number 1 and that the process ID of -the last process in the pipeline associated with this job is 25647. -All of the processes in a single pipeline are members of the same job. -Bash uses the JOB abstraction as the basis for job control. - - To facilitate the implementation of the user interface to job -control, the system maintains the notion of a current terminal process -group ID. Members of this process group (processes whose process group -ID is equal to the current terminal process group ID) receive -keyboard-generated signals such as `SIGINT'. These processes are said -to be in the foreground. Background processes are those whose process -group ID differs from the terminal's; such processes are immune to -keyboard-generated signals. Only foreground processes are allowed to -read from or write to the terminal. Background processes which attempt -to read from (write to) the terminal are sent a `SIGTTIN' (`SIGTTOU') -signal by the terminal driver, which, unless caught, suspends the -process. - - If the operating system on which Bash is running supports job -control, Bash allows you to use it. Typing the SUSPEND character -(typically `^Z', Control-Z) while a process is running causes that -process to be stopped and returns you to Bash. Typing the DELAYED -SUSPEND character (typically `^Y', Control-Y) causes the process to be -stopped when it attempts to read input from the terminal, and control to -be returned to Bash. You may then manipulate the state of this job, -using the `bg' command to continue it in the background, the `fg' -command to continue it in the foreground, or the `kill' command to kill -it. A `^Z' takes effect immediately, and has the additional side -effect of causing pending output and typeahead to be discarded. - - There are a number of ways to refer to a job in the shell. The -character `%' introduces a job name. Job number `n' may be referred to -as `%n'. A job may also be referred to using a prefix of the name used -to start it, or using a substring that appears in its command line. -For example, `%ce' refers to a stopped `ce' job. Using `%?ce', on the -other hand, refers to any job containing the string `ce' in its command -line. If the prefix or substring matches more than one job, Bash -reports an error. The symbols `%%' and `%+' refer to the shell's -notion of the current job, which is the last job stopped while it was -in the foreground. The previous job may be referenced using `%-'. In -output pertaining to jobs (e.g., the output of the `jobs' command), the -current job is always flagged with a `+', and the previous job with a -`-'. - - Simply naming a job can be used to bring it into the foreground: -`%1' is a synonym for `fg %1' bringing job 1 from the background into -the foreground. Similarly, `%1 &' resumes job 1 in the background, -equivalent to `bg %1' - - The shell learns immediately whenever a job changes state. -Normally, Bash waits until it is about to print a prompt before -reporting changes in a job's status so as to not interrupt any other -output. If the the `-b' option to the `set' builtin is set, Bash -reports such changes immediately (*note The Set Builtin::.). This -feature is also controlled by the variable `notify'. - - If you attempt to exit bash while jobs are stopped, the shell prints -a message warning you. You may then use the `jobs' command to inspect -their status. If you do this, or try to exit again immediately, you -are not warned again, and the stopped jobs are terminated. - - -File: features.info, Node: Job Control Builtins, Next: Job Control Variables, Prev: Job Control Basics, Up: Job Control - -Job Control Builtins -==================== - -`bg' - bg [JOBSPEC] - Place JOBSPEC into the background, as if it had been started with - `&'. If JOBSPEC is not supplied, the current job is used. - -`fg' - fg [JOBSPEC] - Bring JOBSPEC into the foreground and make it the current job. If - JOBSPEC is not supplied, the current job is used. - -`jobs' - jobs [-lpn] [JOBSPEC] - jobs -x COMMAND [JOBSPEC] - - The first form lists the active jobs. The `-l' option lists - process IDs in addition to the normal information; the `-p' option - lists only the process ID of the job's process group leader. The - `-n' option displays only jobs that have changed status since last - notfied. If JOBSPEC is given, output is restricted to information - about that job. If JOBSPEC is not supplied, the status of all - jobs is listed. - - If the `-x' option is supplied, `jobs' replaces any JOBSPEC found - in COMMAND or ARGUMENTS with the corresponding process group ID, - and executes COMMAND, passing it ARGUMENTs, returning its exit - status. - -`suspend' - suspend [-f] - Suspend the execution of this shell until it receives a `SIGCONT' - signal. The `-f' option means to suspend even if the shell is a - login shell. - - When job control is active, the `kill' and `wait' builtins also -accept JOBSPEC arguments. - - -File: features.info, Node: Job Control Variables, Prev: Job Control Builtins, Up: Job Control - -Job Control Variables -===================== - -`auto_resume' - This variable controls how the shell interacts with the user and - job control. If this variable exists then single word simple - commands without redirects are treated as candidates for resumption - of an existing job. There is no ambiguity allowed; if you have - more than one job beginning with the string that you have typed, - then the most recently accessed job will be selected. The name of - a stopped job, in this context, is the command line used to start - it. If this variable is set to the value `exact', the string - supplied must match the name of a stopped job exactly; if set to - `substring', the string supplied needs to match a substring of the - name of a stopped job. The `substring' value provides - functionality analogous to the `%?' job id (*note Job Control - Basics::.). 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 `%' job id. - -`notify' - Setting this variable to a value is equivalent to `set -b'; - unsetting it is equivalent to `set +b' (*note The Set Builtin::.). - - -File: features.info, Node: Using History Interactively, Next: Command Line Editing, Prev: Job Control, Up: Top - -Using History Interactively -*************************** - - This chapter describes how to use the GNU History Library -interactively, from a user's standpoint. It should be considered a -user's guide. For information on using the GNU History Library in your -own programs, see the GNU Readline Library Manual. - -* Menu: - -* History Interaction:: What it feels like using History as a user. - - -File: features.info, Node: History Interaction, Up: Using History Interactively - -History Interaction -=================== - - The History library provides a history expansion feature that is -similar to the history expansion provided by `csh'. The following text -describes the syntax used to manipulate the history information. - - History expansion takes place in two parts. The first is to -determine which line from the previous history should be used during -substitution. The second is to select portions of that line for -inclusion into the current one. The line selected from the previous -history is called the "event", and the portions of that line that are -acted upon are called "words". The line is broken into words in the -same fashion that Bash does, so that several English (or Unix) words -surrounded by quotes are considered as one word. - -* Menu: - -* Event Designators:: How to specify which history line to use. -* Word Designators:: Specifying which words are of interest. -* Modifiers:: Modifying the results of substitution. - - -File: features.info, Node: Event Designators, Next: Word Designators, Up: History Interaction - -Event Designators ------------------ - - An event designator is a reference to a command line entry in the -history list. - -`!' - Start a history substitution, except when followed by a space, tab, - the end of the line, = or (. - -`!!' - Refer to the previous command. This is a synonym for `!-1'. - -`!n' - Refer to command line N. - -`!-n' - Refer to the command N lines back. - -`!string' - Refer to the most recent command starting with STRING. - -`!?string'[`?'] - Refer to the most recent command containing STRING. - -`!#' - The entire command line typed so far. - -`^string1^string2^' - Quick Substitution. Repeat the last command, replacing STRING1 - with STRING2. Equivalent to `!!:s/string1/string2/'. - - -File: features.info, Node: Word Designators, Next: Modifiers, Prev: Event Designators, Up: History Interaction - -Word Designators ----------------- - - A : separates the event specification from the word designator. It -can be omitted if the word designator begins with a ^, $, * or %. -Words are numbered from the beginning of the line, with the first word -being denoted by a 0 (zero). - -`0 (zero)' - The `0'th word. For many applications, this is the command word. - -`n' - The Nth word. - -`^' - The first argument; that is, word 1. - -`$' - The last argument. - -`%' - The word matched by the most recent `?string?' search. - -`x-y' - A range of words; `-Y' abbreviates `0-Y'. - -`*' - All of the words, except the `0'th. This is a synonym for `1-$'. - It is not an error to use * if there is just one word in the event; - the empty string is returned in that case. - -`x*' - Abbreviates `x-$' - -`x-' - Abbreviates `x-$' like `x*', but omits the last word. - - -File: features.info, Node: Modifiers, Prev: Word Designators, Up: History Interaction - -Modifiers ---------- - - After the optional word designator, you can add a sequence of one or -more of the following modifiers, each preceded by a :. - -`h' - Remove a trailing pathname component, leaving only the head. - -`r' - Remove a trailing suffix of the form `.'SUFFIX, leaving the - basename. - -`e' - Remove all but the trailing suffix. - -`t' - Remove all leading pathname components, leaving the tail. - -`p' - Print the new command but do not execute it. - -`q' - Quote the substituted words, escaping further substitutions. - -`x' - Quote the substituted words as with `q', but break into words at - spaces, tabs, and newlines. - -`s/old/new/' - Substitute NEW for the first occurrence of OLD in the event line. - Any delimiter may be used in place of /. The delimiter may be - quoted in OLD and NEW with a single backslash. If & appears in - NEW, it is replaced by OLD. A single backslash will quote the &. - The final delimiter is optional if it is the last character on the - input line. - -`&' - Repeat the previous substitution. - -`g' - Cause changes to be applied over the entire event line. Used in - conjunction with `s', as in `gs/old/new/', or with `&'. - - -File: features.info, Node: Command Line Editing, Next: Variable Index, Prev: Using History Interactively, Up: Top - -Command Line Editing -******************** - - This chapter describes the basic features of the GNU command line -editing interface. - -* Menu: - -* Introduction and Notation:: Notation used in this text. -* Readline Interaction:: The minimum set of commands for editing a line. -* Readline Init File:: Customizing Readline from a user's view. -* Bindable Readline Commands:: A description of most of the Readline commands - available for binding -* Readline vi Mode:: A short description of how to make Readline - behave like the vi editor. - - -File: features.info, Node: Introduction and Notation, Next: Readline Interaction, Up: Command Line Editing - -Introduction to Line Editing -============================ - - The following paragraphs describe the notation used to represent -keystrokes. - - The text C-k is read as `Control-K' and describes the character -produced when the Control key is depressed and the k key is struck. - - The text M-k is read as `Meta-K' and describes the character -produced when the meta key (if you have one) is depressed, and the k -key is struck. If you do not have a meta key, the identical keystroke -can be generated by typing ESC first, and then typing k. Either -process is known as "metafying" the k key. - - The text M-C-k is read as `Meta-Control-k' and describes the -character produced by "metafying" C-k. - - In addition, several keys have their own names. Specifically, DEL, -ESC, LFD, SPC, RET, and TAB all stand for themselves when seen in this -text, or in an init file (*note Readline Init File::., for more info). - - -File: features.info, Node: Readline Interaction, Next: Readline Init File, Prev: Introduction and Notation, Up: Command Line Editing - -Readline Interaction -==================== - - Often during an interactive session you type in a long line of text, -only to notice that the first word on the line is misspelled. The -Readline library gives you a set of commands for manipulating the text -as you type it in, allowing you to just fix your typo, and not forcing -you to retype the majority of the line. Using these editing commands, -you move the cursor to the place that needs correction, and delete or -insert the text of the corrections. Then, when you are satisfied with -the line, you simply press RETURN. You do not have to be at the end of -the line to press RETURN; the entire line is accepted regardless of the -location of the cursor within the line. - -* Menu: - -* Readline Bare Essentials:: The least you need to know about Readline. -* Readline Movement Commands:: Moving about the input line. -* Readline Killing Commands:: How to delete text, and how to get it back! -* Readline Arguments:: Giving numeric arguments to commands. - - -File: features.info, Node: Readline Bare Essentials, Next: Readline Movement Commands, Up: Readline Interaction - -Readline Bare Essentials ------------------------- - - In order to enter characters into the line, simply type them. The -typed character appears where the cursor was, and then the cursor moves -one space to the right. If you mistype a character, you can use your -erase character to back up and delete the mistyped character. - - Sometimes you may miss typing a character that you wanted to type, -and not notice your error until you have typed several other -characters. In that case, you can type C-b to move the cursor to the -left, and then correct your mistake. Afterwards, you can move the -cursor to the right with C-f. - - When you add text in the middle of a line, you will notice that -characters to the right of the cursor are `pushed over' to make room -for the text that you have inserted. Likewise, when you delete text -behind the cursor, characters to the right of the cursor are `pulled -back' to fill in the blank space created by the removal of the text. A -list of the basic bare essentials for editing the text of an input line -follows. - -C-b - Move back one character. - -C-f - Move forward one character. - -DEL - Delete the character to the left of the cursor. - -C-d - Delete the character underneath the cursor. - -Printing characters - Insert the character into the line at the cursor. - -C-_ - Undo the last thing that you did. You can undo all the way back - to an empty line. - - -File: features.info, Node: Readline Movement Commands, Next: Readline Killing Commands, Prev: Readline Bare Essentials, Up: Readline Interaction - -Readline Movement Commands --------------------------- - - The above table describes the most basic possible keystrokes that -you need in order to do editing of the input line. For your -convenience, many other commands have been added in addition to C-b, -C-f, C-d, and DEL. Here are some commands for moving more rapidly -about the line. - -C-a - Move to the start of the line. - -C-e - Move to the end of the line. - -M-f - Move forward a word. - -M-b - Move backward a word. - -C-l - Clear the screen, reprinting the current line at the top. - - Notice how C-f moves forward a character, while M-f moves forward a -word. It is a loose convention that control keystrokes operate on -characters while meta keystrokes operate on words. - - -File: features.info, Node: Readline Killing Commands, Next: Readline Arguments, Prev: Readline Movement Commands, Up: Readline Interaction - -Readline Killing Commands -------------------------- - - "Killing" text means to delete the text from the line, but to save -it away for later use, usually by "yanking" (re-inserting) it back into -the line. If the description for a command says that it `kills' text, -then you can be sure that you can get the text back in a different (or -the same) place later. - - When you use a kill command, the text is saved in a "kill-ring". -Any number of consecutive kills save all of the killed text together, so -that when you yank it back, you get it all. The kill ring is not line -specific; the text that you killed on a previously typed line is -available to be yanked back later, when you are typing another line. - - Here is the list of commands for killing text. - -C-k - Kill the text from the current cursor position to the end of the - line. - -M-d - Kill from the cursor to the end of the current word, or if between - words, to the end of the next word. - -M-DEL - Kill from the cursor the start of the previous word, or if between - words, to the start of the previous word. - -C-w - Kill from the cursor to the previous whitespace. This is - different than M-DEL because the word boundaries differ. - - And, here is how to "yank" the text back into the line. Yanking -means to copy the most-recently-killed text from the kill buffer. - -C-y - Yank the most recently killed text back into the buffer at the - cursor. - -M-y - Rotate the kill-ring, and yank the new top. You can only do this - if the prior command is C-y or M-y. - - -File: features.info, Node: Readline Arguments, Prev: Readline Killing Commands, Up: Readline Interaction - -Readline Arguments ------------------- - - You can pass numeric arguments to Readline commands. Sometimes the -argument acts as a repeat count, other times it is the sign of the -argument that is significant. If you pass a negative argument to a -command which normally acts in a forward direction, that command will -act in a backward direction. For example, to kill text back to the -start of the line, you might type M- C-k. - - The general way to pass numeric arguments to a command is to type -meta digits before the command. If the first `digit' you type is a -minus sign (-), then the sign of the argument will be negative. Once -you have typed one meta digit to get the argument started, you can type -the remainder of the digits, and then the command. For example, to give -the C-d command an argument of 10, you could type M-1 0 C-d. - - -File: features.info, Node: Readline Init File, Next: Bindable Readline Commands, Prev: Readline Interaction, Up: Command Line Editing - -Readline Init File -================== - - Although the Readline library comes with a set of Emacs-like -keybindings installed by default, it is possible that you would like to -use a different set of keybindings. You can customize programs that -use Readline by putting commands in an "init" file in your home -directory. The name of this file is taken from the value of the shell -variable `INPUTRC'. If that variable is unset, the default is -`~/.inputrc'. - - When a program which uses the Readline library starts up, the init -file is read, and the key bindings are set. - - In addition, the `C-x C-r' command re-reads this init file, thus -incorporating any changes that you might have made to it. - -* Menu: - -* Readline Init Syntax:: Syntax for the commands in the inputrc file. -* Conditional Init Constructs:: Conditional key bindings in the inputrc file. - - -File: features.info, Node: Readline Init Syntax, Next: Conditional Init Constructs, Up: Readline Init File - -Readline Init Syntax --------------------- - - There are only a few basic constructs allowed in the Readline init -file. Blank lines are ignored. Lines beginning with a # are comments. -Lines beginning with a $ indicate conditional constructs (*note -Conditional Init Constructs::.). Other lines denote variable settings -and key bindings. - -Variable Settings - You can change the state of a few variables in Readline by using - the `set' command within the init file. Here is how you would - specify that you wish to use `vi' line editing commands: - - set editing-mode vi - - Right now, there are only a few variables which can be set; so - few, in fact, that we just list them here: - - `editing-mode' - The `editing-mode' variable controls which editing mode you - are using. By default, Readline starts up in Emacs editing - mode, where the keystrokes are most similar to Emacs. This - variable can be set to either `emacs' or `vi'. - - `horizontal-scroll-mode' - This variable can be set to either `On' or `Off'. Setting it - to `On' means that the text of the lines that you edit will - scroll horizontally on a single screen line when they are - longer than the width of the screen, instead of wrapping onto - a new screen line. By default, this variable is set to `Off'. - - `mark-modified-lines' - This variable, when set to `On', says to display an asterisk - (`*') at the start of history lines which have been modified. - This variable is `off' by default. - - `bell-style' - Controls what happens when Readline wants to ring the - terminal bell. If set to `none', Readline never rings the - bell. If set to `visible', Readline uses a visible bell if - one is available. If set to `audible' (the default), - Readline attempts to ring the terminal's bell. - - `comment-begin' - The string to insert at the beginning of the line when the - `vi-comment' command is executed. The default value is `"#"'. - - `meta-flag' - If set to `on', Readline will enable eight-bit input (it will - not strip the eighth bit from the characters it reads), - regardless of what the terminal claims it can support. The - default value is `off'. - - `convert-meta' - If set to `on', Readline will convert characters with the - eigth bit set to an ASCII key sequence by stripping the eigth - bit and prepending an ESC character, converting them to a - meta-prefixed key sequence. The default value is `on'. - - `output-meta' - If set to `on', Readline will display characters with the - eighth bit set directly rather than as a meta-prefixed escape - sequence. The default is `off'. - - `completion-query-items' - The number of possible completions that determines when the - user is asked whether he wants to see the list of - possibilities. If the number of possible completions is - greater than this value, Readline will ask the user whether - or not he wishes to view them; otherwise, they are simply - listed. The default limit is `100'. - - `keymap' - Sets Readline's idea of the current keymap for key binding - commands. Acceptable `keymap' names are `emacs', - `emacs-standard', `emacs-meta', `emacs-ctlx', `vi', `vi-move', - `vi-command', and `vi-insert'. `vi' is equivalent to - `vi-command'; `emacs' is equivalent to `emacs-standard'. The - default value is `emacs'. The value of the `editing-mode' - variable also affects the default keymap. - - `show-all-if-ambiguous' - This alters the default behavior of the completion functions. - If set to `on', words which have more than one possible - completion cause the matches to be listed immediately instead - of ringing the bell. The default value is `off'. - - `expand-tilde' - If set to `on', tilde expansion is performed when Readline - attempts word completion. The default is `off'. - -Key Bindings - The syntax for controlling key bindings in the init file is - simple. First you have to know the name of the command that you - want to change. The following pages contain tables of the command - name, the default keybinding, and a short description of what the - command does. - - Once you know the name of the command, simply place the name of - the key you wish to bind the command to, a colon, and then the - name of the command on a line in the init file. The name of the - key can be expressed in different ways, depending on which is most - comfortable for you. - - KEYNAME: FUNCTION-NAME or MACRO - KEYNAME is the name of a key spelled out in English. For - example: - Control-u: universal-argument - Meta-Rubout: backward-kill-word - Control-o: ">&output" - - In the above example, `C-u' is bound to the function - `universal-argument', and `C-o' is bound to run the macro - expressed on the right hand side (that is, to insert the text - `>&output' into the line). - - "KEYSEQ": FUNCTION-NAME or MACRO - KEYSEQ differs from KEYNAME above in that strings denoting an - entire key sequence can be specified, by placing the key - sequence in double quotes. Some GNU Emacs style key escapes - can be used, as in the following example, but the special - character names are not recognized. - - "\C-u": universal-argument - "\C-x\C-r": re-read-init-file - "\e[11~": "Function Key 1" - - In the above example, `C-u' is bound to the function - `universal-argument' (just as it was in the first example), - `C-x C-r' is bound to the function `re-read-init-file', and - `ESC [ 1 1 ~' is bound to insert the text `Function Key 1'. - The following escape sequences are available when specifying - key sequences: - - ``\C-'' - control prefix - - ``\M-'' - meta prefix - - ``\e'' - an escape character - - ``\\'' - backslash - - ``\"'' - " - - ``\''' - ' - - When entering the text of a macro, single or double quotes - should be used to indicate a macro definition. Unquoted text - is assumed to be a function name. Backslash will quote any - character in the macro text, including " and '. For example, - the following binding will make `C-x \' insert a single \ - into the line: - "\C-x\\": "\\" - - -File: features.info, Node: Conditional Init Constructs, Prev: Readline Init Syntax, Up: Readline Init File - -Conditional Init Constructs ---------------------------- - - Readline implements a facility similar in spirit to the conditional -compilation features of the C preprocessor which allows key bindings -and variable settings to be performed as the result of tests. There -are three parser directives used. - -`$if' - The `$if' construct allows bindings to be made based on the - editing mode, the terminal being used, or the application using - Readline. The text of the test extends to the end of the line; no - characters are required to isolate it. - - `mode' - The `mode=' form of the `$if' directive is used to test - whether Readline is in `emacs' or `vi' mode. This may be - used in conjunction with the `set keymap' command, for - instance, to set bindings in the `emacs-standard' and - `emacs-ctlx' keymaps only if Readline is starting out in - `emacs' mode. - - `term' - The `term=' form may be used to include terminal-specific key - bindings, perhaps to bind the key sequences output by the - terminal's function keys. The word on the right side of the - `=' is tested against the full name of the terminal and the - portion of the terminal name before the first `-'. This - allows SUN to match both SUN and SUN-CMD, for instance. - - `application' - The APPLICATION construct is used to include - application-specific settings. Each program using the - Readline library sets the APPLICATION NAME, and you can test - for it. This could be used to bind key sequences to - functions useful for a specific program. For instance, the - following command adds a key sequence that quotes the current - or previous word in Bash: - $if bash - # Quote the current or previous word - "\C-xq": "\eb\"\ef\"" - $endif - -`$endif' - This command, as you saw in the previous example, terminates an - `$if' command. - -`$else' - Commands in this branch of the `$if' directive are executed if the - test fails. - - -File: features.info, Node: Bindable Readline Commands, Next: Readline vi Mode, Prev: Readline Init File, Up: Command Line Editing - -Bindable Readline Commands -========================== - -* Menu: - -* Commands For Moving:: Moving about the line. -* Commands For History:: Getting at previous lines. -* Commands For Text:: Commands for changing text. -* Commands For Killing:: Commands for killing and yanking. -* Numeric Arguments:: Specifying numeric arguments, repeat counts. -* Commands For Completion:: Getting Readline to do the typing for you. -* Keyboard Macros:: Saving and re-executing typed characters -* Miscellaneous Commands:: Other miscellaneous commands. - - -File: features.info, Node: Commands For Moving, Next: Commands For History, Up: Bindable Readline Commands - -Commands For Moving -------------------- - -`beginning-of-line (C-a)' - Move to the start of the current line. - -`end-of-line (C-e)' - Move to the end of the line. - -`forward-char (C-f)' - Move forward a character. - -`backward-char (C-b)' - Move back a character. - -`forward-word (M-f)' - Move forward to the end of the next word. Words are composed of - letters and digits. - -`backward-word (M-b)' - Move back to the start of this, or the previous, word. Words are - composed of letters and digits. - -`clear-screen (C-l)' - Clear the screen and redraw the current line, leaving the current - line at the top of the screen. - -`redraw-current-line ()' - Refresh the current line. By default, this is unbound. - - -File: features.info, Node: Commands For History, Next: Commands For Text, Prev: Commands For Moving, Up: Bindable Readline Commands - -Commands For Manipulating The History -------------------------------------- - -`accept-line (Newline, Return)' - Accept the line regardless of where the cursor is. If this line is - non-empty, add it to the history list according to the setting of - the `HISTCONTROL' variable. If this line was a history line, then - restore the history line to its original state. - -`previous-history (C-p)' - Move `up' through the history list. - -`next-history (C-n)' - Move `down' through the history list. - -`beginning-of-history (M-<)' - Move to the first line in the history. - -`end-of-history (M->)' - Move to the end of the input history, i.e., the line you are - entering. - -`reverse-search-history (C-r)' - Search backward starting at the current line and moving `up' - through the history as necessary. This is an incremental search. - -`forward-search-history (C-s)' - Search forward starting at the current line and moving `down' - through the the history as necessary. This is an incremental - search. - -`non-incremental-reverse-search-history (M-p)' - Search backward starting at the current line and moving `up' - through the history as necessary using a non-incremental search - for a string supplied by the user. - -`non-incremental-forward-search-history (M-n)' - Search forward starting at the current line and moving `down' - through the the history as necessary using a non-incremental search - for a string supplied by the user. - -`history-search-forward ()' - Search forward through the history for the string of characters - between the start of the current line and the current point. This - is a non-incremental search. By default, this command is unbound. - -`history-search-backward ()' - Search backward through the history for the string of characters - between the start of the current line and the current point. This - is a non-incremental search. By default, this command is unbound. - -`yank-nth-arg (M-C-y)' - Insert the first argument to the previous command (usually the - second word on the previous line). With an argument N, insert the - Nth word from the previous command (the words in the previous - command begin with word 0). A negative argument inserts the Nth - word from the end of the previous command. - -`yank-last-arg (M-., M-_)' - Insert last argument to the previous command (the last word on the - previous line). With an argument, behave exactly like - `yank-nth-arg'. - - -File: features.info, Node: Commands For Text, Next: Commands For Killing, Prev: Commands For History, Up: Bindable Readline Commands - -Commands For Changing Text --------------------------- - -`delete-char (C-d)' - Delete the character under the cursor. If the cursor is at the - beginning of the line, there are no characters in the line, and - the last character typed was not C-d, then return EOF. - -`backward-delete-char (Rubout)' - Delete the character behind the cursor. A numeric arg says to kill - the characters instead of deleting them. - -`quoted-insert (C-q, C-v)' - Add the next character that you type to the line verbatim. This is - how to insert key sequences like C-q, for example. - -`tab-insert (M-TAB)' - Insert a tab character. - -`self-insert (a, b, A, 1, !, ...)' - Insert yourself. - -`transpose-chars (C-t)' - Drag the character before the cursor forward over the character at - the cursor, moving the cursor forward as well. If the insertion - point is at the end of the line, then this transposes the last two - characters of the line. Negative argumentss don't work. - -`transpose-words (M-t)' - Drag the word behind the cursor past the word in front of the - cursor moving the cursor over that word as well. - -`upcase-word (M-u)' - Uppercase the current (or following) word. With a negative - argument, do the previous word, but do not move the cursor. - -`downcase-word (M-l)' - Lowercase the current (or following) word. With a negative - argument, do the previous word, but do not move the cursor. - -`capitalize-word (M-c)' - Capitalize the current (or following) word. With a negative - argument, do the previous word, but do not move the cursor. - - -File: features.info, Node: Commands For Killing, Next: Numeric Arguments, Prev: Commands For Text, Up: Bindable Readline Commands - -Killing And Yanking -------------------- - -`kill-line (C-k)' - Kill the text from the current cursor position to the end of the - line. - -`backward-kill-line (C-x Rubout)' - Kill backward to the beginning of the line. - -`unix-line-discard (C-u)' - Kill backward from the cursor to the beginning of the current line. - Save the killed text on the kill-ring. - -`kill-whole-line ()' - Kill all characters on the current line, no matter where the - cursor is. By default, this is unbound. - -`kill-word (M-d)' - Kill from the cursor to the end of the current word, or if between - words, to the end of the next word. Word boundaries are the same - as `forward-word'. - -`backward-kill-word (M-DEL)' - Kill the word behind the cursor. Word boundaries are the same as - `backward-word'. - -`unix-word-rubout (C-w)' - Kill the word behind the cursor, using white space as a word - boundary. The killed text is saved on the kill-ring. - -`delete-horizontal-space ()' - Delete all spaces and tabs around point. By default, this is - unbound. - -`yank (C-y)' - Yank the top of the kill ring into the buffer at the current - cursor position. - -`yank-pop (M-y)' - Rotate the kill-ring, and yank the new top. You can only do this - if the prior command is yank or yank-pop. - - -File: features.info, Node: Numeric Arguments, Next: Commands For Completion, Prev: Commands For Killing, Up: Bindable Readline Commands - -Specifying Numeric Arguments ----------------------------- - -`digit-argument (M-0, M-1, ... M--)' - Add this digit to the argument already accumulating, or start a new - argument. M- starts a negative argument. - -`universal-argument ()' - Each time this is executed, the argument count is multiplied by - four. The argument count is initially one, so executing this - function the first time makes the argument count four. By - default, this is not bound to a key. - - -File: features.info, Node: Commands For Completion, Next: Keyboard Macros, Prev: Numeric Arguments, Up: Bindable Readline Commands - -Letting Readline Type For You ------------------------------ - -`complete (TAB)' - Attempt to do completion on the text before the cursor. This is - application-specific. Generally, if you are typing a filename - argument, you can do filename completion; if you are typing a - command, you can do command completion, if you are typing in a - symbol to GDB, you can do symbol name completion, if you are - typing in a variable to Bash, you can do variable name completion, - and so on. See the Bash manual page for a complete list of - available completion functions. - -`possible-completions (M-?)' - List the possible completions of the text before the cursor. - -`insert-completions ()' - Insert all completions of the text before point that would have - been generated by `possible-completions'. By default, this is not - bound to a key. - - -File: features.info, Node: Keyboard Macros, Next: Miscellaneous Commands, Prev: Commands For Completion, Up: Bindable Readline Commands - -Keyboard Macros ---------------- - -`start-kbd-macro (C-x ()' - Begin saving the characters typed into the current keyboard macro. - -`end-kbd-macro (C-x ))' - Stop saving the characters typed into the current keyboard macro - and save the definition. - -`call-last-kbd-macro (C-x e)' - Re-execute the last keyboard macro defined, by making the - characters in the macro appear as if typed at the keyboard. - - -File: features.info, Node: Miscellaneous Commands, Prev: Keyboard Macros, Up: Bindable Readline Commands - -Some Miscellaneous Commands ---------------------------- - -`re-read-init-file (C-x C-r)' - Read in the contents of your init file, and incorporate any - bindings or variable assignments found there. - -`abort (C-g)' - Abort the current editing command and ring the terminal's bell - (subject to the setting of `bell-style'). - -`do-uppercase-version (M-a, M-b, ...)' - Run the command that is bound to the corresoponding uppercase - character. - -`prefix-meta (ESC)' - Make the next character that you type be metafied. This is for - people without a meta key. Typing `ESC f' is equivalent to typing - `M-f'. - -`undo (C-_, C-x C-u)' - Incremental undo, separately remembered for each line. - -`revert-line (M-r)' - Undo all changes made to this line. This is like typing the `undo' - command enough times to get back to the beginning. - -`tilde-expand (M-~)' - Perform tilde expansion on the current word. - -`dump-functions ()' - Print all of the functions and their key bindings to the readline - output stream. If a numeric argument is supplied, the output is - formatted in such a way that it can be made part of an INPUTRC - file. - -`display-shell-version (C-x C-v)' - Display version information about the current instance of Bash. - -`shell-expand-line (M-C-e)' - Expand the line the way the shell does when it reads it. This - performs alias and history expansion as well as all of the shell - word expansions. - -`history-expand-line (M-^)' - Perform history expansion on the current line. - -`insert-last-argument (M-., M-_)' - A synonym for `yank-last-arg'. - -`operate-and-get-next (C-o)' - Accept the current line for execution and fetch the next line - relative to the current line from the history for editing. Any - argument is ignored. - -`emacs-editing-mode (C-e)' - When in `vi' editing mode, this causes a switch back to emacs - editing mode, as if the command `set -o emacs' had been executed. - - -File: features.info, Node: Readline vi Mode, Prev: Bindable Readline Commands, Up: Command Line Editing - -Readline vi Mode -================ - - While the Readline library does not have a full set of `vi' editing -functions, it does contain enough to allow simple editing of the line. -The Readline `vi' mode behaves as specified in the Posix 1003.2 -standard. - - In order to switch interactively between `Emacs' and `Vi' editing -modes, use the `set -o emacs' and `set -o vi' commands (*note The Set -Builtin::.). The Readline default is `emacs' mode. - - When you enter a line in `vi' mode, you are already placed in -`insertion' mode, as if you had typed an `i'. Pressing ESC switches -you into `command' mode, where you can edit the text of the line with -the standard `vi' movement keys, move to previous history lines with -`k', and following lines with `j', and so forth. - - -File: features.info, Node: Variable Index, Next: Concept Index, Prev: Command Line Editing, Up: Top - -Variable Index -************** - -* Menu: - -* auto_resume: Job Control Variables. -* BASH_VERSION: Bash Variables. -* bell-style: Readline Init Syntax. -* cdable_vars: C Shell Variables. -* CDPATH: Bourne Shell Variables. -* comment-begin: Readline Init Syntax. -* completion-query-items: Readline Init Syntax. -* convert-meta: Readline Init Syntax. -* editing-mode: Readline Init Syntax. -* EUID: Bash Variables. -* expand-tilde: Readline Init Syntax. -* FIGNORE: Bash Variables. -* histchars: Bash Variables. -* HISTCMD: Bash Variables. -* HISTCONTROL: Bash Variables. -* HISTFILE: Bash Variables. -* history_control: Bash Variables. -* HISTSIZE: Bash Variables. -* HOME: Bourne Shell Variables. -* horizontal-scroll-mode: Readline Init Syntax. -* HOSTFILE: Bash Variables. -* hostname_completion_file: Bash Variables. -* HOSTTYPE: Bash Variables. -* IFS: Bourne Shell Variables. -* IGNOREEOF: C Shell Variables. -* IGNOREEOF: Bash Variables. -* INPUTRC: Bash Variables. -* keymap: Readline Init Syntax. -* MAILCHECK: Bash Variables. -* MAILPATH: Bourne Shell Variables. -* mark-modified-lines: Readline Init Syntax. -* meta-flag: Readline Init Syntax. -* nolinks: Bash Variables. -* notify: Job Control Variables. -* no_exit_on_failed_exec: Bash Variables. -* OLDPWD: Korn Shell Variables. -* OPTARG: Bourne Shell Variables. -* OPTIND: Bourne Shell Variables. -* OSTYPE: Bash Variables. -* output-meta: Readline Init Syntax. -* PATH: Bourne Shell Variables. -* PROMPT_COMMAND: Bash Variables. -* PS1: Bourne Shell Variables. -* PS2: Bourne Shell Variables. -* PS3: Korn Shell Variables. -* PS4: Korn Shell Variables. -* PWD: Korn Shell Variables. -* RANDOM: Korn Shell Variables. -* REPLY: Korn Shell Variables. -* SECONDS: Korn Shell Variables. -* show-all-if-ambiguous: Readline Init Syntax. -* TMOUT: Korn Shell Variables. -* UID: Bash Variables. - - -File: features.info, Node: Concept Index, Prev: Variable Index, Up: Top - -Concept Index -************* - -* Menu: - -* $else: Conditional Init Constructs. -* $endif: Conditional Init Constructs. -* $if: Conditional Init Constructs. -* .: Bourne Shell Builtins. -* :: Bourne Shell Builtins. -* abort (C-g): Miscellaneous Commands. -* accept-line (Newline, Return): Commands For History. -* alias: Alias Builtins. -* backward-char (C-b): Commands For Moving. -* backward-delete-char (Rubout): Commands For Text. -* backward-kill-line (C-x Rubout): Commands For Killing. -* backward-kill-word (M-DEL): Commands For Killing. -* backward-word (M-b): Commands For Moving. -* beginning-of-history (M-<): Commands For History. -* beginning-of-line (C-a): Commands For Moving. -* bg: Job Control Builtins. -* bind: Bash Builtins. -* break: Bourne Shell Builtins. -* builtin: Bash Builtins. -* call-last-kbd-macro (C-x e): Keyboard Macros. -* capitalize-word (M-c): Commands For Text. -* case: Conditional Constructs. -* cd: Bourne Shell Builtins. -* clear-screen (C-l): Commands For Moving. -* command: Bash Builtins. -* complete (TAB): Commands For Completion. -* continue: Bourne Shell Builtins. -* declare: Bash Builtins. -* delete-char (C-d): Commands For Text. -* delete-horizontal-space (): Commands For Killing. -* digit-argument (M-0, M-1, ... M-): Numeric Arguments. -* dirs: C Shell Builtins. -* do-uppercase-version (M-a, M-b, ...): Miscellaneous Commands. -* downcase-word (M-l): Commands For Text. -* dump-functions (): Miscellaneous Commands. -* echo: Bourne Shell Builtins. -* enable: Bash Builtins. -* end-kbd-macro (C-x )): Keyboard Macros. -* end-of-history (M->): Commands For History. -* end-of-line (C-e): Commands For Moving. -* eval: Bourne Shell Builtins. -* event designators: Event Designators. -* exec: Bourne Shell Builtins. -* exit: Bourne Shell Builtins. -* expansion: History Interaction. -* export: Bourne Shell Builtins. -* fc: Korn Shell Builtins. -* fg: Job Control Builtins. -* for: Looping Constructs. -* forward-char (C-f): Commands For Moving. -* forward-search-history (C-s): Commands For History. -* forward-word (M-f): Commands For Moving. -* getopts: Bourne Shell Builtins. -* hash: Bourne Shell Builtins. -* help: Bash Builtins. -* history: C Shell Builtins. -* history events: Event Designators. -* History, how to use: Job Control Variables. -* history-search-backward (): Commands For History. -* history-search-forward (): Commands For History. -* if: Conditional Constructs. -* insert-completions (): Commands For Completion. -* interaction, readline: Readline Interaction. -* jobs: Job Control Builtins. -* kill: Bourne Shell Builtins. -* Kill ring: Readline Killing Commands. -* kill-line (C-k): Commands For Killing. -* kill-whole-line (): Commands For Killing. -* kill-word (M-d): Commands For Killing. -* Killing text: Readline Killing Commands. -* let: Korn Shell Builtins. -* let: Arithmetic Builtins. -* local: Bash Builtins. -* logout: C Shell Builtins. -* next-history (C-n): Commands For History. -* non-incremental-forward-search-history (M-n): Commands For History. -* non-incremental-reverse-search-history (M-p): Commands For History. -* popd: C Shell Builtins. -* possible-completions (M-?): Commands For Completion. -* prefix-meta (ESC): Miscellaneous Commands. -* previous-history (C-p): Commands For History. -* pushd: C Shell Builtins. -* pwd: Bourne Shell Builtins. -* quoted-insert (C-q, C-v): Commands For Text. -* re-read-init-file (C-x C-r): Miscellaneous Commands. -* read: Bourne Shell Builtins. -* Readline, how to use: Modifiers. -* readonly: Bourne Shell Builtins. -* redraw-current-line (): Commands For Moving. -* return: Bourne Shell Builtins. -* reverse-search-history (C-r): Commands For History. -* revert-line (M-r): Miscellaneous Commands. -* self-insert (a, b, A, 1, !, ...): Commands For Text. -* set: The Set Builtin. -* shift: Bourne Shell Builtins. -* source: C Shell Builtins. -* start-kbd-macro (C-x (): Keyboard Macros. -* suspend: Job Control Builtins. -* tab-insert (M-TAB): Commands For Text. -* test: Bourne Shell Builtins. -* tilde-expand (M-~): Miscellaneous Commands. -* times: Bourne Shell Builtins. -* transpose-chars (C-t): Commands For Text. -* transpose-words (M-t): Commands For Text. -* trap: Bourne Shell Builtins. -* type: Bash Builtins. -* typeset: Korn Shell Builtins. -* ulimit: Bash Builtins. -* umask: Bourne Shell Builtins. -* unalias: Alias Builtins. -* undo (C-_, C-x C-u): Miscellaneous Commands. -* universal-argument (): Numeric Arguments. -* unix-line-discard (C-u): Commands For Killing. -* unix-word-rubout (C-w): Commands For Killing. -* unset: Bourne Shell Builtins. -* until: Looping Constructs. -* upcase-word (M-u): Commands For Text. -* wait: Bourne Shell Builtins. -* while: Looping Constructs. -* yank (C-y): Commands For Killing. -* yank-last-arg (M-., M-_): Commands For History. -* yank-nth-arg (M-C-y): Commands For History. -* yank-pop (M-y): Commands For Killing. -* Yanking text: Readline Killing Commands. -* [: Bourne Shell Builtins. - - - -Tag Table: -Node: Top1044 -Node: Bourne Shell Features2405 -Node: Looping Constructs3579 -Node: Conditional Constructs4634 -Node: Shell Functions6194 -Node: Bourne Shell Builtins7567 -Node: Bourne Shell Variables9766 -Node: Other Bourne Shell Features11025 -Node: Major Differences from the Bourne Shell11783 -Node: Csh Features14194 -Node: Tilde Expansion15087 -Node: Brace Expansion15691 -Node: C Shell Builtins17283 -Node: C Shell Variables20578 -Node: Korn Shell Features21088 -Node: Korn Shell Constructs21826 -Node: Korn Shell Builtins23037 -Node: Korn Shell Variables25190 -Node: Aliases26466 -Node: Alias Builtins28833 -Node: Bash Specific Features29356 -Node: Invoking Bash30085 -Node: Bash Startup Files32404 -Node: Is This Shell Interactive?34247 -Node: Bash Builtins35055 -Node: The Set Builtin41437 -Node: Bash Variables46377 -Node: Shell Arithmetic50945 -Node: Arithmetic Evaluation51307 -Node: Arithmetic Expansion53028 -Node: Arithmetic Builtins53862 -Node: Printing a Prompt54334 -Node: Job Control55599 -Node: Job Control Basics56074 -Node: Job Control Builtins60249 -Node: Job Control Variables61768 -Node: Using History Interactively63077 -Node: History Interaction63584 -Node: Event Designators64630 -Node: Word Designators65461 -Node: Modifiers66446 -Node: Command Line Editing67755 -Node: Introduction and Notation68415 -Node: Readline Interaction69435 -Node: Readline Bare Essentials70574 -Node: Readline Movement Commands72104 -Node: Readline Killing Commands72995 -Node: Readline Arguments74698 -Node: Readline Init File75649 -Node: Readline Init Syntax76647 -Node: Conditional Init Constructs83580 -Node: Bindable Readline Commands85826 -Node: Commands For Moving86496 -Node: Commands For History87344 -Node: Commands For Text89988 -Node: Commands For Killing91727 -Node: Numeric Arguments93176 -Node: Commands For Completion93803 -Node: Keyboard Macros94816 -Node: Miscellaneous Commands95375 -Node: Readline vi Mode97466 -Node: Variable Index98343 -Node: Concept Index101671 - -End Tag Table diff --git a/documentation/features.ps b/documentation/features.ps deleted file mode 100644 index b8b52cc..0000000 --- a/documentation/features.ps +++ /dev/null @@ -1,3825 +0,0 @@ -%!PS (but not EPSF; comments have been disabled) -%DVIPSCommandLine: dvips -D 300 -o features.ps features.dvi -%DVIPSParameters: dpi=300, compressed, comments removed -%DVIPSSource: TeX output 1995.05.08:1603 -/TeXDict 250 dict def TeXDict begin /N{def}def /B{bind def}N /S{exch}N -/X{S N}B /TR{translate}N /isls false N /vsize 11 72 mul N /hsize 8.5 72 -mul N /landplus90{false}def /@rigin{isls{[0 landplus90{1 -1}{-1 1} -ifelse 0 0 0]concat}if 72 Resolution div 72 VResolution div neg scale -isls{landplus90{VResolution 72 div vsize mul 0 exch}{Resolution -72 div -hsize mul 0}ifelse TR}if Resolution VResolution vsize -72 div 1 add mul -TR[matrix currentmatrix{dup dup round sub abs 0.00001 lt{round}if} -forall round exch round exch]setmatrix}N /@landscape{/isls true N}B -/@manualfeed{statusdict /manualfeed true put}B /@copies{/#copies X}B -/FMat[1 0 0 -1 0 0]N /FBB[0 0 0 0]N /nn 0 N /IE 0 N /ctr 0 N /df-tail{ -/nn 8 dict N nn begin /FontType 3 N /FontMatrix fntrx N /FontBBox FBB N -string /base X array /BitMaps X /BuildChar{CharBuilder}N /Encoding IE N -end dup{/foo setfont}2 array copy cvx N load 0 nn put /ctr 0 N[}B /df{ -/sf 1 N /fntrx FMat N df-tail}B /dfs{div /sf X /fntrx[sf 0 0 sf neg 0 0] -N df-tail}B /E{pop nn dup definefont setfont}B /ch-width{ch-data dup -length 5 sub get}B /ch-height{ch-data dup length 4 sub get}B /ch-xoff{ -128 ch-data dup length 3 sub get sub}B /ch-yoff{ch-data dup length 2 sub -get 127 sub}B /ch-dx{ch-data dup length 1 sub get}B /ch-image{ch-data -dup type /stringtype ne{ctr get /ctr ctr 1 add N}if}B /id 0 N /rw 0 N -/rc 0 N /gp 0 N /cp 0 N /G 0 N /sf 0 N /CharBuilder{save 3 1 roll S dup -/base get 2 index get S /BitMaps get S get /ch-data X pop /ctr 0 N ch-dx -0 ch-xoff ch-yoff ch-height sub ch-xoff ch-width add ch-yoff -setcachedevice ch-width ch-height true[1 0 0 -1 -.1 ch-xoff sub ch-yoff -.1 sub]/id ch-image N /rw ch-width 7 add 8 idiv string N /rc 0 N /gp 0 N -/cp 0 N{rc 0 ne{rc 1 sub /rc X rw}{G}ifelse}imagemask restore}B /G{{id -gp get /gp gp 1 add N dup 18 mod S 18 idiv pl S get exec}loop}B /adv{cp -add /cp X}B /chg{rw cp id gp 4 index getinterval putinterval dup gp add -/gp X adv}B /nd{/cp 0 N rw exit}B /lsh{rw cp 2 copy get dup 0 eq{pop 1}{ -dup 255 eq{pop 254}{dup dup add 255 and S 1 and or}ifelse}ifelse put 1 -adv}B /rsh{rw cp 2 copy get dup 0 eq{pop 128}{dup 255 eq{pop 127}{dup 2 -idiv S 128 and or}ifelse}ifelse put 1 adv}B /clr{rw cp 2 index string -putinterval adv}B /set{rw cp fillstr 0 4 index getinterval putinterval -adv}B /fillstr 18 string 0 1 17{2 copy 255 put pop}for N /pl[{adv 1 chg} -{adv 1 chg nd}{1 add chg}{1 add chg nd}{adv lsh}{adv lsh nd}{adv rsh}{ -adv rsh nd}{1 add adv}{/rc X nd}{1 add set}{1 add clr}{adv 2 chg}{adv 2 -chg nd}{pop nd}]dup{bind pop}forall N /D{/cc X dup type /stringtype ne{] -}if nn /base get cc ctr put nn /BitMaps get S ctr S sf 1 ne{dup dup -length 1 sub dup 2 index S get sf div put}if put /ctr ctr 1 add N}B /I{ -cc 1 add D}B /bop{userdict /bop-hook known{bop-hook}if /SI save N @rigin -0 0 moveto /V matrix currentmatrix dup 1 get dup mul exch 0 get dup mul -add .99 lt{/QV}{/RV}ifelse load def pop pop}N /eop{SI restore userdict -/eop-hook known{eop-hook}if showpage}N /@start{userdict /start-hook -known{start-hook}if pop /VResolution X /Resolution X 1000 div /DVImag X -/IE 256 array N 0 1 255{IE S 1 string dup 0 3 index put cvn put}for -65781.76 div /vsize X 65781.76 div /hsize X}N /p{show}N /RMat[1 0 0 -1 0 -0]N /BDot 260 string N /rulex 0 N /ruley 0 N /v{/ruley X /rulex X V}B /V -{}B /RV statusdict begin /product where{pop product dup length 7 ge{0 7 -getinterval dup(Display)eq exch 0 4 getinterval(NeXT)eq or}{pop false} -ifelse}{false}ifelse end{{gsave TR -.1 .1 TR 1 1 scale rulex ruley false -RMat{BDot}imagemask grestore}}{{gsave TR -.1 .1 TR rulex ruley scale 1 1 -false RMat{BDot}imagemask grestore}}ifelse B /QV{gsave newpath transform -round exch round exch itransform moveto rulex 0 rlineto 0 ruley neg -rlineto rulex neg 0 rlineto fill grestore}B /a{moveto}B /delta 0 N /tail -{dup /delta X 0 rmoveto}B /M{S p delta add tail}B /b{S p tail}B /c{-4 M} -B /d{-3 M}B /e{-2 M}B /f{-1 M}B /g{0 M}B /h{1 M}B /i{2 M}B /j{3 M}B /k{ -4 M}B /w{0 rmoveto}B /l{p -4 w}B /m{p -3 w}B /n{p -2 w}B /o{p -1 w}B /q{ -p 1 w}B /r{p 2 w}B /s{p 3 w}B /t{p 4 w}B /x{0 S rmoveto}B /y{3 2 roll p -a}B /bos{/SS save N}B /eos{SS restore}B end -TeXDict begin 40258431 52099146 1000 300 300 (features.dvi) -@start /Fa 1 59 df<127012F8A3127005057C840D>58 D E /Fb -1 59 df<127812FCA4127806067B8510>58 D E /Fc 35 122 df<126012F0A212701210 -A31220A21240A2040B7D830B>44 D48 -D<12035AB4FC1207B3A2EA7FF80D187D9713>III<1318A21338137813F813B8EA01381202A212041208121812101220124012C0 -B5FCEA0038A6EA03FF10187F9713>I -II<1240EA7FFF13 -FEA2EA4004EA80081310A2EA00201340A21380120113005AA25A1206A2120EA512041019 -7E9813>I -II<39FFE1FFC039 -0E001C00AB380FFFFC380E001CAC39FFE1FFC01A1A7F991D>72 D<39FFE01FC0390E000F -00140C14085C5C5C495A0102C7FC5B130C131C132E1347EB8380EA0F03380E01C06D7EA2 -147080A280141E141F39FFE07FC01A1A7F991E>75 D82 D<39FF801FE0391E00070014066C13046C130CEB800800035BEA01C06D -5A00001360EB7040EB78801338011DC7FC131F130EAAEBFFC01B1A7F991D>89 -D97 D99 D<133F1307A9EA03E7EA0C17EA180F487E127012E0A6126012706C -5AEA1C373807C7E0131A7F9915>II103 D<12FC121CA9137CEA1D87381E0380A2121CAB38FF9FF014 -1A809915>I<1218123CA212181200A612FC121CAE12FF081A80990A>I<12FC121CA9EB1F -C0EB0F00130C5B13205B13E0121DEA1E70EA1C7813387F131E7F148038FF9FE0131A8099 -14>107 D<12FC121CB3A6EAFF80091A80990A>I110 DII114 DI<1208A41218A2 -1238EAFFC0EA3800A81320A41218EA1C40EA07800B177F960F>I<38FC1F80EA1C03AB13 -07120CEA0E0B3803F3F01410808F15>I<38FF0F80383C0700EA1C061304A26C5AA26C5A -A3EA03A0A2EA01C0A36C5A11107F8F14>I<39FE7F1F8039381C0700003C1306381C0C04 -130E380E16081317A238072310149013A33803C1A014E0380180C0A319107F8F1C>I<38 -FE3F80383C1E00EA1C086C5AEA0F306C5A6C5A12017F1203EA0270487E1208EA181CEA38 -1E38FC3FC012107F8F14>I<38FF0F80383C0700EA1C061304A26C5AA26C5AA3EA03A0A2 -EA01C0A36C5AA248C7FCA212E112E212E4127811177F8F14>I E -/Fd 1 59 df<126012F0A2126004047D830B>58 D E /Fe 68 127 -df<126012F0AD12601200A4126012F0A212600417789614>33 D<13801201A2EA07E0EA -1FF0EA39BCEA619CEAC18EA3EAE184EA7180127FEA1FE0EA0FF0EA01F8139C138EEA4186 -12E1A3EA718CEA39B8EA1FF0EA0FC0EA0180A212000F1D7E9914>36 -D40 D<128012C01260123012381218121C120EA31207A9120EA3121C121812 -381230126012C01280081D7C9914>I<127012F812FCA2127C120C1218123012E012C006 -0A798414>44 DI<127012F8A312700505798414>I48 D<1203A25A5A123F12F712471207AEEA7FF0A20C177C9614>III<137813F8EA01B8A2EA0338A21206120E120C121C12381230127012E0B51280A2 -38003800A548B4FCA211177F9614>I<127012F8A312701200A6127012F8A31270051079 -8F14>58 D<130E133E137C13F0EA03E0EA07C0EA1F00123E12F85A7E123E7EEA07C0EA03 -E0EA00F0137C133E130E0F137E9414>60 D<124012E012F8127C121EEA0F80EA07C0EA01 -F0EA00F8133E131E133E13F8EA01F0EA07C0EA0F80EA1E00127C5A12E012400F157E9514 ->62 DI65 DI< -3801F180EA07FFEA0E1FEA1C071238EA7003A348C7FCA738700380A338380700121CEA0E -0EEA07FCEA01F011177F9614>IIIII<38FE3F80A238380E00A8EA3FFEA2EA380EA938FE3F80A211177F9614>II75 -DI<38FC1F80A2007C1300EA7637A4EA7777 -A2EA7367A313E7EA71C7A2EA7007A638F80F80A211177F9614>I<38FE3F80A2383E0E00 -123BA4138E1239A213CEA31238A213EE136EA4133E12FEA211177F9614>III82 DI<387FFF80B5FCEA -E1C3A43801C000AFEA0FF8A211177F9614>I<38FE0FE0A238380380B0381C0700A2EA0E -0EEA07FCEA01F01317809614>I<38FC1F80A238380E00A3EA3C1EEA1C1CA46C5AA4EA06 -30EA0770A3EA0360A213E0A26C5A11177F9614>I<38FC1F80A238700700A7EA31C6EA33 -E6EA3BEE136EA5EA1B6CA2EA1A2CEA1E3CA311177F9614>I<38FC1F80A238380E00EA3C -1EEA1C1CEA1E3CEA0E38A26C5AA2EA036013E0A26C5AA8EA07F0A211177F9614>89 -DII<12 -04121FEA7FC0EAF1E012E00B057C9614>94 D97 -D<12FCA2121CA513F8EA1DFEEA1F07EA1E03001C1380EB01C0A6EB0380001E1300EA1F0E -EA1DFCEA0CF81217809614>II<137EA2130EA5EA07CEEA0FFEEA1C3EEA -301EEA700E12E0A61270EA301EEA383E381FEFC0EA07CF12177F9614>II<13FCEA01FEEA038EEA07041300A3EA7FFE12FFEA0700ACEAFFF8A20F17 -7F9614>II<12FCA2121CA51378EA1DFEEA1F86EA1E07121CAA38FF8FE0A21317809614>I<1206 -120FA21206C7FCA4B4FCA21207ACEAFFF8A20D187C9714>I<136013F0A213601300A4EA -1FF0A2EA0070B2EA40E0EAE0C0EA7F80EA3F000C207E9714>I<12FCA2121CA5EBFF80A2 -EB1C005B5B5BEA1DC0EA1FE0A2EA1E70EA1C38133C131C7F38FF1F80A21117809614>I< -EAFF80A21203B3EAFFFEA20F177E9614>III< -EA07C0EA1FF0EA3C78EA701CA2EAE00EA6EA701CEA783CEA3C78EA1FF0EA07C00F107E8F -14>IIIII< -1206120EA4EA7FFC12FFEA0E00A8130EA3131CEA07F8EA01F00F157F9414>II<38FE3F80A2383C1E00EA1C1CA36C5AA3 -EA0630EA0770A36C5AA311107F8F14>I<38FE3F80A238700700EA380EA3EA39CEA3EA1B -6C121AA3EA1E7CA2EA0E3811107F8F14>II<38FE3F80A2381C0E005BA2 -120E5BA212071330A2EA0370A25B1201A25BA3485A12730077C7FC127E123C11187F8F14 ->II126 -D E /Ff 51 122 df<903907FC0FE090393FFF3FF89039FC03FC783A03F007F0FC3807E0 -0F15E0D80FC0147802071300A7B71280A23A0FC007E000B3A239FFFC7FFFA226267FA524 ->11 DI<123C127E12FFA4127E123C08 -087C8711>46 D<131C133C13FC12FFA21200B3AA387FFFFCA216237CA21F>49 -D<48B4FC000713C0381E07F0383803F8386001FC387C00FE12FE14FF147FA2127C003813 -FFC7FC14FEA2EB01FC14F8EB03F0EB07E01480EB0F00131E5B1370EBE003EA01C0380380 -07380700061206380FFFFE5A5A4813FCB5FCA218237DA21F>I<48B4FC000713E0381E03 -F0383801F8003C13FC387E00FEA3123EEA1C01000013FCA2EB03F8EB07F0EB0FC03801FF -00A2380007E0EB01F014F8EB00FC14FE14FFA21210127C12FEA214FEA2387C01FC007013 -F8383E07F0380FFFC00001130018237DA21F>I<14381478A214F8130113031307130613 -0C131C13381330136013E0EA01C01380EA03005A120E5A12185A12705AB612C0A2390001 -F800A790387FFFC0A21A237EA21F>I<0018130C001F137CEBFFF814F014E014C01480EB -FC000018C7FCA513FF001B13E0381F03F0381C00F8000813FCC7127EA3147FA2127812FC -A3147E5A006013FC1270383801F8381E07E03807FFC03801FE0018237DA21F>II<1230123C003FB512C0A215804814005C5C3860 -0018A200E05B485B5CC6485AA249C7FC1306130EA25BA2133CA25BA213F8A41201A66C5A -13601A257DA41F>II<141CA2143EA3147FA24A7EA39038019FC0A29038031FE0140F01077FEB0607 -A2010C7F1403011C7FEB1801A2496C7EA2017FB5FCA29039E0007F8049133FA248488015 -1F00038190C7120FA2486E7ED8FFF090B51280A229257EA42E>65 -DI<9138FF8008010FEBF01890393FC03C -789039FE0006F8D801F81303484813014848130048481478121F48481438A2007F151890 -C8FCA2481500A97E16187F123FA26C6C1430120F6C6C14606C6C14C06C6CEB0180D800FE -EB070090383FC01E90380FFFF8010013C025257DA42C>IIII72 -DI75 DIII82 D<01FF1380000713E3380F80F7381E001F48130F481307140312F81401A2 -7E91C7FCB4FCEA7FE013FE383FFFE014F86C13FE00077F6C1480C67E010313C0EB003FEC -0FE01407A200C01303A315C07E6C13076C14806CEB0F0038FFC03E38E3FFF838803FE01B -257DA422>I<007FB612F8A2397E00FE010078EC00780070153800601518A200E0151C16 -0C5AA4C71400B3A390B512FEA226247EA32B>I87 D89 -D97 -DIII<137F3803FFC03807C1F0380F80F8EA1F0048137C127E147E -12FEA2B512FEA248C7FCA3127EA214067E6C130C380F80183807E0703803FFE038007F80 -17187E971C>II<3901FF07C00007EBDFE0380F83F1EA1F01393E00F800 -007E7FA6003E5B6C485A380F83E0EBFFC0001190C7FC0030C8FCA21238123C383FFFE06C -13FC806C7F481480383C003F48EB0FC000F81307A4007CEB0F806CEB1F00381F807E3807 -FFF8C613C01B247E971F>II<120FEA1F80EA3FC0A4EA1F80EA0F00 -C7FCA7EA7FC0A2120FB3A2EAFFF8A20D277EA611>I<131E133FEB7F80A4EB3F00131E90 -C7FCA73801FF80A2EA001FB3A8127800FC13005B133EEA787CEA3FF8EA0FE0113283A613 ->III<26FF80FE137F903A83FF81FFC03B0F8E0FC7 -07E0019813CC903A9007E803F001A013F0A201C013E0AF3BFFFC7FFE3FFFA230187E9733 ->I<38FF80FE903883FF80390F8E0FC0139890389007E013A0A213C0AF39FFFC7FFEA21F -187E9722>II<38FFC1FC -EBCFFF390FFC1FC09038F007E001C013F0140315F8140115FCA8EC03F8A215F0EBE00790 -38F00FE09038DC1F809038CFFF00EBC3F801C0C7FCA9EAFFFCA21E237F9722>I<38FF83 -E0EB8FF8380F8C7CEB90FC13B013A01478EBE0005BAEEAFFFEA216187F9719>114 -D<3807F8C0EA1FFFEA3C07EA7001EAF000A300FC1300B47EEA7FFC7F383FFF80000F13C0 -120338001FE01303EAC001A212E014C0EAF00338FC078038EFFF00EAC3FC13187E9718> -I<13C0A41201A312031207120F121FB512C0A2380FC000AC1460A63807E0C013E13801FF -8038007E0013237FA218>I<39FFC07FE0A2000F1307B0140FA200071317EBE0673903FF -C7FE38007F071F187E9722>I<39FFF80FF8A2390FC001C015803907E00300A26D5A0003 -1306EBF80E0001130C13FC00005B13FEEB7E30A26D5AA214E06D5AA26D5AA26DC7FCA21D -187F9720>I<39FFF83FF0A2390FC00F003807E00E6C6C5A6D5A6C6C5A00001360EB7EC0 -6D5AA2131F6D7E497E80EB33F81361EBE0FC3801C07E3803807F3907003F8048131F39FF -C07FF8A21D187F9720>120 D<39FFF80FF8A2390FC001C015803907E00300A26D5A0003 -1306EBF80E0001130C13FC00005B13FEEB7E30A26D5AA214E06D5AA26D5AA26DC7FCA213 -06A25B1230EA781CEAFC185B1370EA68E0EA7FC0001FC8FC1D237F9720>I -E /Fg 39 122 df12 -D<903803F03F90391E09E0809039380F80C09039701F01E0EBE03E021E13C02601C01CC7 -FCA548485A007FB612803903803803A43A0700700700A6000EEBE00EA64848485A001EEB -E01E3AFF8FF8FFC023207E9F26>14 D35 -D45 D<13181338EA01F8EA0E701200A513E0A6EA01C0A6EA0380 -A6EA07001380EAFFFC0E1E7B9D17>49 DI<120E121FA2121E120C1200 -AA1230127812F81278127008147C930D>58 D<001FB512FE4814FFC9FCA8B612FC6C14F8 -200C7D9023>61 D<3807FF803800F8001378A25BA6485AA6485AA6485AA648C7FC7FEAFF -F0111F7E9E10>73 D<3A07FF803FE03A00F8001F000178130C5D4913205D5D4AC7FC1402 -140848485A5C146014F013E1EBE4F83803C878EBD07CEBE03CEBC03E141E141F48487E81 -140781140381380F00016D487E39FFF00FFE231F7E9E23>75 D79 D<0007B5FC3900F803C090387800F015785B157C -A41578484813F815F0EC01E0EC03C0EC0F00EBFFFCD803C0C7FCA6485AA648C8FC7FEAFF -F81E1F7E9E1F>I83 -D<3A03FFC0FFC03A007F003E00013C1318013E1310011E5B011F5B6D5B0281C7FCEB0783 -14C2EB03C414E8EB01F0A2130080A2EB017CEB023CEB043EEB0C1EEB081F497E13200140 -7FEB8007000180EB0003000780391F8007F039FFC01FFE221F7F9E22>88 -D97 D<1207123F120F7EA2120EA65A137CEA1D -83381E0180001C13C0EB00E05A14F0A5387001E0A214C013031480EB0700EAE80EEACC38 -EA83E014207B9F19>I<13FEEA0383380E0780121C0038130090C7FC12785AA45AA37E5B -EA70026C5AEA1C18EA07E011147D9314>I<1438EB01F8EB00781438A21470A614E013FC -EA0382EA0601121CEA3C00383801C0127812F0A438E00380A412F0EA700738380F00381C -37803807C7E015207D9F19>I<13F8EA070EEA0E07121C383803801278127012F0A2B5FC -00F0C7FC5AA46C5AEA7002EA3004EA1C18EA07E011147D9314>II<140EEB3E11EBE1A33801C1C2380381E0EA07801301120FA3380703C01480EB87 -00EA04FC48C7FCA21218121CEA0FFF14C014E0381800F04813305A5AA3006013606C13C0 -381C0700EA07FC181F809417>I<13E0120712011200A2485AA6485AEB8F80EB90E013A0 -EBC0601380000713E01300A5380E01C0A6381C0380001E13C038FF8FF014207E9F19>I< -EA01C0EA03E0A213C0EA0180C7FCA6EA0380121F12071203A2EA0700A6120EA65A121EEA -FF800B1F7F9E0C>II<13E0120712011200A2485A -A6485AEB81FCEB80F014C0EB81801400EA07045B13181338137C131C120E7FA2130F7F14 -80EA1C03381E07C038FF8FF016207E9F18>I<13E0120712011200A2EA01C0A6EA0380A6 -EA0700A6120EA65A121EEAFF800B207F9F0C>I<390387C07C391F9861863907A0720739 -03C03403EB80380007EB7807EB0070A5000EEBE00EA64848485A001EEBE01E3AFFCFFCFF -C022147E9326>I<38038F80381F90E0EA07A03803C0601380000713E01300A5380E01C0 -A6381C0380001E13C038FF8FF014147E9319>I<13FCEA0387380E0180381C00C04813E0 -A24813F012F0A438E001E0A214C0130300F0138038700700EA380E6C5AEA07E014147D93 -17>IIIII<1380EA0100A35A5A5A121EEAFFF8EA0E00A45AA65A1310 -A41320A2EA1840EA0F800D1C7C9B12>I<381C0380EAFC1FEA3C07EA1C03A238380700A6 -EA700EA4131EA25BEA305E381F9F8011147B9319>I<38FF83F8381E00E0001C13C01480 -121E380E01005B13025B12075BA25BEA039013A013E05B5B120190C7FC15147C9318>I< -39FF9FE1FC393C078070391C030060148015401580EA0E0790380D81001309EB19C21311 -380F21C4EA0720EB40C814E8EB80F0A26C485A1460000213401E147C9321>I<381FF0FF -3803C0780001137014403800E0C0EBE180EB73001376133CA2131C132E134E1387EA0107 -380203801204380C01C0383C03E038FE07FC18147F9318>I<390FF83F803901E00E00EB -C00C140813E000005B143014205C13705CA20171C7FC1339133A133E133C133813181310 -A25BA25BEA70C0EAF08000F1C8FC12E61278191D809318>I E /Fh -44 122 df12 D45 D49 DII<157015F0140114031407 -140FA2141F143F147714F714E7EB01C7EB0387EB0707130F130E131C1338137013F013E0 -EA01C0EA0380EA07005A120E5A5A5A5AB712E0A3C7380FF000A9010FB512E0A3232E7EAD -28>I<000C1430390FC007F090B512E015C0158015005C14F85C1480000EC8FCA8EB1FF0 -EBFFFE390FE03F809038000FC0000EEB07E0000C14F0C713F8140315FCA215FEA2121812 -3E127F5AA215FCA25A0078EB07F815F06CEB0FE06CEB1FC0390FC07F806CB51200000113 -FC38003FE01F2E7CAD28>I<14FF010713E0011F7F90387F80F89038FE003CD801F8137C -484813FE00071301EA0FE0A2EA1FC0003F6D5A157892C7FC485AA338FF83FC90388FFF80 -90389C0FC09038B003F06E7E01E07F01C07F140081A2491480A4127FA4003F15007F121F -5D000F495AEA07E06C6C485A3901FC0FE06CB55A013F90C7FCEB0FFC212E7DAD28>I<12 -38123E003FB612C0A316804815005D5D5D0078C7123800705C5D00F0495A48495A4AC7FC -A2C7120E5C5C1478147014F0495AA213035C1307A2130FA2131F5CA2133FA4137FA86DC8 -FC131E22307CAF28>I<1578A215FCA34A7EA24A7EA24A7FA34A7FEC0E7F021E7FEC1C3F -A202387F151F02787FEC700FA202E07F1507010180ECC003A249486C7EA201078191C7FC -498191B6FCA24981011CC7123F013C810138141FA24981160F01F081491407A248488148 -6C1403B549B512FCA336317DB03D>65 DI<913A03FF800180023FEBF00349B5EAFC0701079038003F0FD91FF8EB07 -9FD93FC0EB01FFD9FF807F4848C8127F4848153F0007161F49150F485A001F1607A2485A -1703127FA24992C7FCA212FFA9127FA27FEF0380123FA26C7E1707000F17006C7E6D150E -0003161E6C6C151C6C6C6C1478D93FC05CD91FF8EB03E0D907FFEB3F800101D9FFFEC7FC -D9003F13F80203138031317CB03A>I69 DI72 DI<017FB512C0A39039001FF000B3AF121C123E127FEAFF80A25D14 -3FD87F005B007E5C003C49C7FC381F01FE3807FFF8C613C022317DB02A>III<90391FF8018090B51203000314C73907F007EF390F8000FF48C7 -127F003E141F150F5A150712FCA215037EA26C91C7FC13C0EA7FF0EBFF806C13F8ECFF80 -6C14F06C806C806C14FFC6FC013F1480010114C0D9001F13E01401EC003FED1FF0150F15 -07126000E01403A316E07EA26CEC07C07EB4EC0F8001C0EB1F00D8FBFC13FE00F1B512F8 -D8E03F5BD8C003138024317CB02D>83 D<007FB8FCA39039C00FF801D87E00EC003F007C -82007882A200708200F01780A3481603A5C792C7FCB3AA017FB6FCA331307DAF38>III97 DIIIII<90391FF007C09039FFFE3FE03A01F83F79F03907E00FC3000F14E19039C007E0 -E0001FECF000A2003F80A5001F5CA2000F5CEBE00F00075C2603F83FC7FC3806FFFE380E -1FF090C9FC121EA2121F7F90B57E6C14F015FC6C806C801680000F15C0003FC7127F007E -EC1FE0007C140F00FC1407A4007EEC0FC0003E1580003F141FD80FC0EB7E003907F803FC -0001B512F0D8001F90C7FC242F7E9F28>II< -EA03C0487E487E487EA46C5A6C5A6C5AC8FCA9EA01F8127FA31207B3A7B51280A311337D -B217>I108 -D<2703F007F8EB1FE000FFD93FFEEBFFF8913A783F01E0FC02C090388300FE280FF1801F -C6137F2607F30013CC01F602F8148001FC5CA3495CB3B500C3B5380FFFFCA33E207D9F43 ->I<3903F007F800FFEB3FFEEC783F02C013803A0FF1801FC03807F30001F614E013FCA3 -5BB3B500C3B5FCA328207D9F2D>II<3901F83FE000FFEBFFFC9038FBE07F9039FF003F80D807FEEB1FC049EB0FE04914 -F0ED07F8A216FC1503A216FEA816FC1507A216F8A2ED0FF06D14E06DEB1FC06DEB3F8090 -39FBC0FE009038F8FFF8EC3FC091C8FCABB512C0A3272E7E9F2D>I<3803F03F00FFEB7F -C09038F1C3E01487390FF30FF0EA07F6A29038FC07E0EC03C091C7FCA25BB2B512E0A31C -207E9F21>114 D<3801FF86000713FEEA1F00003C133E48131E140E12F8A36C90C7FCB4 -7E13FC387FFFC06C13F0806C7F00077F00017FEA003F01001380143F0060131F00E0130F -A27E15007E6C131E6C131C38FF807838F3FFF038C07F8019207D9F20>I<131CA5133CA3 -137CA213FC120112031207381FFFFEB5FCA2D803FCC7FCB0EC0380A71201EC0700EA00FE -EB7F0EEB3FFCEB07F0192E7FAD1F>II< -B5EB1FFCA3D80FF8EB03C0000715806D1307000315007F0001140E7F6C5CA2EC803C017F -1338ECC078013F1370ECE0F0011F5B14F1010F5B14F9903807FB80A214FF6D90C7FCA26D -5AA26D5AA21478A226207E9F2B>I<3A7FFF807FFCA33A03FC000F006C6C131E6C6C5BEC -803890387FC078013F5B90381FE1E090380FF3C0ECFF806D90C7FC6D5A13016D7E81815B -903803DFE09038078FF08190380F07FC90381E03FEEB3C01496C7E4914804848EB7FC000 -03EC3FE026FFFC01B5FCA328207F9F2B>120 DI -E /Fi 1 14 df<14FF010713E090381F00F80178131E01E01307D80180EB018048C812C0 -00061560481530A248151848150CA2481506A4481503A900601506A46C150CA26C15186C -1530A26C15606C15C06C6CEB0180D800E0EB07000178131E011F13F8903807FFE0010090 -C7FC282B7EA02D>13 D E /Fj 64 122 df<49B4FC011F13C090387F81E0EBFC013901F8 -07F01203EA07F0A4EC01C091C8FCA3EC3FF8B6FCA33807F003B3A33A7FFF3FFF80A3212A -7FA925>12 D<131CA3EB7F803803FFE0000F13F8381F9CFC383E1C1E003C7F007C7F0078 -EB0F8000F8131F143FA312FC00FEEB1F0000FF90C7FCEA7FDC13FCEBFFC06C7F6C7F6C13 -FC7E00017F6C6C7E131F131CEC3F800038131F127C00FE130FA312FC00F8140012705C00 -38131E003C5B381F9CF86CB45A00035BC690C7FC131CA319307CAC22>36 -D<123C127FEAFF80A213C0A3127F123E1200A2EA0180A3EA0300A21206120E5A5A12100A -157B8813>44 DI<121C127FA2EAFF80A3EA7F00A2121C09097B -8813>I<130E131E137EEA07FE12FFA212F81200B3ABB512FEA317277BA622>49 -DII<140FA25C5C5C5C5BA2EB03 -BFEB073F130E131C133C1338137013E0EA01C0EA038012071300120E5A5A5A12F0B612F8 -A3C7EA7F00A890381FFFF8A31D277EA622>I<00181303381F801FEBFFFE5C5C5C14C091 -C7FC001CC8FCA7EB7FC0381DFFF8381F80FC381E003F1208C7EA1F8015C0A215E0A21218 -127C12FEA315C05A0078EB3F80A26CEB7F00381F01FE6CB45A000313F0C613801B277DA6 -22>II<1238123E003FB512F0A34814E015C0158015003870000EA25C485B5C5CC6485AA249 -5A130791C7FC5B5B131E133EA2137E137CA213FCA41201A76C5A13701C297CA822>III<121C127FA2EAFF80A3EA7F00A2121CC7FCA9121C127FA2EA -FF80A3EA7F00A2121C091B7B9A13>I<48B4FC000F13E0381E03F0383801F8387800FC00 -FC13FE7EA3127C003813FCEA0001EB03F8EB07E0EB0FC01480EB1E00A25B1338A25BA790 -C7FCA5137013F8487E487EA36C5A6C5A1370172A7CA920>63 D65 DI<91387FE003903907FFFC07011FEBFF0F90397FF00F9F9039FF0001FFD801FC7F48 -48147F4848143F4848141F485A160F485A1607127FA290C9FC5AA97E7F1607123FA26C7E -160E6C7E6C6C141C6C6C143C6C6C14786CB4EB01F090397FF007C0011FB512800107EBFE -009038007FF028297CA831>IIII<91387FE003903907FFFC07011FEBFF0F -90397FF00F9F9039FF0001FFD801FC7F484880484880484880485A82485A82127FA290CA -FC5AA892B512F87E7F03001300123FA26C7EA26C7E6C7E6C7E6C7E6CB45B90387FF00701 -1FB5129F0107EBFE0F9039007FF0032D297CA835>III<90B512F8A301001300B3A91218127EB4FCA35C387E01FC007C5B -383E07F0380FFFE0000390C7FC1D297EA823>IIIIIIIII<9038FF80600003EBF0E0000F13 -F8381F80FD383F001F003E1307481303A200FC1301A214007EA26C140013C0EA7FFCEBFF -E06C13F86C13FE80000714806C14C0C6FC010F13E0EB007FEC1FF0140F140700E01303A4 -6C14E0A26C13076C14C0B4EB0F80EBE03F39E3FFFE0000E15B38C01FF01C297CA825>I< -007FB71280A39039807F807FD87C00140F00781507A20070150300F016C0A2481501A5C7 -91C7FCB3A490B612C0A32A287EA72F>IIII89 -D91 D<3803FF80000F13F0381F01FC38 -3F80FE147F801580EA1F00C7FCA4EB3FFF3801FC3FEA0FE0EA1F80EA3F00127E5AA4145F -007E13DF393F839FFC381FFE0F3803FC031E1B7E9A21>97 DIIIII<9038FF80F00003EBE3F8390FC1FE1C391F007C7C48137E -003EEB3E10007EEB3F00A6003E133E003F137E6C137C380FC1F8380BFFE00018138090C8 -FC1238A2123C383FFFF814FF6C14C06C14E06C14F0121F383C0007007CEB01F8481300A4 -007CEB01F0A2003FEB07E0390FC01F806CB5120038007FF01E287E9A22>II<1207EA0F80EA1FC0EA3FE0A3EA1FC0EA0F80EA0700C7FCA7EAFFE0A3 -120FB3A3EAFFFEA30F2B7EAA12>I107 DI<26 -FFC07FEB1FC0903AC1FFC07FF0903AC307E0C1F8D80FC49038F101FC9039C803F20001D8 -01FE7F01D05BA201E05BB03CFFFE3FFF8FFFE0A3331B7D9A38>I<38FFC07E9038C1FF80 -9038C30FC0D80FC413E0EBC80701D813F013D0A213E0B039FFFE3FFFA3201B7D9A25>I< -EB3FE03801FFFC3803F07E390FC01F80391F800FC0393F0007E0A2007EEB03F0A300FE14 -F8A8007E14F0A26CEB07E0A2391F800FC0390FC01F803907F07F003801FFFC38003FE01D -1B7E9A22>I<38FFE1FE9038EFFF809038FE0FE0390FF803F09038F001F801E013FC1400 -15FEA2157FA8157E15FEA215FC140101F013F89038F807F09038FC0FE09038EFFF809038 -E1FC0001E0C7FCA9EAFFFEA320277E9A25>I<38FFC1F0EBC7FCEBC63E380FCC7F13D813 -D0A2EBF03EEBE000B0B5FCA3181B7F9A1B>114 D<3803FE30380FFFF0EA3E03EA780012 -7000F01370A27E00FE1300EAFFE06CB4FC14C06C13E06C13F0000713F8C6FCEB07FC1300 -00E0137C143C7E14387E6C137038FF01E038E7FFC000C11300161B7E9A1B>I<13E0A412 -01A31203A21207120F381FFFE0B5FCA2380FE000AD1470A73807F0E0000313C03801FF80 -38007F0014267FA51A>I<39FFE07FF0A3000F1307B2140FA2000713173903F067FF3801 -FFC738007F87201B7D9A25>I<39FFFC03FFA3390FF000F0000714E07F0003EB01C0A2EB -FC0300011480EBFE070000140013FFEB7F0EA2149EEB3F9C14FC6D5AA26D5AA36D5AA26D -5AA2201B7F9A23>I<3BFFFC7FFC1FFCA33B0FE00FE001C02607F007EB0380A201F8EBF0 -0700031600EC0FF801FC5C0001150EEC1FFC2600FE1C5B15FE9039FF387E3C017F1438EC -787F6D486C5A16F0ECE01F011F5CA26D486C5AA2EC800701075CA22E1B7F9A31>I<39FF -FC1FFEA33907F003803803F8079038FC0F003801FE1E00005BEB7F3814F86D5A6D5A130F -806D7E130F497EEB3CFEEB38FFEB787F9038F03F803901E01FC0D803C013E0EB800F39FF -F03FFFA3201B7F9A23>I<39FFFC03FFA3390FF000F0000714E07F0003EB01C0A2EBFC03 -00011480EBFE070000140013FFEB7F0EA2149EEB3F9C14FC6D5AA26D5AA36D5AA26D5AA2 -5CA21307003890C7FCEA7C0FEAFE0E131E131C5BEA74F0EA3FE0EA0F8020277F9A23>I -E /Fk 91 127 df<127012F8B012701200A5127012F8A31270051C779B18>33 -DI -I<13C01201A3EA03F0EA0FFCEA3FFEEA7DCFEA71C738E1C38013C7A338F1C0001279123F -6C7EEA0FF8EA01FC13DE13CF13C73861C38012F1A212E1EBC7001271EA79DEEA3FFEEA1F -F8EA07E0EA01C0A3120011247D9F18>III<1238127CA2127E -123E120EA3121CA2123812F812F012C0070E789B18>I<137013F0EA01E0EA03C0EA0780 -EA0F00121E121C5AA25AA45AA81270A47EA27E121E7EEA0780EA03C0EA01F0120013700C -24799F18>I<126012F012787E7E7EEA07801203EA01C0A2EA00E0A41370A813E0A4EA01 -C0A2EA03801207EA0F00121E5A5A5A12600C247C9F18>II<136013F0A7387FFFC0B512E0A26C13C03800F000A7136013147E9718>I<121C -123E127E127F123F121F1207120E121E127C12F81260080C788518>I<387FFFC0B512E0 -A26C13C013047E8F18>I<1230127812FCA2127812300606778518>I<1303EB0780A2130F -14005B131EA2133E133C137C1378A213F85B12015B12035BA212075B120F90C7FCA25A12 -1E123E123CA2127C127812F85AA2126011247D9F18>IIIII<131F5B1377A213E7120113C7EA03 -8712071307120E121E123C1238127812F0B512F8A338000700A6EB7FF0A3151C7F9B18> -I<383FFF80A30038C7FCA8EA3BF8EA3FFE7F383C0780383003C0EA0001EB00E0A2126012 -F0A238E001C0EA7003387C0F80383FFF00EA1FFCEA03F0131C7E9B18>I<137E48B4FC00 -071380380F83C0EA1E03121C3838018090C7FC5AA2EAE1F8EAE7FEB5FC38FE078038F803 -C0EAF001EB00E05A7E1270A3383801C0EA3C03381E0780380FFF006C5AEA01F8131C7E9B -18>I<12E0B512E0A214C038E00380EB0700C65A131E131C5BA25B13F05BA2485AA3485A -A448C7FCA7131D7E9C18>I<1230127812FCA2127812301200A81230127812FCA2127812 -300614779318>58 D<1218123C127EA2123C12181200A81218123C127EA2123E121E120E -121C123C127812F01260071A789318>I<14C0EB03E01307EB1FC0EB3F80EBFE00485AEA -07F0485AEA3F8048C7FC12FCA2127F6C7EEA0FE06C7EEA01FC6C7EEB3F80EB1FC0EB07E0 -1303EB00C013187E9918>I<387FFFC0B512E0A3C8FCA4B512E0A36C13C0130C7E9318>I< -126012F87E127F6C7EEA0FE06C7EEA01FC6C7EEB3F80EB1FC0EB07E0A2EB1FC0EB3F80EB -FE00485AEA07F0485AEA3F8048C7FC12FC5A126013187E9918>II<137CEA01FEEA07FF380F8780381E03C0EA3C1DEA387F3870FFE0EA71 -E313C112E1EAE380A638E1C1C0127113E33870FF8038387F00EA3C1C381E00E0EA0F8338 -07FFC00001138038007E00131C7E9B18>I<137013F8A213D8A2EA01DCA3138CEA038EA4 -EA0707A5380FFF80A3EA0E03381C01C0A3387F07F000FF13F8007F13F0151C7F9B18>I< -EA7FFCB5FC6C1380381C03C01301EB00E0A4130114C01307381FFF80140014C0EA1C03EB -00E014F01470A414F014E01303387FFFC0B51280387FFE00141C7F9B18>IIIII<3801F1C0EA03FDEA0FFFEA1F0FEA1C03123813011270A290C7 -FC5AA5EB0FF0131F130F387001C0A213031238A2EA1C07EA1F0FEA0FFFEA03FDEA01F114 -1C7E9B18>I<387F07F038FF8FF8387F07F0381C01C0A9EA1FFFA3EA1C01AA387F07F038 -FF8FF8387F07F0151C7F9B18>II<387F07F038FF87F8387F07F0381C03C0EB07801400130E131E5B1338 -5B13F0121DA2EA1FB8A2131C121EEA1C0EA27FA2EB0380A2EB01C0387F03F038FF87F838 -7F03F0151C7F9B18>75 DI<38FC01 -F8EAFE03A2383B06E0A4138EA2EA398CA213DCA3EA38D8A213F81370A21300A638FE03F8 -A3151C7F9B18>I<387E07F038FF0FF8387F07F0381D81C0A313C1121CA213E1A3136113 -71A213311339A31319A2131D130DA3EA7F07EAFF87EA7F03151C7F9B18>IIIII<3803F1C0EA1FFF5AEA7C0FEA7003EAE001A390C7FC12701278123FEA1FF0 -EA07FEC67EEB0F80EB03C01301EB00E0A2126012E0130100F013C038F80780B5FCEBFE00 -EAE7F8131C7E9B18>I<387FFFF8B5FCA238E07038A400001300B2EA07FFA3151C7F9B18> -I<38FF83FEA3381C0070B36C13E0EA0F01380783C03803FF806C1300EA007C171C809B18 ->I<38FE03F8EAFF07EAFE03383C01E0001C13C0A3EA1E03000E1380A438070700A4EA03 -8EA4EA018C13DCA3EA00D813F8A21370151C7F9B18>I<38FE03F8A338700070A36C13E0 -A513F8EA39FC13DCA2001913C0A3138CA2EA1D8DA31305000D1380EA0F07A2EA0E03151C -7F9B18>I<387F0FE0139F130F380E0700120FEA070E138EEA039C13DCEA01F8A212005B -137013F07F487E13DCEA039E138EEA070F7F000E13801303001E13C0387F07F000FF13F8 -007F13F0151C7F9B18>I<38FE03F8EAFF07EAFE03381C01C0EA1E03000E1380EA0F0700 -071300A2EA038EA2EA01DCA3EA00F8A21370A9EA01FC487E6C5A151C7F9B18>I<383FFF -E05AA2387001C01303EB07801400C65A131E131C133C5B137013F0485A5B1203485A90C7 -FC5A001E13E0121C123C5A1270B5FCA3131C7E9B18>II<126012F0A27E1278127C123CA2123E121E121F7EA27F12077F1203A27F -12017F12007F1378A2137C133C133E131EA2131F7F14801307A2EB030011247D9F18>I< -EAFFF8A3EA0038B3ACEAFFF8A30D247F9F18>II<387FFFC0B512E0A26C13C013047E7F18>I<1206121E123E12381270 -A212E0A312F812FC127CA21238070E789E18>II<127E12FE127E120EA5133EEBFF80000F13C0EBC1E01380EB0070120E1438A600 -0F1370A2EB80E013C1EBFFC0000E138038063E00151C809B18>IIIII<3801E1F03807FFF85A381E -1E30381C0E00487EA5EA1C0EEA1E1EEA1FFC5BEA39E00038C7FC7EEA1FFEEBFFC04813E0 -387801F038700070481338A4007813F0EA7E03381FFFC06C13803801FC00151F7F9318> -I<127E12FE127E120EA5133EEBFF80000F13C013C1EB80E01300120EAB387FC7FC38FFE7 -FE387FC7FC171C809B18>II<1338137CA313381300A4EA0FFCA3EA001CB3A4EA6038EAF078EAFF -F0EA7FE0EA3F800E277E9C18>I<127E12FE127E120EA5EB3FF0A3EB0780EB0F00131E5B -5B5BEA0FF87F139C130EEA0E0F7FEB038014C0387FC7F812FF127F151C7F9B18>II<38F9C1C038FFF7F013FF383E3E38EA3C3CA2EA -3838AB38FE3E3EEB7E7EEB3E3E1714809318>IIII<3801F380EA07FBEA1FFFEA3E1FEA380FEA7007A2EAE003A6EA7007A2EA380FEA3C1F -EA1FFFEA0FFBEA03E3EA0003A7EB1FF0EB3FF8EB1FF0151E7E9318>I<38FF0FC0EB3FE0 -EB7FF0EA07F0EBE060EBC0005BA290C7FCA9EAFFFC7F5B14147E9318>II<487E1203A4387FFFC0B5FCA238038000A9144014 -E0A33801C1C013FF6C1380EB3E0013197F9818>I<387E07E0EAFE0FEA7E07EA0E00AC13 -01EA0F033807FFFC6C13FE3801FCFC1714809318>I<387F8FF000FF13F8007F13F0381C -01C0380E0380A338070700A3138FEA038EA3EA01DCA3EA00F8A2137015147F9318>I<38 -FF07F8138F1307383800E0A4381C01C0137113F9A213D9EA1DDD000D1380A3138DEA0F8F -A23807070015147F9318>I<387F8FF0139F138F380F0700EA078EEA039EEA01DC13F812 -00137013F07FEA01DCEA039E138EEA0707000E1380387F8FF000FF13F8007F13F015147F -9318>I<387F8FF000FF13F8007F13F0380E01C0EB0380A21207EB0700A2EA0387A2138E -EA01CEA213CC120013DC1378A31370A313F05B1279EA7BC0EA7F806CC7FC121E151E7F93 -18>I<383FFFF05AA2387001E0EB03C0EB078038000F00131E5B13F8485AEA03C0485A38 -0F0070121E5A5AB512F0A314147F9318>II<126012F0B3B0126004 -24769F18>I<127CB4FC13C01203C67EAB7FEB7FC0EB3FE0A2EB7FC0EBF0005BABEA03C0 -12FF90C7FC127C13247E9F18>II E /Fl 82 124 df<90381F83E09038F06E303901C07878380380F8903800F03048 -EB7000A7B612803907007000B2383FE3FF1D20809F1B>11 D<133FEBE0C0EA01C0380381 -E0EA0701A290C7FCA6B512E0EA0700B2383FC3FC1620809F19>II<90381F81F89038F04F043901C0 -7C06390380F80FEB00F05A0270C7FCA6B7FC3907007007B23A3FE3FE3FE02320809F26> -I<127012F8A71270AA1220A51200A5127012F8A3127005217CA00D>33 -DI<127012F812FCA212741204A31208A21210A212201240060E7C9F0D>39 -D<13401380EA01005A12061204120C5AA212381230A212701260A412E0AC1260A4127012 -30A212381218A27E120412067E7EEA008013400A2E7BA112>I<7E12407E12307E120812 -0C7EA212077EA213801201A413C0AC1380A412031300A25A1206A25A120812185A12205A -5A0A2E7EA112>I<127012F012F8A212781208A31210A31220A21240050E7C840D>44 -DI<127012F8A3127005057C840D>I<144014C0EB0180A3EB0300 -A31306A25BA35BA35BA25BA35BA3485AA348C7FCA21206A35AA35AA25AA35AA35AA2122D -7EA117>II<13801203120F12F31203B3A6EA -07C0EAFFFE0F1E7C9D17>III<1306A2130EA2131E132EA2134E138EA2EA -010E1202A212041208A212101220A2124012C0B512F038000E00A7EBFFE0141E7F9D17> -II<137CEA -0182EA0701380E0380EA0C0712183838030090C7FC12781270A2EAF1F0EAF21CEAF406EA -F807EB0380A200F013C0A51270A214801238EB07001218EA0C0E6C5AEA01F0121F7E9D17 ->I<1240387FFFE014C0A23840008038800100A21302485AA25B5BA25BA21360A213E05B -1201A41203A76C5A131F7E9D17>III<127012F8A312 -701200AA127012F8A3127005147C930D>I<127012F8A312701200AA127012F012F8A212 -781208A31210A31220A21240051D7C930D>I63 D<5B497EA3497EA3EB09E0A3EB10F0A3EB2078A3497EA2EBC03EEB801E -A248B5FCEB000FA20002EB0780A348EB03C0A2120C001E14E039FF801FFE1F207F9F22> -65 DI<90380FE010903838 -1C309038E002703803C00139078000F048C71270121E15305A1510127C127800F81400A9 -1278007C1410123CA26C1420A27E6C6C13406C6C13803900E00300EB380CEB0FF01C217E -9F21>IIII<90380FE0 -109038381C309038E002703803C00139078000F048C71270121E15305A1510127C127800 -F81400A7EC3FFEEC01F000781300127C123CA27EA27E6C7E3903C001703900E002309038 -380C1090380FF0001F217E9F24>I<39FFF07FF8390F000780AD90B5FCEB0007AF39FFF0 -7FF81D1F7E9E22>II<3807FFC038003E00131E -B3A3122012F8A3EAF01CEA403CEA6038EA1070EA0FC012207F9E17>I<39FFF007FC390F -0003E0EC0180150014025C5C5C5C5C5C49C7FC5B497E130FEB13C0EB21E01341EB80F0EB -0078A28080A280EC0780A2EC03C015E015F039FFF01FFE1F1F7E9E23>IIIIIIII<3803 -F040380C0CC0EA1803EA3001EA6000A212E01440A36C13007E127CEA7F80EA3FF86CB4FC -00071380C613C0EB1FE013031301EB00F014707EA46C136014E06C13C038F8018038C603 -00EA81FC14217E9F19>I<007FB512E038780F010060EB006000401420A200C014300080 -1410A400001400B3497E3803FFFC1C1F7E9E21>I<39FFF00FF8390F0003E0EC0080B3A4 -6CEB01001380120314026C6C5A6C6C5AEB3830EB0FC01D207E9E22>I<39FFF003FE391F -8000F86CC7126015206C6C1340A36C6C1380A2EBE00100011400A23800F002A213F8EB78 -04A26D5AA36D5AA2131F6D5AA2EB07C0A36D5AA36DC7FC1F207F9E22>I<3BFFF07FF81F -F03B1F000FC007C06C903907800180170015C001805C00071502EC09E013C000035DEC19 -F01410D801E05CA2EC2078D800F05CA2EC403C01785CA2EC801E017C1460013C14409038 -3D000F133F6D5CA2011E1307010E91C7FCA2010C7F010413022C207F9E2F>I<39FFF001 -FF391F800078000F146012076D1340000314807F3901F001001200EBF802EB7C06EB3C04 -EB3E08131EEB1F10EB0FB0EB07A014E06D5AACEB3FFC201F7F9E22>89 -D<387FFFFE387E003C127800701378006013F814F0384001E0130314C0EB07801200EB0F -00131EA25B137C13785B1201EBE002EA03C0A2EA0780000F13061300001E1304003E130C -123C48133C14FCB5FC171F7E9E1C>I<12FFA212C0B3B3A512FFA2082D7CA10D>II<12 -FFA21203B3B3A512FFA2082D80A10D>I<120812101220A21240A21280A312B812FCA212 -7C1238060E7D9F0D>96 DI<121C12FC121CAA13 -7CEA1D87381E0180EB00C0001C13E01470A21478A6147014F014E0001E13C0381A018038 -198700EA107C15207E9F19>IIII<137CEA01C6EA030F1207EA0E061300A7 -EAFFF0EA0E00B2EA7FE01020809F0E>I<14E03803E330EA0E3CEA1C1C38380E00EA780F -A5EA380E6C5AEA1E38EA33E00020C7FCA21230A2EA3FFE381FFF8014C0383001E0386000 -70481330A4006013606C13C0381C03803803FC00141F7F9417>I<121C12FC121CAA137C -1386EA1D03001E1380A2121CAE38FF8FF014207E9F19>I<1238127CA31238C7FCA6121C -12FC121CB1EAFF80091F7F9E0C>I<13E0EA01F0A3EA00E01300A61370EA07F012001370 -B3A31260EAF06013C0EA6180EA3F000C28829E0E>I<121C12FC121CAAEB1FE0EB0780EB -060013045B5B5B136013E0EA1DF0EA1E70EA1C38133C131C7F130F7F148014C038FF9FF0 -14207E9F18>I<121C12FC121CB3ABEAFF8009207F9F0C>I<391C3E03E039FCC30C30391D -039038391E01E01CA2001C13C0AE3AFF8FF8FF8021147E9326>III< -EA1C7CEAFD87381E018014C0381C00E014F014701478A6147014F014E0381E01C0EB0380 -381D8700EA1C7C90C7FCA8B47E151D7E9319>I<3801F04038070CC0EA0E02EA1C03EA38 -011278127012F0A6127012781238EA1C03EA0C05EA0709EA01F1EA0001A8EB0FF8151D7F -9318>III<1202A31206A2120EA2123EEAFFF8EA0E00AB1304A5EA07 -081203EA01F00E1C7F9B12>I<381C0380EAFC1FEA1C03AE1307120CEA061B3803E3F014 -147E9319>I<38FF83F8383E00E0001C13C06C1380A338070100A21383EA0382A2EA01C4 -A213E4EA00E8A21370A3132015147F9318>I<39FF9FE1FC393C078070391C030060EC80 -20000E1440A214C0D80704138014E0A239038861001471A23801D032143A143E3800E01C -A2EB6018EB40081E147F9321>I<38FF87F8381E03C0380E0180EB0300EA0702EA0384EA -01C813D8EA00F01370137813F8139CEA010E1202EA060738040380000C13C0003C13E038 -FE07FC16147F9318>I<38FF83F8383E00E0001C13C06C1380A338070100A21383EA0382 -A2EA01C4A213E4EA00E8A21370A31320A25BA3EAF080A200F1C7FC1262123C151D7F9318 ->III -E /Fm 9 118 df66 D70 D97 D<49B47E010F13F0017F13FC9038FF81FE -3A03FE007F80D807F8133F4848EB1FC0ED0FE0485A003F15F01507485A16F8A212FFA290 -B6FCA301C0C8FCA4127FA36C7E1678121F7F000F15F06C6C13016C6CEB03E06C6CEB0FC0 -3A00FFC07F8090393FFFFE00010F13F8010013C025267DA52C>101 -D<13FE12FFA412071203B0EDFF80020313F0020F7F91381E03FC91383801FE02607F4A7E -01FF15805C91C7FCA35BB3A4B5D8F83F13FEA42F3C7CBB36>104 -D<3901FC03F000FFEB0FFC4AB4FC91383C3F80EC707F00079038E0FFC000035BEBFD80A2 -01FFEB7F809138003F00151E92C7FC5BB3A3B512FCA422267DA528>114 -D<90383FF0383903FFFE7848EBFFF8381FC00F383F0003003E13005A157812FCA27E6C14 -0013C013FC387FFFF06C13FEECFF806C14C06C14E0000314F0C614F8011F13FCEB007FEC -07FE0070130100F01300157E7EA27E157C6C14FC6C14F890388001F09038F00FE000F9B5 -12C0D8F07F130038C01FF81F267DA526>I<130FA55BA45BA25BA25B5A5A5A001FEBFFF0 -B6FCA3000190C7FCB3153CA86C14781480017F13F090383FC1E090381FFFC06D13809038 -01FE001E377EB626>I<01FEEC3F8000FFEC3FFFA400071401000380B3A45DA25D120115 -066C6C4913C090267F807813FE6DB45A6D5B010313802F267CA536>I -E end -TeXDict begin - -1 0 bop 0 1176 a Fm(Bash)32 b(F)-8 b(eatures)p 0 1210 -1950 17 v 1261 1258 a Fl(Ov)o(erview)16 b(Do)q(cumen)o(tation)f(for)g -(Bash)1244 1312 y(Edition)h(1.14,)d(for)i Fk(bash)g Fl(V)l(ersion)h -(1.14.)1701 1366 y(August)f(1994)0 2467 y Fj(Brian)23 -b(F)-6 b(o)n(x,)23 b(F)-6 b(ree)23 b(Soft)n(w)n(are)f(F)-6 -b(oundation)0 2534 y(Chet)22 b(Ramey)-6 b(,)23 b(Case)e(W)-6 -b(estern)23 b(Reserv)n(e)f(Univ)n(ersit)n(y)p 0 2570 -1950 9 v eop -2 1 bop 0 2661 a Fl(Cop)o(yrigh)o(t)226 2660 y(c)214 -2661 y Fi(\015)15 b Fl(1991,)f(1993)g(F)l(ree)h(Soft)o(w)o(are)f(F)l -(oundation,)h(Inc.)p eop -1 2 bop 0 -58 a Fl(Chapter)15 b(1:)k(Bourne)d(Shell)h(St)o(yle)f(F)l -(eatures)1143 b(1)0 183 y Fh(1)41 b(Bourne)15 b(Shell)e(St)n(yle)h(F)-7 -b(eatures)62 369 y Fl(Bash)20 b(is)g(an)g(acron)o(ym)f(for)g(Bourne)i -(Again)f(SHell.)35 b(The)20 b(Bourne)h(shell)g(is)f(the)g(traditional)h -(Unix)f(shell)0 432 y(originally)f(written)f(b)o(y)f(Stephen)i(Bourne.) -27 b(All)19 b(of)e(the)h(Bourne)f(shell)j(builtin)f(commands)f(are)f(a) -o(v)m(ailable)i(in)0 494 y(Bash,)g(and)f(the)g(rules)h(for)e(ev)m -(aluation)j(and)e(quoting)g(are)g(tak)o(en)g(from)f(the)h(P)o(osix)g -(1003.2)f(sp)q(eci\014cation)j(for)0 556 y(the)15 b(`standard')f(Unix)i -(shell.)62 693 y(This)g(section)f(brie\015y)h(summarizes)f(things)g -(whic)o(h)h(Bash)f(inherits)h(from)e(the)g(Bourne)i(shell:)21 -b(shell)16 b(con)o(trol)0 755 y(structures,)i(builtins,)i(v)m -(ariables,)g(and)e(other)g(features.)27 b(It)18 b(also)g(lists)h(the)f -(signi\014can)o(t)h(di\013erences)g(b)q(et)o(w)o(een)0 -818 y(Bash)c(and)h(the)f(Bourne)h(Shell.)0 1041 y Fj(1.1)33 -b(Lo)r(oping)15 b(Constructs)62 1178 y Fl(Note)g(that)g(wherev)o(er)h -(y)o(ou)f(see)h(a)f(`)p Fk(;)p Fl(')g(in)h(the)g(description)h(of)e(a)g -(command's)g(syn)o(tax,)g(it)h(ma)o(y)e(b)q(e)j(replaced)0 -1240 y(indiscriminately)h(with)e(one)f(or)g(more)g(newlines.)62 -1377 y(Bash)h(supp)q(orts)f(the)g(follo)o(wing)h(lo)q(oping)g -(constructs.)0 1527 y Fk(until)120 b Fl(The)15 b(syn)o(tax)g(of)g(the)g -Fk(until)f Fl(command)h(is:)360 1589 y Fk(until)23 b -Fg(test-commands)r Fk(;)g(do)h Fg(consequen)o(t-commands)r -Fk(;)g(done)240 1663 y Fl(Execute)14 b Fg(consequen)o(t-commands)i -Fl(as)d(long)h(as)f(the)h(\014nal)h(command)e(in)i Fg(test-commands)g -Fl(has)e(an)240 1726 y(exit)j(status)e(whic)o(h)i(is)g(not)f(zero.)0 -1813 y Fk(while)120 b Fl(The)15 b(syn)o(tax)g(of)g(the)g -Fk(while)f Fl(command)h(is:)360 1875 y Fk(while)23 b -Fg(test-commands)r Fk(;)g(do)h Fg(consequen)o(t-commands)r -Fk(;)g(done)240 1949 y Fl(Execute)14 b Fg(consequen)o(t-commands)i -Fl(as)d(long)h(as)f(the)h(\014nal)h(command)e(in)i Fg(test-commands)g -Fl(has)e(an)240 2011 y(exit)j(status)e(of)h(zero.)0 2098 -y Fk(for)168 b Fl(The)15 b(syn)o(tax)g(of)g(the)g(for)g(command)g(is:) -360 2160 y Fk(for)23 b Fg(name)k Fk([in)c Fg(w)o(ords)i -Fk(...];)f(do)f Fg(commands)r Fk(;)h(done)240 2235 y -Fl(Execute)11 b Fg(commands)g Fl(for)f(eac)o(h)g(mem)o(b)q(er)h(in)g -Fg(w)o(ords)p Fl(,)f(with)g Fg(name)j Fl(b)q(ound)e(to)f(the)g(curren)o -(t)g(mem)o(b)q(er.)240 2297 y(If)15 b(\\)p Fk(in)g Fg(w)o(ords)r -Fl(")f(is)i(not)f(presen)o(t,)f(\\)p Fk(in)h("$@")p Fl(")f(is)i -(assumed.)0 2521 y Fj(1.2)33 b(Conditional)16 b(Constructs)0 -2670 y Fk(if)192 b Fl(The)15 b(syn)o(tax)g(of)g(the)g -Fk(if)g Fl(command)g(is:)p eop -2 3 bop 0 -58 a Fl(2)1646 b(Bash)15 b(F)l(eatures)360 -183 y Fk(if)24 b Fg(test-commands)r Fk(;)f(then)408 233 -y Fg(consequen)o(t-commands)r Fk(;)360 283 y([elif)g -Fg(more-test-commands)r Fk(;)g(then)408 333 y Fg(more-consequen)o(ts)r -Fk(;])360 382 y([else)g Fg(alternate-consequen)o(ts)r -Fk(;])360 432 y(fi)240 508 y Fl(Execute)e Fg(consequen)o(t-commands)h -Fl(only)f(if)g(the)g(\014nal)g(command)f(in)h Fg(test-commands)h -Fl(has)e(an)240 570 y(exit)c(status)e(of)h(zero.)20 b(Otherwise,)c(eac) -o(h)f Fk(elif)g Fl(list)h(is)f(executed)i(in)f(turn,)f(and)g(if)h(its)f -(exit)h(status)240 633 y(is)g(zero,)f(the)h(corresp)q(onding)h -Fg(more-consequen)o(ts)g Fl(is)f(executed)h(and)f(the)f(command)h -(completes.)240 695 y(If)i(\\)p Fk(else)d Fg(alternate-consequen)o(ts)r -Fl(")j(is)h(presen)o(t,)f(and)h(the)f(\014nal)h(command)f(in)h(the)g -(\014nal)g Fk(if)e Fl(or)240 757 y Fk(elif)e Fl(clause)h(has)f(a)g -(non-zero)g(exit)h(status,)e(then)h(execute)h Fg(alternate-consequen)o -(ts)p Fl(.)0 846 y Fk(case)144 b Fl(The)15 b(syn)o(tax)g(of)g(the)g -Fk(case)g Fl(command)g(is:)360 910 y Fk(case)23 b Fg(w)o(ord)i -Fk(in)f([)p Fg(pattern)f Fk([|)h Fg(pattern)p Fk(]...\))f -Fg(commands)i Fk(;;]...)e(esac)240 986 y Fl(Selectiv)o(ely)c(execute)e -Fg(commands)h Fl(based)e(up)q(on)h Fg(w)o(ord)h Fl(matc)o(hing)e -Fg(pattern)p Fl(.)23 b(The)16 b(`)p Fk(|)p Fl(')g(is)h(used)g(to)240 -1048 y(separate)e(m)o(ultiple)i(patterns.)240 1124 y(Here)d(is)h(an)f -(example)g(using)h Fk(case)e Fl(in)i(a)f(script)g(that)f(could)i(b)q(e) -g(used)f(to)g(describ)q(e)h(an)f(in)o(teresting)240 1186 -y(feature)h(of)g(an)g(animal:)360 1249 y Fk(echo)23 b(-n)h("Enter)f -(the)g(name)h(of)f(an)h(animal:)f(")360 1299 y(read)g(ANIMAL)360 -1349 y(echo)g(-n)h("The)f($ANIMAL)g(has)h(")360 1399 -y(case)f($ANIMAL)g(in)408 1448 y(horse)g(|)h(dog)f(|)h(cat\))f(echo)g -(-n)h("four";;)408 1498 y(man)f(|)h(kangaroo)f(\))g(echo)h(-n)f -("two";;)408 1548 y(*\))g(echo)h(-n)f("an)h(unknown)f(number)g(of";;) -360 1598 y(esac)360 1648 y(echo)g("legs.")0 1881 y Fj(1.3)33 -b(Shell)16 b(F)-6 b(unctions)62 2019 y Fl(Shell)20 b(functions)f(are)f -(a)g(w)o(a)o(y)g(to)f(group)h(commands)g(for)g(later)g(execution)h -(using)g(a)f(single)i(name)e(for)g(the)0 2082 y(group.)36 -b(They)21 b(are)f(executed)h(just)g(lik)o(e)g(a)g Fk(")p -Fl(regular)p Fk(")f Fl(command.)36 b(Shell)22 b(functions)g(are)e -(executed)h(in)h(the)0 2144 y(curren)o(t)15 b(shell)i(con)o(text;)d(no) -h(new)h(pro)q(cess)f(is)h(created)f(to)g(in)o(terpret)g(them.)62 -2282 y(F)l(unctions)h(are)f(declared)i(using)e(this)h(syn)o(tax:)120 -2407 y Fk([)24 b(function)e(])i Fg(name)j Fk(\(\))c({)h -Fg(command-list)q Fk(;)h(})62 2545 y Fl(This)16 b(de\014nes)h(a)e -(function)i(named)e Fg(name)p Fl(.)21 b(The)16 b Fg(b)q(o)q(dy)k -Fl(of)15 b(the)h(function)g(is)g(the)g Fg(command-list)h -Fl(b)q(et)o(w)o(een)f Fk({)0 2608 y Fl(and)d Fk(})p Fl(.)19 -b(This)14 b(list)g(is)g(executed)g(whenev)o(er)g Fg(name)i -Fl(is)d(sp)q(eci\014ed)j(as)c(the)i(name)f(of)g(a)g(command.)19 -b(The)13 b(exit)h(status)0 2670 y(of)h(a)g(function)h(is)f(the)h(exit)f -(status)g(of)f(the)i(last)f(command)g(executed)h(in)g(the)f(b)q(o)q(dy) -l(.)p eop -3 4 bop 0 -58 a Fl(Chapter)15 b(1:)k(Bourne)d(Shell)h(St)o(yle)f(F)l -(eatures)1143 b(3)62 183 y(When)17 b(a)e(function)i(is)g(executed,)g -(the)f(argumen)o(ts)f(to)g(the)i(function)f(b)q(ecome)h(the)f(p)q -(ositional)i(parameters)0 246 y(during)h(its)f(execution.)29 -b(The)18 b(sp)q(ecial)i(parameter)d Fk(#)h Fl(that)f(giv)o(es)h(the)g -(n)o(um)o(b)q(er)h(of)e(p)q(ositional)i(parameters)e(is)0 -308 y(up)q(dated)f(to)f(re\015ect)g(the)g(c)o(hange.)20 -b(P)o(ositional)c(parameter)e(0)h(is)h(unc)o(hanged.)62 -445 y(If)f(the)g(builtin)i(command)e Fk(return)f Fl(is)h(executed)h(in) -f(a)g(function,)g(the)g(function)g(completes)h(and)f(execution)0 -507 y(resumes)g(with)h(the)f(next)h(command)f(after)f(the)h(function)i -(call.)k(When)15 b(a)g(function)h(completes,)g(the)f(v)m(alues)h(of)0 -569 y(the)f(p)q(ositional)h(parameters)e(and)h(the)g(sp)q(ecial)i -(parameter)d Fk(#)h Fl(are)f(restored)g(to)h(the)g(v)m(alues)h(they)f -(had)g(prior)g(to)0 632 y(function)h(execution.)0 852 -y Fj(1.4)33 b(Bourne)15 b(Shell)i(Builtins)62 989 y Fl(The)d(follo)o -(wing)g(shell)h(builtin)g(commands)e(are)g(inherited)i(from)e(the)g -(Bourne)h(shell.)21 b(These)13 b(commands)g(are)0 1052 -y(implemen)o(ted)k(as)e(sp)q(eci\014ed)i(b)o(y)e(the)g(P)o(osix)h -(1003.2)d(standard.)0 1200 y Fk(:)216 b Fl(Do)15 b(nothing)g(b)q(ey)o -(ond)h(expanding)h(an)o(y)d(argumen)o(ts)h(and)g(p)q(erforming)h -(redirections.)0 1286 y Fk(.)216 b Fl(Read)15 b(and)g(execute)g -(commands)g(from)f(the)h Fg(\014lename)j Fl(argumen)o(t)c(in)h(the)g -(curren)o(t)g(shell)h(con)o(text.)0 1371 y Fk(break)120 -b Fl(Exit)15 b(from)g(a)g Fk(for)p Fl(,)f Fk(while)p -Fl(,)g(or)h Fk(until)f Fl(lo)q(op.)0 1457 y Fk(cd)192 -b Fl(Change)15 b(the)g(curren)o(t)h(w)o(orking)e(directory)l(.)0 -1542 y Fk(continue)48 b Fl(Resume)16 b(the)f(next)h(iteration)f(of)g -(an)g(enclosing)i Fk(for)p Fl(,)d Fk(while)p Fl(,)g(or)h -Fk(until)f Fl(lo)q(op.)0 1628 y Fk(echo)144 b Fl(Prin)o(t)15 -b(the)g(argumen)o(ts,)f(separated)h(b)o(y)g(spaces,)h(to)e(the)h -(standard)g(output.)0 1713 y Fk(eval)144 b Fl(The)17 -b(argumen)o(ts)g(are)f(concatenated)h(together)g(in)o(to)g(a)g(single)h -(command,)f(whic)o(h)h(is)g(then)f(read)240 1776 y(and)e(executed.)0 -1861 y Fk(exec)144 b Fl(If)16 b(a)g Fg(command)i Fl(argumen)o(t)d(is)i -(supplied,)h(it)f(replaces)g(the)f(shell.)24 b(If)17 -b(no)f Fg(command)i Fl(is)e(sp)q(eci\014ed,)240 1924 -y(redirections)g(ma)o(y)f(b)q(e)h(used)g(to)e(a\013ect)h(the)g(curren)o -(t)g(shell)i(en)o(vironmen)o(t.)0 2009 y Fk(exit)144 -b Fl(Exit)15 b(the)h(shell.)0 2095 y Fk(export)96 b Fl(Mark)14 -b(the)i(argumen)o(ts)e(as)h(v)m(ariables)h(to)f(b)q(e)h(passed)f(to)g -(c)o(hild)i(pro)q(cesses)e(in)h(the)f(en)o(vironmen)o(t.)0 -2180 y Fk(getopts)72 b Fl(P)o(arse)14 b(options)i(to)e(shell)j(scripts) -f(or)e(functions.)0 2266 y Fk(hash)144 b Fl(Remem)o(b)q(er)17 -b(the)g(full)g(pathnames)g(of)f(commands)g(sp)q(eci\014ed)i(as)e -(argumen)o(ts,)g(so)g(they)g(need)h(not)240 2328 y(b)q(e)f(searc)o(hed) -f(for)g(on)g(subsequen)o(t)h(in)o(v)o(o)q(cations.)0 -2413 y Fk(kill)144 b Fl(Send)16 b(a)f(signal)h(to)f(a)f(pro)q(cess.)0 -2499 y Fk(pwd)168 b Fl(Prin)o(t)15 b(the)g(curren)o(t)h(w)o(orking)e -(directory)l(.)0 2584 y Fk(read)144 b Fl(Read)16 b(a)f(line)i(from)d -(the)h(shell)i(input)f(and)g(use)f(it)h(to)e(set)h(the)g(v)m(alues)i -(of)e(sp)q(eci\014ed)i(v)m(ariables.)0 2670 y Fk(readonly)48 -b Fl(Mark)14 b(v)m(ariables)j(as)e(unc)o(hangable.)p -eop -4 5 bop 0 -58 a Fl(4)1646 b(Bash)15 b(F)l(eatures)0 183 -y Fk(return)96 b Fl(Cause)15 b(a)g(shell)i(function)f(to)e(exit)i(with) -g(a)e(sp)q(eci\014ed)k(v)m(alue.)0 283 y Fk(shift)120 -b Fl(Shift)16 b(p)q(ositional)g(parameters)f(to)f(the)i(left.)0 -383 y Fk(test)0 464 y([)216 b Fl(Ev)m(aluate)16 b(a)f(conditional)h -(expression.)0 564 y Fk(times)120 b Fl(Prin)o(t)15 b(out)g(the)g(user)h -(and)f(system)g(times)g(used)h(b)o(y)f(the)g(shell)i(and)f(its)f(c)o -(hildren.)0 664 y Fk(trap)144 b Fl(Sp)q(ecify)17 b(commands)e(to)f(b)q -(e)i(executed)g(when)g(the)f(shell)i(receiv)o(es)f(signals.)0 -764 y Fk(umask)120 b Fl(Set)15 b(the)h(shell)g(pro)q(cess's)f(\014le)i -(creation)e(mask.)0 863 y Fk(unset)120 b Fl(Cause)15 -b(shell)i(v)m(ariables)f(to)f(disapp)q(ear.)0 963 y Fk(wait)144 -b Fl(W)l(ait)15 b(un)o(til)h(c)o(hild)h(pro)q(cesses)f(exit)g(and)f -(rep)q(ort)g(their)g(exit)h(status.)0 1244 y Fj(1.5)33 -b(Bourne)15 b(Shell)i(V)-6 b(ariables)62 1388 y Fl(Bash)20 -b(uses)h(certain)f(shell)h(v)m(ariables)h(in)f(the)f(same)f(w)o(a)o(y)g -(as)h(the)g(Bourne)g(shell.)36 b(In)21 b(some)e(cases,)i(Bash)0 -1450 y(assigns)15 b(a)g(default)h(v)m(alue)g(to)f(the)g(v)m(ariable.)0 -1612 y Fk(IFS)168 b Fl(A)19 b(list)i(of)d(c)o(haracters)h(that)g -(separate)f(\014elds;)23 b(used)d(when)f(the)h(shell)h(splits)f(w)o -(ords)f(as)g(part)f(of)240 1674 y(expansion.)0 1774 y -Fk(PATH)144 b Fl(A)15 b(colon-separated)h(list)g(of)f(directories)h(in) -g(whic)o(h)g(the)f(shell)i(lo)q(oks)e(for)g(commands.)0 -1874 y Fk(HOME)144 b Fl(The)15 b(curren)o(t)h(user's)e(home)i -(directory)l(.)0 1974 y Fk(CDPATH)96 b Fl(A)15 b(colon-separated)h -(list)g(of)f(directories)h(used)g(as)e(a)h(searc)o(h)g(path)g(for)g -(the)g Fk(cd)g Fl(command.)0 2074 y Fk(MAILPATH)48 b -Fl(A)13 b(colon-separated)h(list)g(of)f(\014les)i(whic)o(h)f(the)g -(shell)h(p)q(erio)q(dically)h(c)o(hec)o(ks)e(for)e(new)i(mail.)20 -b(Y)l(ou)14 b(can)240 2136 y(also)f(sp)q(ecify)i(what)d(message)h(is)h -(prin)o(ted)f(b)o(y)h(separating)f(the)g(\014le)h(name)f(from)g(the)g -(message)g(with)240 2198 y(a)18 b(`)p Fk(?)p Fl('.)29 -b(When)19 b(used)g(in)g(the)g(text)f(of)g(the)h(message,)f -Fk($_)g Fl(stands)g(for)g(the)h(name)f(of)g(the)h(curren)o(t)240 -2261 y(mail\014le.)0 2360 y Fk(PS1)168 b Fl(The)15 b(primary)h(prompt)e -(string.)0 2460 y Fk(PS2)168 b Fl(The)15 b(secondary)h(prompt)e -(string.)0 2560 y Fk(OPTIND)96 b Fl(The)15 b(index)i(of)e(the)g(last)g -(option)g(pro)q(cessed)h(b)o(y)g(the)f Fk(getopts)f Fl(builtin.)0 -2660 y Fk(OPTARG)96 b Fl(The)15 b(v)m(alue)i(of)e(the)g(last)g(option)g -(argumen)o(t)g(pro)q(cessed)h(b)o(y)f(the)g Fk(getopts)f -Fl(builtin.)p eop -5 6 bop 0 -58 a Fl(Chapter)15 b(1:)k(Bourne)d(Shell)h(St)o(yle)f(F)l -(eatures)1143 b(5)0 183 y Fj(1.6)33 b(Other)15 b(Bourne)g(Shell)i(F)-6 -b(eatures)62 321 y Fl(Bash)15 b(implemen)o(ts)g(essen)o(tially)h(the)e -(same)g(grammar,)f(parameter)g(and)h(v)m(ariable)i(expansion,)f -(redirection,)0 384 y(and)h(quoting)g(as)f(the)h(Bourne)g(Shell.)23 -b(Bash)16 b(uses)g(the)g(P)o(osix)f(1003.2)f(standard)i(as)f(the)h(sp)q -(eci\014cation)h(of)e(ho)o(w)0 446 y(these)i(features)f(are)g(to)g(b)q -(e)h(implemen)o(ted.)25 b(There)17 b(are)f(some)g(di\013erences)h(b)q -(et)o(w)o(een)g(the)f(traditional)i(Bourne)0 508 y(shell)f(and)f(the)f -(P)o(osix)h(standard;)f(this)h(section)g(quic)o(kly)h(details)f(the)g -(di\013erences)g(of)f(signi\014cance.)23 b(A)16 b(n)o(um)o(b)q(er)0 -571 y(of)f(these)g(di\013erences)i(are)d(explained)k(in)e(greater)e -(depth)i(in)g(subsequen)o(t)g(sections.)0 789 y Ff(1.6.1)30 -b(Ma)s(jor)15 b(Di\013erences)h(from)e(the)h(Bourne)g(Shell)62 -928 y Fl(Bash)i(implemen)o(ts)g(the)g Fk(!)f Fl(k)o(eyw)o(ord)f(to)h -(negate)g(the)g(return)g(v)m(alue)i(of)e(a)g(pip)q(eline.)26 -b(V)l(ery)17 b(useful)g(when)g(an)0 990 y Fk(if)e Fl(statemen)o(t)f -(needs)i(to)f(act)f(only)i(if)g(a)f(test)f(fails.)62 -1128 y(Bash)i(includes)h(brace)e(expansion)h(\(see)g(Section)g(2.2)e -([Brace)h(Expansion],)g(page)g(7\).)62 1266 y(Bash)h(includes)h(the)f -(P)o(osix)f(and)h Fk(ksh)p Fl(-st)o(yle)f(pattern)g(remo)o(v)m(al)g -Fk(\045\045)h Fl(and)f Fk(##)g Fl(constructs)g(to)g(remo)o(v)o(e)g -(leading)0 1329 y(or)g(trailing)h(substrings)f(from)g(v)m(ariables.)62 -1467 y(The)j(P)o(osix)g(and)g Fk(ksh)p Fl(-st)o(yle)g -Fk($\(\))f Fl(form)g(of)h(command)f(substitution)i(is)f(implemen)o -(ted,)i(and)e(preferred)h(to)0 1529 y(the)c(Bourne)h(shell's)g -Fk(``)f Fl(\(whic)o(h)h(is)g(also)f(implemen)o(ted)i(for)d(bac)o(kw)o -(ards)h(compatibilit)o(y\).)62 1667 y(V)l(ariables)e(presen)o(t)g(in)f -(the)h(shell's)g(initial)h(en)o(vironmen)o(t)e(are)g(automatically)g -(exp)q(orted)h(to)e(c)o(hild)j(pro)q(cesses.)0 1730 y(The)19 -b(Bourne)g(shell)h(do)q(es)f(not)f(normally)h(do)g(this)g(unless)g(the) -g(v)m(ariables)h(are)e(explicitly)j(mark)o(ed)e(using)g(the)0 -1792 y Fk(export)14 b Fl(command.)62 1930 y(The)i(expansion)g -Fk(${#xx})p Fl(,)e(whic)o(h)i(returns)f(the)g(length)h(of)f -Fk($xx)p Fl(,)f(is)i(supp)q(orted.)62 2068 y(The)k Fk(IFS)g -Fl(v)m(ariable)h(is)f(used)g(to)f(split)i(only)f(the)g(results)g(of)g -(expansion,)h(not)e(all)i(w)o(ords.)33 b(This)20 b(closes)g(a)0 -2131 y(longstanding)c(shell)h(securit)o(y)e(hole.)62 -2269 y(It)i(is)g(p)q(ossible)i(to)d(ha)o(v)o(e)h(a)f(v)m(ariable)i(and) -f(a)g(function)h(with)f(the)g(same)f(name;)h Fk(sh)g -Fl(do)q(es)g(not)g(separate)f(the)0 2331 y(t)o(w)o(o)e(name)h(spaces.) -62 2469 y(Bash)j(functions)h(are)e(p)q(ermitted)i(to)e(ha)o(v)o(e)h(lo) -q(cal)g(v)m(ariables,)i(and)e(th)o(us)g(useful)h(recursiv)o(e)f -(functions)h(ma)o(y)0 2532 y(b)q(e)d(written.)62 2670 -y(The)g Fk(noclobber)e Fl(option)h(is)h(a)o(v)m(ailable)h(to)d(a)o(v)o -(oid)h(o)o(v)o(erwriting)g(existing)h(\014les)g(with)g(output)f -(redirection.)p eop -6 7 bop 0 -58 a Fl(6)1646 b(Bash)15 b(F)l(eatures)62 -183 y(Bash)i(allo)o(ws)g(y)o(ou)f(to)g(write)g(a)g(function)i(to)e(o)o -(v)o(erride)g(a)g(builtin,)j(and)e(pro)o(vides)g(access)f(to)g(that)g -(builtin's)0 246 y(functionalit)o(y)g(within)h(the)e(function)h(via)g -(the)f Fk(builtin)f Fl(and)h Fk(command)g Fl(builtins.)62 -382 y(The)f Fk(command)e Fl(builtin)j(allo)o(ws)f(selectiv)o(e)g -(disabling)h(of)e(functions)h(when)f(command)g(lo)q(okup)h(is)g(p)q -(erformed.)62 519 y(Individual)k(builtins)g(ma)o(y)c(b)q(e)i(enabled)h -(or)e(disabled)i(using)e(the)h Fk(enable)e Fl(builtin.)62 -656 y(F)l(unctions)i(ma)o(y)f(b)q(e)h(exp)q(orted)f(to)g(c)o(hildren)i -(via)e(the)h(en)o(vironmen)o(t.)62 793 y(The)g(Bash)f -Fk(read)g Fl(builtin)i(will)g(read)f(a)f(line)h(ending)h(in)f -Fk(\\)f Fl(with)h(the)f Fk(-r)g Fl(option,)g(and)h(will)h(use)e(the)h -Fk($REPLY)0 856 y Fl(v)m(ariable)h(as)d(a)h(default)h(if)g(no)f -(argumen)o(ts)f(are)h(supplied.)62 993 y(The)j Fk(return)f -Fl(builtin)j(ma)o(y)d(b)q(e)h(used)h(to)e(ab)q(ort)g(execution)h(of)g -(scripts)g(executed)g(with)g(the)g Fk(.)g Fl(or)f Fk(source)0 -1055 y Fl(builtins.)62 1192 y(The)f Fk(umask)e Fl(builtin)k(allo)o(ws)d -(sym)o(b)q(olic)h(mo)q(de)g(argumen)o(ts)e(similar)j(to)d(those)h -(accepted)h(b)o(y)f Fk(chmod)p Fl(.)62 1329 y(The)d Fk(test)e -Fl(builtin)k(is)d(sligh)o(tly)i(di\013eren)o(t,)e(as)g(it)h(implemen)o -(ts)g(the)f(P)o(osix)g(1003.2)f(algorithm,)h(whic)o(h)h(sp)q(eci\014es) -0 1391 y(the)j(b)q(eha)o(vior)h(based)g(on)f(the)g(n)o(um)o(b)q(er)g -(of)g(argumen)o(ts.)p eop -7 8 bop 0 -58 a Fl(Chapter)15 b(2:)k(C-Shell)f(St)o(yle)d(F)l(eatures) -1254 b(7)0 183 y Fh(2)41 b(C-Shell)13 b(St)n(yle)h(F)-7 -b(eatures)62 355 y Fl(The)18 b(C-Shell)h(\()p Fk(csh)p -Fl(\))e(w)o(as)f(created)i(b)o(y)f(Bill)j(Jo)o(y)d(at)g(UC)g(Berk)o -(eley)l(.)28 b(It)18 b(is)g(generally)h(considered)f(to)f(ha)o(v)o(e)0 -417 y(b)q(etter)e(features)f(for)g(in)o(teractiv)o(e)h(use)g(than)f -(the)h(original)h(Bourne)f(shell.)21 b(Some)15 b(of)f(the)h -Fk(csh)f Fl(features)g(presen)o(t)0 480 y(in)21 b(Bash)f(include)i(job) -e(con)o(trol,)g(history)g(expansion,)h(`protected')e(redirection,)j -(and)e(sev)o(eral)g(v)m(ariables)i(for)0 542 y(con)o(trolling)16 -b(the)f(in)o(teractiv)o(e)h(b)q(eha)o(viour)g(of)f(the)g(shell)i -(\(e.g.)i Fk(IGNOREEOF)p Fl(\).)62 679 y(See)d(Chapter)f(6)g([Using)g -(History)g(In)o(teractiv)o(ely],)h(page)f(33)f(for)h(details)h(on)f -(history)g(expansion.)0 888 y Fj(2.1)33 b(Tilde)16 b(Expansion)62 -1025 y Fl(Bash)k(has)f(tilde)i(\()p Fk(~)p Fl(\))e(expansion,)i -(similar,)g(but)f(not)f(iden)o(tical,)j(to)d(that)f(of)h -Fk(csh)p Fl(.)33 b(The)19 b(follo)o(wing)i(table)0 1087 -y(sho)o(ws)15 b(what)f(unquoted)i(w)o(ords)e(b)q(eginning)k(with)d(a)g -(tilde)i(expand)e(to.)0 1233 y Fk(~)216 b Fl(The)15 b(curren)o(t)h(v)m -(alue)g(of)f Fk($HOME)p Fl(.)0 1313 y Fk(~/foo)120 b -Fl(`)p Fk($HOME/foo)p Fl(')0 1384 y Fk(~fred/foo)240 -1446 y Fl(The)15 b(sub)q(directory)i Fk(foo)d Fl(of)h(the)g(home)h -(directory)f(of)g(the)g(user)g Fk(fred)p Fl(.)0 1526 -y Fk(~+/foo)96 b Fl(`)p Fk($PWD/foo)p Fl(')0 1605 y Fk(~-)192 -b Fl(`)p Fk($OLDPWD/foo)p Fl(')62 1751 y(Bash)21 b(will)h(also)f(tilde) -h(expand)g(w)o(ords)e(follo)o(wing)h(redirection)h(op)q(erators)e(and)h -(w)o(ords)f(follo)o(wing)h(`)p Fk(=)p Fl(')f(in)0 1813 -y(assignmen)o(t)15 b(statemen)o(ts.)0 2022 y Fj(2.2)33 -b(Brace)14 b(Expansion)62 2159 y Fl(Brace)d(expansion)h(is)g(a)e(mec)o -(hanism)i(b)o(y)f(whic)o(h)h(arbitrary)e(strings)h(ma)o(y)f(b)q(e)i -(generated.)18 b(This)12 b(mec)o(hanism)f(is)0 2222 y(similar)j(to)e -Fg(pathname)g(expansion)i Fl(\(see)f(the)f(Bash)h(man)o(ual)g(page)g -(for)f(details\),)h(but)g(the)g(\014le)g(names)g(generated)0 -2284 y(need)j(not)f(exist.)21 b(P)o(atterns)14 b(to)h(b)q(e)h(brace)g -(expanded)g(tak)o(e)f(the)h(form)e(of)h(an)h(optional)g -Fg(pream)o(ble)p Fl(,)f(follo)o(w)o(ed)h(b)o(y)0 2346 -y(a)h(series)g(of)g(comma-separated)f(strings)h(b)q(et)o(w)o(een)g(a)g -(pair)h(of)e(braces,)h(follo)o(w)o(ed)h(b)o(y)f(an)g(optional)g -Fg(p)q(ostam)o(ble)p Fl(.)0 2408 y(The)f(pream)o(ble)h(is)f(prep)q -(ended)i(to)d(eac)o(h)h(string)g(con)o(tained)h(within)g(the)f(braces,) -g(and)g(the)g(p)q(ostam)o(ble)g(is)h(then)0 2471 y(app)q(ended)g(to)d -(eac)o(h)i(resulting)g(string,)f(expanding)h(left)g(to)e(righ)o(t.)62 -2608 y(Brace)19 b(expansions)g(ma)o(y)f(b)q(e)i(nested.)30 -b(The)19 b(results)g(of)f(eac)o(h)h(expanded)h(string)f(are)f(not)g -(sorted;)i(left)f(to)0 2670 y(righ)o(t)c(order)g(is)h(preserv)o(ed.)k -(F)l(or)14 b(example,)p eop -8 9 bop 0 -58 a Fl(8)1646 b(Bash)15 b(F)l(eatures)120 -183 y Fk(a{d,c,b}e)62 322 y Fl(expands)h(in)o(to)f Fg(ade)h(ace)f(ab)q -(e)p Fl(.)62 461 y(Brace)h(expansion)g(is)g(p)q(erformed)g(b)q(efore)g -(an)o(y)f(other)g(expansions,)h(and)g(an)o(y)f(c)o(haracters)g(sp)q -(ecial)i(to)e(other)0 524 y(expansions)k(are)f(preserv)o(ed)h(in)g(the) -f(result.)30 b(It)18 b(is)h(strictly)g(textual.)29 b(Bash)18 -b(do)q(es)h(not)f(apply)h(an)o(y)f(syn)o(tactic)0 586 -y(in)o(terpretation)d(to)g(the)g(con)o(text)g(of)g(the)g(expansion)h -(or)f(the)g(text)g(b)q(et)o(w)o(een)g(the)g(braces.)62 -725 y(A)h(correctly-formed)f(brace)h(expansion)g(m)o(ust)f(con)o(tain)g -(unquoted)h(op)q(ening)h(and)e(closing)i(braces,)e(and)h(at)0 -787 y(least)f(one)h(unquoted)f(comma.)20 b(An)o(y)15 -b(incorrectly)h(formed)f(brace)g(expansion)h(is)g(left)g(unc)o(hanged.) -62 926 y(This)22 b(construct)f(is)h(t)o(ypically)h(used)f(as)f -(shorthand)g(when)h(the)f(common)g(pre\014x)h(of)f(the)g(strings)h(to)e -(b)q(e)0 988 y(generated)15 b(is)h(longer)f(than)g(in)h(the)g(ab)q(o)o -(v)o(e)f(example:)120 1115 y Fk(mkdir)23 b(/usr/local/src/bash/{old,ne) -o(w,dist,b)o(ugs})62 1254 y Fl(or)120 1380 y Fk(chown)g(root)g -(/usr/{ucb/{ex,edit},lib/{ex?.?)o(*,how_e)o(x}})0 1623 -y Fj(2.3)33 b(C)14 b(Shell)j(Builtins)62 1762 y Fl(Bash)f(has)f(sev)o -(eral)g(builtin)i(commands)e(whose)h(de\014nition)h(is)e(v)o(ery)g -(similar)h(to)f Fk(csh)p Fl(.)0 1915 y Fk(pushd)360 1979 -y(pushd)23 b([)p Fg(dir)28 b Fk(|)c(+)p Fg(n)g Fk(|)f -Fg(-n)p Fk(])240 2056 y Fl(Sa)o(v)o(e)14 b(the)g(curren)o(t)h -(directory)f(on)g(a)g(list)i(and)e(then)h Fk(cd)f Fl(to)f -Fg(dir)p Fl(.)21 b(With)14 b(no)h(argumen)o(ts,)e(exc)o(hanges)240 -2118 y(the)i(top)g(t)o(w)o(o)f(directories.)240 2210 -y Fk(+)p Fg(n)191 b Fl(Brings)13 b(the)f Fg(n)p Fl(th)h(directory)f -(\(coun)o(ting)h(from)e(the)i(left)f(of)g(the)g(list)i(prin)o(ted)f(b)o -(y)f Fk(dirs)p Fl(\))480 2272 y(to)j(the)g(top)g(of)f(the)i(list)g(b)o -(y)f(rotating)f(the)h(stac)o(k.)240 2363 y Fk(-)p Fg(n)191 -b Fl(Brings)21 b(the)f Fg(n)p Fl(th)g(directory)h(\(coun)o(ting)f(from) -g(the)g(righ)o(t)g(of)g(the)g(list)h(prin)o(ted)g(b)o(y)480 -2425 y Fk(dirs)p Fl(\))14 b(to)h(the)g(top)g(of)g(the)g(list)h(b)o(y)f -(rotating)f(the)i(stac)o(k.)240 2517 y Fg(dir)185 b Fl(Mak)o(es)14 -b(the)g(curren)o(t)h(w)o(orking)f(directory)g(b)q(e)i(the)e(top)g(of)g -(the)h(stac)o(k,)e(and)i(then)g Fg(cd)r Fl(s)480 2579 -y(to)g Fg(dir)p Fl(.)20 b(Y)l(ou)c(can)f(see)g(the)h(sa)o(v)o(ed)e -(directory)i(list)g(with)f(the)h Fk(dirs)e Fl(command.)0 -2670 y Fk(popd)p eop -9 10 bop 0 -58 a Fl(Chapter)15 b(2:)k(C-Shell)f(St)o(yle)d(F)l(eatures) -1254 b(9)360 183 y Fk(popd)23 b([+)p Fg(n)h Fk(|)g(-)p -Fg(n)p Fk(])240 265 y Fl(P)o(ops)17 b(the)g(directory)h(stac)o(k,)f -(and)h Fk(cd)p Fl(s)f(to)f(the)i(new)g(top)f(directory)l(.)27 -b(When)17 b(no)h(argumen)o(ts)e(are)240 327 y(giv)o(en,)f(remo)o(v)o -(es)e(the)i(top)e(directory)i(from)f(the)g(stac)o(k)g(and)g -Fk(cd)p Fl(s)g(to)g(the)g(new)h(top)f(directory)l(.)20 -b(The)240 389 y(elemen)o(ts)14 b(are)g(n)o(um)o(b)q(ered)g(from)f(0)g -(starting)g(at)g(the)h(\014rst)f(directory)h(listed)h(with)f -Fk(dirs)p Fl(;)f(i.e.)20 b Fk(popd)240 452 y Fl(is)c(equiv)m(alen)o(t)h -(to)d Fk(popd)h(+0)p Fl(.)240 553 y Fk(+)p Fg(n)191 b -Fl(Remo)o(v)o(es)19 b(the)g Fg(n)p Fl(th)g(directory)g(\(coun)o(ting)g -(from)f(the)i(left)f(of)f(the)h(list)h(prin)o(ted)g(b)o(y)480 -615 y Fk(dirs)p Fl(\),)14 b(starting)g(with)i(zero.)240 -716 y Fk(-)p Fg(n)191 b Fl(Remo)o(v)o(es)16 b(the)h Fg(n)p -Fl(th)f(directory)h(\(coun)o(ting)g(from)e(the)i(righ)o(t)f(of)g(the)h -(list)g(prin)o(ted)g(b)o(y)480 778 y Fk(dirs)p Fl(\),)d(starting)g -(with)i(zero.)0 879 y Fk(dirs)360 948 y(dirs)23 b([+)p -Fg(n)h Fk(|)g(-)p Fg(n)p Fk(])g([-)p Fg(l)r Fk(])240 -1030 y Fl(Displa)o(y)19 b(the)f(list)i(of)d(curren)o(tly)i(remem)o(b)q -(ered)g(directories.)31 b(Directories)19 b(\014nd)g(their)g(w)o(a)o(y)e -(on)o(to)240 1092 y(the)e(list)h(with)g(the)f Fk(pushd)f -Fl(command;)h(y)o(ou)g(can)g(get)g(bac)o(k)g(up)h(through)f(the)g(list) -h(with)f(the)h Fk(popd)240 1155 y Fl(command.)240 1256 -y Fk(+)p Fg(n)191 b Fl(Displa)o(ys)20 b(the)g Fg(n)p -Fl(th)f(directory)h(\(coun)o(ting)g(from)f(the)h(left)f(of)h(the)f -(list)i(prin)o(ted)f(b)o(y)480 1318 y Fk(dirs)15 b Fl(when)g(in)o(v)o -(ok)o(ed)h(without)f(options\),)g(starting)f(with)i(zero.)240 -1419 y Fk(-)p Fg(n)191 b Fl(Displa)o(ys)18 b(the)f Fg(n)p -Fl(th)g(directory)g(\(coun)o(ting)g(from)g(the)g(righ)o(t)g(of)f(the)h -(list)h(prin)o(ted)g(b)o(y)480 1481 y Fk(dirs)d Fl(when)g(in)o(v)o(ok)o -(ed)h(without)f(options\),)g(starting)f(with)i(zero.)240 -1582 y Fk(-)p Fg(l)204 b Fl(Pro)q(duces)16 b(a)g(longer)g(listing;)i -(the)e(default)g(listing)i(format)c(uses)i(a)g(tilde)h(to)f(denote)480 -1644 y(the)f(home)g(directory)l(.)0 1745 y Fk(history)360 -1815 y(history)23 b([)p Fg(n)p Fk(])h([)f([-w)h(-r)g(-a)f(-n])h([)p -Fg(\014lename)s Fk(]])240 1896 y Fl(Displa)o(y)c(the)g(history)g(list)h -(with)f(line)i(n)o(um)o(b)q(ers.)34 b(Lines)21 b(pre\014xed)g(with)f -(with)g(a)g Fk(*)f Fl(ha)o(v)o(e)h(b)q(een)240 1958 y(mo)q(di\014ed.)25 -b(An)17 b(argumen)o(t)f(of)g Fg(n)g Fl(sa)o(ys)g(to)g(list)h(only)g -(the)g(last)f Fg(n)h Fl(lines.)25 b(Option)17 b Fk(-w)f -Fl(means)h(write)240 2021 y(out)i(the)g(curren)o(t)g(history)g(to)f -(the)i(history)f(\014le;)i Fk(-r)e Fl(means)g(to)g(read)g(the)g(curren) -o(t)g(history)g(\014le)240 2083 y(and)e(mak)o(e)g(its)g(con)o(ten)o(ts) -f(the)h(history)g(list.)26 b(An)18 b(argumen)o(t)e(of)g -Fk(-a)h Fl(means)g(to)f(app)q(end)j(the)e(new)240 2145 -y(history)f(lines)i(\(history)d(lines)j(en)o(tered)e(since)h(the)f(b)q -(eginning)j(of)c(the)h(curren)o(t)g(Bash)g(session\))h(to)240 -2208 y(the)g(history)f(\014le.)25 b(Finally)l(,)18 b(the)f -Fk(-n)f Fl(argumen)o(t)g(means)h(to)f(read)g(the)h(history)f(lines)i -(not)f(already)240 2270 y(read)i(from)g(the)g(history)g(\014le)h(in)o -(to)f(the)h(curren)o(t)f(history)g(list.)33 b(These)19 -b(are)g(lines)i(app)q(ended)g(to)240 2332 y(the)d(history)h(\014le)g -(since)g(the)g(b)q(eginning)h(of)e(the)g(curren)o(t)h(Bash)f(session.) -30 b(If)18 b Fg(\014lename)k Fl(is)d(giv)o(en,)240 2394 -y(then)c(it)f(is)h(used)g(as)e(the)i(history)f(\014le,)h(else)g(if)g -Fk($HISTFILE)e Fl(has)h(a)g(v)m(alue,)h(that)e(is)i(used,)g(otherwise) -240 2457 y(`)p Fk(~/.bash_history)p Fl(')d(is)k(used.)0 -2558 y Fk(logout)96 b Fl(Exit)15 b(a)g(login)h(shell.)0 -2659 y Fk(source)96 b Fl(A)15 b(synon)o(ym)g(for)g Fk(.)g -Fl(\(see)g(Section)h(1.4)e([Bourne)h(Shell)j(Builtins],)e(page)f(3\))p -eop -10 11 bop 0 -58 a Fl(10)1623 b(Bash)15 b(F)l(eatures)0 -183 y Fj(2.4)33 b(C)14 b(Shell)j(V)-6 b(ariables)0 320 -y Fk(IGNOREEOF)240 382 y Fl(If)12 b(this)h(v)m(ariable)g(is)g(set,)f -(it)h(represen)o(ts)f(the)g(n)o(um)o(b)q(er)g(of)g(consecutiv)o(e)h -Fk(EOF)p Fl(s)f(Bash)g(will)i(read)e(b)q(efore)240 445 -y(exiting.)21 b(By)15 b(default,)h(Bash)f(will)i(exit)e(up)q(on)h -(reading)g(a)f(single)h Fk(EOF)p Fl(.)0 519 y Fk(cdable_vars)240 -582 y Fl(If)g(this)g(v)m(ariable)i(is)e(set,)g(Bash)g(treats)e(argumen) -o(ts)h(to)h(the)g Fk(cd)f Fl(command)h(whic)o(h)h(are)e(not)h(direc-) -240 644 y(tories)f(as)g(names)g(of)g(v)m(ariables)h(whose)f(v)m(alues)i -(are)e(the)g(directories)h(to)f(c)o(hange)g(to.)p eop -11 12 bop 0 -58 a Fl(Chapter)15 b(3:)k(Korn)d(Shell)h(St)o(yle)e(F)l -(eatures)1164 b(11)0 183 y Fh(3)41 b(Korn)15 b(Shell)f(St)n(yle)g(F)-7 -b(eatures)62 373 y Fl(This)23 b(section)g(describ)q(es)h(features)e -(primarily)h(inspired)h(b)o(y)f(the)f(Korn)g(Shell)j(\()p -Fk(ksh)p Fl(\).)40 b(In)22 b(some)g(cases,)0 435 y(the)17 -b(P)o(osix)f(1003.2)f(standard)h(has)h(adopted)g(these)f(commands)h -(and)g(v)m(ariables)h(from)e(the)g(Korn)h(Shell;)i(Bash)0 -498 y(implemen)o(ts)d(those)f(features)g(using)h(the)f(P)o(osix)h -(standard)e(as)h(a)g(guide.)0 728 y Fj(3.1)33 b(Korn)15 -b(Shell)i(Constructs)62 865 y Fl(Bash)h(includes)j(the)d(Korn)g(Shell)i -Fk(select)d Fl(construct.)28 b(This)18 b(construct)g(allo)o(ws)g(the)g -(easy)g(generation)g(of)0 928 y(men)o(us.)i(It)15 b(has)g(almost)g(the) -g(same)g(syn)o(tax)g(as)g(the)g Fk(for)g Fl(command.)62 -1065 y(The)h(syn)o(tax)e(of)h(the)g Fk(select)g Fl(command)g(is:)120 -1190 y Fk(select)23 b Fg(name)k Fk([in)c Fg(w)o(ords)i -Fk(...];)e(do)h Fg(commands)r Fk(;)f(done)62 1328 y Fl(The)13 -b(list)g(of)g(w)o(ords)e(follo)o(wing)j Fk(in)e Fl(is)h(expanded,)h -(generating)f(a)f(list)h(of)f(items.)20 b(The)13 b(set)f(of)g(expanded) -i(w)o(ords)0 1390 y(is)19 b(prin)o(ted)g(on)g(the)f(standard)g(error,)g -(eac)o(h)h(preceded)h(b)o(y)e(a)g(n)o(um)o(b)q(er.)30 -b(If)19 b(the)f(\\)p Fk(in)d Fg(w)o(ords)r Fl(")i(is)i(omitted,)g(the)0 -1452 y(p)q(ositional)g(parameters)d(are)h(prin)o(ted.)26 -b(The)18 b Fk(PS3)e Fl(prompt)h(is)h(then)f(displa)o(y)o(ed)i(and)e(a)g -(line)i(is)e(read)g(from)g(the)0 1515 y(standard)h(input.)32 -b(If)19 b(the)g(line)h(consists)f(of)g(the)g(n)o(um)o(b)q(er)g(corresp) -q(onding)h(to)e(one)h(of)f(the)h(displa)o(y)o(ed)h(w)o(ords,)0 -1577 y(then)13 b(the)g(v)m(alue)h(of)e Fg(name)k Fl(is)d(set)f(to)g -(that)g(w)o(ord.)19 b(If)13 b(the)g(line)h(is)f(empt)o(y)l(,)g(the)g(w) -o(ords)f(and)h(prompt)f(are)h(displa)o(y)o(ed)0 1639 -y(again.)19 b(If)14 b Fk(EOF)g Fl(is)g(read,)f(the)h -Fk(select)f Fl(command)h(completes.)20 b(An)o(y)14 b(other)f(v)m(alue)i -(read)e(causes)h Fg(name)j Fl(to)c(b)q(e)h(set)0 1702 -y(to)h(n)o(ull.)21 b(The)15 b(line)i(read)e(is)h(sa)o(v)o(ed)f(in)h -(the)f(v)m(ariable)i Fk(REPLY)p Fl(.)62 1839 y(The)d -Fg(commands)h Fl(are)f(executed)g(after)f(eac)o(h)g(selection)i(un)o -(til)g(a)e Fk(break)g Fl(or)g Fk(return)g Fl(command)g(is)h(executed,)0 -1901 y(at)h(whic)o(h)h(p)q(oin)o(t)f(the)h Fk(select)e -Fl(command)h(completes.)0 2131 y Fj(3.2)33 b(Korn)15 -b(Shell)i(Builtins)62 2269 y Fl(This)f(section)g(describ)q(es)h(Bash)e -(builtin)i(commands)e(tak)o(en)g(from)g Fk(ksh)p Fl(.)0 -2420 y Fk(fc)360 2483 y(fc)24 b([-e)f Fg(ename)s Fk(])h([-nlr])f([)p -Fg(\014rst)q Fk(])g([)p Fg(last)q Fk(])360 2532 y(fc)h(-s)f([)p -Fg(pat=rep)q Fk(])h([)p Fg(command)r Fk(])240 2608 y -Fl(Fix)19 b(Command.)29 b(In)20 b(the)e(\014rst)h(form,)f(a)g(range)g -(of)h(commands)f(from)g Fg(\014rst)h Fl(to)f Fg(last)i -Fl(is)f(selected)240 2670 y(from)f(the)g(history)h(list.)30 -b(Both)18 b Fg(\014rst)h Fl(and)g Fg(last)g Fl(ma)o(y)f(b)q(e)h(sp)q -(eci\014ed)i(as)d(a)g(string)h(\(to)e(lo)q(cate)i(the)p -eop -12 13 bop 0 -58 a Fl(12)1623 b(Bash)15 b(F)l(eatures)240 -183 y(most)h(recen)o(t)h(command)g(b)q(eginning)i(with)f(that)e -(string\))h(or)f(as)h(a)g(n)o(um)o(b)q(er)g(\(an)g(index)h(in)o(to)f -(the)240 246 y(history)g(list,)h(where)g(a)f(negativ)o(e)g(n)o(um)o(b)q -(er)h(is)g(used)g(as)f(an)g(o\013set)f(from)h(the)g(curren)o(t)g -(command)240 308 y(n)o(um)o(b)q(er\).)k(If)15 b Fg(last)i -Fl(is)f(not)f(sp)q(eci\014ed)i(it)f(is)g(set)f(to)g Fg(\014rst)p -Fl(.)21 b(If)15 b Fg(\014rst)h Fl(is)g(not)f(sp)q(eci\014ed)j(it)e(is)g -(set)f(to)g(the)240 370 y(previous)f(command)g(for)e(editing)j(and)f -(-16)f(for)g(listing.)20 b(If)14 b(the)g Fk(-l)f Fl(\015ag)g(is)h(giv)o -(en,)g(the)f(commands)240 432 y(are)19 b(listed)i(on)e(standard)g -(output.)32 b(The)19 b Fk(-n)g Fl(\015ag)g(suppresses)h(the)g(command)f -(n)o(um)o(b)q(ers)g(when)240 495 y(listing.)31 b(The)18 -b Fk(-r)g Fl(\015ag)h(rev)o(erses)f(the)g(order)g(of)g(the)h(listing.) -30 b(Otherwise,)20 b(the)f(editor)f(giv)o(en)h(b)o(y)240 -557 y Fg(ename)d Fl(is)d(in)o(v)o(ok)o(ed)h(on)f(a)g(\014le)h(con)o -(taining)g(those)e(commands.)19 b(If)14 b Fg(ename)i -Fl(is)d(not)g(giv)o(en,)h(the)f(v)m(alue)240 619 y(of)h(the)g(follo)o -(wing)i(v)m(ariable)f(expansion)h(is)f(used:)20 b Fk -(${FCEDIT:-${EDITOR:-vi}})o Fl(.)d(This)e(sa)o(ys)f(to)240 -681 y(use)g(the)g(v)m(alue)g(of)f(the)h Fk(FCEDIT)f Fl(v)m(ariable)i -(if)f(set,)f(or)g(the)h(v)m(alue)g(of)f(the)h Fk(EDITOR)f -Fl(v)m(ariable)i(if)f(that)e(is)240 744 y(set,)i(or)g -Fk(vi)h Fl(if)g(neither)h(is)f(set.)20 b(When)15 b(editing)h(is)f -(complete,)g(the)g(edited)h(commands)f(are)f(ec)o(ho)q(ed)240 -806 y(and)h(executed.)240 881 y(In)h(the)g(second)g(form,)f -Fg(command)i Fl(is)f(re-executed)h(after)e(eac)o(h)h(instance)g(of)f -Fg(pat)i Fl(in)f(the)g(selected)240 944 y(command)f(is)h(replaced)g(b)o -(y)f Fg(rep)p Fl(.)240 1019 y(A)20 b(useful)i(alias)f(to)e(use)i(with)f -(the)h Fk(fc)f Fl(command)g(is)h Fk(r='fc)14 b(-s')p -Fl(,)21 b(so)f(that)f(t)o(yping)i Fk(r)15 b(cc)20 b Fl(runs)240 -1081 y(the)c(last)g(command)h(b)q(eginning)h(with)f Fk(cc)e -Fl(and)i(t)o(yping)f Fk(r)g Fl(re-executes)h(the)g(last)f(command)g -(\(see)240 1144 y(Section)g(3.4)e([Aliases],)h(page)h(13\).)0 -1232 y Fk(let)168 b Fl(The)15 b Fk(let)f Fl(builtin)j(allo)o(ws)d -(arithmetic)h(to)f(b)q(e)i(p)q(erformed)e(on)h(shell)h(v)m(ariables.)21 -b(F)l(or)14 b(details,)h(refer)240 1294 y(to)g(Section)h(4.7.3)d -([Arithmetic)j(Builtins],)h(page)e(26.)0 1383 y Fk(typeset)72 -b Fl(The)17 b Fk(typeset)f Fl(command)h(is)h(supplied)h(for)d -(compatibilit)o(y)j(with)e(the)g(Korn)g(shell;)i(ho)o(w)o(ev)o(er,)e -(it)240 1445 y(has)j(b)q(een)i(made)f(obsolete)g(b)o(y)f(the)h -Fk(declare)e Fl(command)i(\(see)f(Section)i(4.4)d([Bash)i(Builtins],) -240 1508 y(page)15 b(17\).)0 1738 y Fj(3.3)33 b(Korn)15 -b(Shell)i(V)-6 b(ariables)0 1889 y Fk(REPLY)120 b Fl(The)15 -b(default)h(v)m(ariable)h(for)d(the)i Fk(read)e Fl(builtin.)0 -1978 y Fk(RANDOM)96 b Fl(Eac)o(h)19 b(time)h(this)f(parameter)g(is)h -(referenced,)h(a)e(random)f(in)o(teger)i(is)g(generated.)32 -b(Assigning)20 b(a)240 2040 y(v)m(alue)c(to)f(this)h(v)m(ariable)g -(seeds)g(the)f(random)g(n)o(um)o(b)q(er)g(generator.)0 -2129 y Fk(SECONDS)72 b Fl(This)13 b(v)m(ariable)g(expands)g(to)e(the)h -(n)o(um)o(b)q(er)g(of)g(seconds)h(since)g(the)f(shell)h(w)o(as)f -(started.)18 b(Assignmen)o(t)240 2191 y(to)12 b(this)i(v)m(ariable)g -(resets)e(the)h(coun)o(t)g(to)f(the)h(v)m(alue)i(assigned,)e(and)g(the) -g(expanded)h(v)m(alue)g(b)q(ecomes)240 2253 y(the)h(v)m(alue)i -(assigned)f(plus)g(the)f(n)o(um)o(b)q(er)h(of)e(seconds)i(since)g(the)g -(assignmen)o(t.)0 2342 y Fk(PS3)168 b Fl(The)15 b(v)m(alue)i(of)e(this) -g(v)m(ariable)i(is)f(used)f(as)g(the)g(prompt)g(for)g(the)g -Fk(select)f Fl(command.)0 2430 y Fk(PS4)168 b Fl(This)18 -b(is)f(the)g(prompt)g(prin)o(ted)h(b)q(efore)f(the)g(command)g(line)i -(is)f(ec)o(ho)q(ed)g(when)f(the)g Fk(-x)g Fl(option)g(is)240 -2493 y(set)e(\(see)g(Section)h(4.5)e([The)i(Set)f(Builtin],)h(page)g -(20\).)0 2581 y Fk(PWD)168 b Fl(The)15 b(curren)o(t)h(w)o(orking)e -(directory)i(as)f(set)g(b)o(y)g(the)g Fk(cd)g Fl(builtin.)0 -2670 y Fk(OLDPWD)96 b Fl(The)15 b(previous)h(w)o(orking)f(directory)h -(as)e(set)h(b)o(y)h(the)f Fk(cd)g Fl(builtin.)p eop -13 14 bop 0 -58 a Fl(Chapter)15 b(3:)k(Korn)d(Shell)h(St)o(yle)e(F)l -(eatures)1164 b(13)0 183 y Fk(TMOUT)120 b Fl(If)14 b(set)g(to)g(a)g(v)m -(alue)h(greater)e(than)h(zero,)g(the)g(v)m(alue)i(is)e(in)o(terpreted)h -(as)f(the)g(n)o(um)o(b)q(er)g(of)g(seconds)h(to)240 246 -y(w)o(ait)f(for)f(input)i(after)e(issuing)i(the)g(primary)f(prompt.)19 -b(Bash)14 b(terminates)g(after)f(that)g(n)o(um)o(b)q(er)h(of)240 -308 y(seconds)i(if)f(input)i(do)q(es)e(not)g(arriv)o(e.)0 -528 y Fj(3.4)33 b(Aliases)62 665 y Fl(The)19 b(shell)i(main)o(tains)e -(a)f(list)i(of)e Fg(aliases)k Fl(that)c(ma)o(y)g(b)q(e)h(set)g(and)g -(unset)g(with)g(the)g Fk(alias)f Fl(and)h Fk(unalias)0 -727 y Fl(builtin)e(commands.)62 864 y(The)i(\014rst)f(w)o(ord)f(of)h -(eac)o(h)h(command,)f(if)h(unquoted,)g(is)g(c)o(hec)o(k)o(ed)g(to)f -(see)g(if)h(it)g(has)f(an)g(alias.)30 b(If)18 b(so,)h(that)0 -927 y(w)o(ord)12 b(is)i(replaced)g(b)o(y)f(the)g(text)f(of)h(the)g -(alias.)20 b(The)13 b(alias)h(name)f(and)g(the)g(replacemen)o(t)g(text) -g(ma)o(y)f(con)o(tain)h(an)o(y)0 989 y(v)m(alid)18 b(shell)h(input,)f -(including)h(shell)g(metac)o(haracters,)c(with)i(the)g(exception)h -(that)e(the)h(alias)g(name)g(ma)o(y)f(not)0 1051 y(con)o(tain)g -Fk(=)p Fl(.)k(The)c(\014rst)f(w)o(ord)f(of)h(the)h(replacemen)o(t)g -(text)f(is)h(tested)f(for)g(aliases,)h(but)g(a)f(w)o(ord)f(that)h(is)h -(iden)o(tical)0 1113 y(to)g(an)h(alias)h(b)q(eing)g(expanded)g(is)g -(not)e(expanded)i(a)f(second)h(time.)25 b(This)18 b(means)f(that)f(one) -h(ma)o(y)f(alias)i Fk(ls)f Fl(to)0 1176 y Fk("ls)e(-F")p -Fl(,)j(for)f(instance,)j(and)e(Bash)g(do)q(es)h(not)f(try)f(to)h -(recursiv)o(ely)h(expand)g(the)f(replacemen)o(t)h(text.)28 -b(If)19 b(the)0 1238 y(last)14 b(c)o(haracter)f(of)h(the)g(alias)h(v)m -(alue)g(is)g(a)e(space)i(or)e(tab)h(c)o(haracter,)f(then)i(the)f(next)g -(command)g(w)o(ord)f(follo)o(wing)0 1300 y(the)i(alias)h(is)g(also)f(c) -o(hec)o(k)o(ed)h(for)e(alias)i(expansion.)62 1437 y(Aliases)i(are)f -(created)g(and)g(listed)h(with)f(the)g Fk(alias)g Fl(command,)f(and)h -(remo)o(v)o(ed)g(with)g(the)g Fk(unalias)f Fl(com-)0 -1499 y(mand.)62 1636 y(There)i(is)h(no)f(mec)o(hanism)g(for)f(using)i -(argumen)o(ts)e(in)i(the)f(replacemen)o(t)g(text,)g(as)f(in)i -Fk(csh)p Fl(.)28 b(If)18 b(argumen)o(ts)0 1699 y(are)d(needed,)h(a)f -(shell)i(function)f(should)g(b)q(e)g(used.)62 1836 y(Aliases)h(are)d -(not)h(expanded)i(when)e(the)g(shell)i(is)f(not)f(in)o(teractiv)o(e.)62 -1973 y(The)d(rules)g(concerning)g(the)g(de\014nition)h(and)e(use)h(of)f -(aliases)h(are)e(somewhat)h(confusing.)19 b(Bash)12 b(alw)o(a)o(ys)e -(reads)0 2035 y(at)k(least)h(one)g(complete)h(line)g(of)f(input)g(b)q -(efore)h(executing)g(an)o(y)e(of)g(the)h(commands)g(on)g(that)f(line.) -21 b(Aliases)16 b(are)0 2097 y(expanded)c(when)g(a)f(command)g(is)g -(read,)h(not)f(when)g(it)h(is)f(executed.)20 b(Therefore,)11 -b(an)g(alias)h(de\014nition)h(app)q(earing)0 2159 y(on)h(the)g(same)g -(line)h(as)f(another)f(command)h(do)q(es)h(not)e(tak)o(e)g(e\013ect)h -(un)o(til)h(the)f(next)g(line)i(of)d(input)i(is)g(read.)k(This)0 -2222 y(means)f(that)f(the)h(commands)f(follo)o(wing)i(the)f(alias)g -(de\014nition)i(on)d(that)g(line)j(are)d(not)h(a\013ected)f(b)o(y)h -(the)g(new)0 2284 y(alias.)24 b(This)16 b(b)q(eha)o(vior)h(is)g(also)f -(an)g(issue)h(when)g(functions)g(are)f(executed.)24 b(Aliases)17 -b(are)f(expanded)h(when)g(the)0 2346 y(function)e(de\014nition)h(is)e -(read,)g(not)f(when)i(the)f(function)g(is)h(executed,)g(b)q(ecause)f(a) -g(function)h(de\014nition)h(is)e(itself)0 2408 y(a)g(comp)q(ound)g -(command.)20 b(As)13 b(a)h(consequence,)h(aliases)g(de\014ned)g(in)g(a) -e(function)i(are)f(not)f(a)o(v)m(ailable)j(un)o(til)f(after)0 -2471 y(that)i(function)h(is)g(executed.)27 b(T)l(o)17 -b(b)q(e)h(safe,)f(alw)o(a)o(ys)g(put)g(alias)h(de\014nitions)h(on)f(a)f -(separate)f(line,)k(and)d(do)g(not)0 2533 y(use)f Fk(alias)e -Fl(in)i(comp)q(ound)g(commands.)62 2670 y(Note)f(that)g(for)f(almost)h -(ev)o(ery)g(purp)q(ose,)g(aliases)h(are)f(sup)q(erseded)i(b)o(y)e -(shell)i(functions.)p eop -14 15 bop 0 -58 a Fl(14)1623 b(Bash)15 b(F)l(eatures)0 -183 y Ff(3.4.1)30 b(Alias)15 b(Builtins)0 333 y Fk(alias)360 -395 y(alias)23 b([)p Fg(name)s Fk([=)p Fg(v)m(alue)s -Fk(])h(...])240 470 y Fl(Without)16 b(argumen)o(ts,)e(prin)o(t)i(the)g -(list)g(of)g(aliases)g(on)f(the)h(standard)f(output.)22 -b(If)15 b(argumen)o(ts)g(are)240 532 y(supplied,)k(an)e(alias)g(is)g -(de\014ned)h(for)e(eac)o(h)h Fg(name)i Fl(whose)d Fg(v)m(alue)21 -b Fl(is)c(giv)o(en.)25 b(If)17 b(no)f Fg(v)m(alue)21 -b Fl(is)c(giv)o(en,)240 594 y(the)e(name)g(and)h(v)m(alue)g(of)f(the)g -(alias)h(is)g(prin)o(ted.)0 681 y Fk(unalias)360 744 -y(unalias)23 b([-a])g([)p Fg(name)k Fk(...)c(])240 818 -y Fl(Remo)o(v)o(e)15 b(eac)o(h)g Fg(name)j Fl(from)d(the)g(list)h(of)f -(aliases.)20 b(If)c Fk(-a)f Fl(is)g(supplied,)i(all)g(aliases)e(are)g -(remo)o(v)o(ed.)p eop -15 16 bop 0 -58 a Fl(Chapter)15 b(4:)k(Bash)d(Sp)q(eci\014c)h(F)l -(eatures)1226 b(15)0 183 y Fh(4)41 b(Bash)15 b(Sp)r(eci\014c)f(F)-7 -b(eatures)62 369 y Fl(This)16 b(section)g(describ)q(es)h(the)e -(features)g(unique)h(to)f(Bash.)0 593 y Fj(4.1)33 b(In)n(v)n(oking)17 -b(Bash)62 730 y Fl(In)c(addition)h(to)e(the)h(single-c)o(haracter)g -(shell)h(command-line)g(options)f(\(see)f(Section)i(4.5)d([The)i(Set)f -(Builtin],)0 792 y(page)17 b(20\),)f(there)h(are)g(sev)o(eral)h(m)o -(ulti-c)o(haracter)f(options)g(that)g(y)o(ou)f(can)i(use.)26 -b(These)17 b(options)g(m)o(ust)g(app)q(ear)0 854 y(on)e(the)g(command)g -(line)i(b)q(efore)f(the)f(single-c)o(haracter)h(options)f(to)g(b)q(e)h -(recognized.)0 1003 y Fk(-norc)120 b Fl(Don't)20 b(read)h(the)g(`)p -Fk(~/.bashrc)p Fl(')e(initialization)24 b(\014le)e(in)g(an)f(in)o -(teractiv)o(e)g(shell.)39 b(This)22 b(is)f(on)g(b)o(y)240 -1066 y(default)16 b(if)f(the)h(shell)h(is)e(in)o(v)o(ok)o(ed)h(as)e -Fk(sh)p Fl(.)0 1140 y Fk(-rcfile)g Fg(\014lename)240 -1203 y Fl(Execute)i(commands)f(from)f Fg(\014lename)19 -b Fl(\(instead)c(of)g(`)p Fk(~/.bashrc)p Fl('\))e(in)j(an)f(in)o -(teractiv)o(e)h(shell.)0 1277 y Fk(-noprofile)240 1339 -y Fl(Don't)k(load)h(the)h(system-wide)f(startup)g(\014le)h(`)p -Fk(/etc/profile)p Fl(')c(or)j(an)o(y)g(of)f(the)i(p)q(ersonal)f(ini-) -240 1402 y(tialization)g(\014les)g(`)p Fk(~/.bash_profile)p -Fl(',)d(`)p Fk(~/.bash_login)p Fl(',)g(or)h(`)p Fk(~/.profile)p -Fl(')f(when)i(bash)g(is)240 1464 y(in)o(v)o(ok)o(ed)15 -b(as)g(a)g(login)h(shell.)0 1551 y Fk(-version)48 b Fl(Displa)o(y)16 -b(the)f(v)o(ersion)g(n)o(um)o(b)q(er)h(of)f(this)g(shell.)0 -1637 y Fk(-login)96 b Fl(Mak)o(e)13 b(this)h(shell)h(act)e(as)g(if)h -(it)g(w)o(ere)g(directly)h(in)o(v)o(ok)o(ed)e(from)g(login.)20 -b(This)15 b(is)f(equiv)m(alen)o(t)h(to)e(`)p Fk(exec)240 -1700 y(-)i(bash)p Fl(')i(but)h(can)g(b)q(e)h(issued)g(from)f(another)f -(shell,)j(suc)o(h)f(as)e Fk(csh)p Fl(.)28 b(If)18 b(y)o(ou)g(w)o(an)o -(ted)g(to)f(replace)240 1762 y(y)o(our)e(curren)o(t)g(login)h(shell)h -(with)e(a)g(Bash)g(login)h(shell,)h(y)o(ou)e(w)o(ould)g(sa)o(y)g(`)p -Fk(exec)f(bash)h(-login)p Fl('.)0 1837 y Fk(-nobraceexpansion)240 -1899 y Fl(Do)g(not)f(p)q(erform)h(curly)h(brace)g(expansion)g(\(see)f -(Section)h(2.2)e([Brace)h(Expansion],)g(page)g(7\).)0 -1973 y Fk(-nolineediting)240 2036 y Fl(Do)c(not)g(use)h(the)f(GNU)h -(Readline)h(library)g(\(see)e(Chapter)g(7)g([Command)g(Line)i -(Editing],)g(page)e(37\))240 2098 y(to)k(read)g(in)o(teractiv)o(e)g -(command)g(lines.)0 2185 y Fk(-posix)96 b Fl(Change)14 -b(the)g(b)q(eha)o(vior)g(of)f(Bash)h(where)g(the)g(default)g(op)q -(eration)g(di\013ers)g(from)f(the)h(P)o(osix)g(1003.2)240 -2247 y(standard)19 b(to)g(matc)o(h)g(the)h(standard.)32 -b(This)20 b(is)g(in)o(tended)h(to)e(mak)o(e)g(Bash)h(b)q(eha)o(v)o(e)g -(as)f(a)g(strict)240 2309 y(sup)q(erset)d(of)e(that)h(standard.)62 -2458 y(There)20 b(are)f(sev)o(eral)g(single-c)o(haracter)h(options)g(y) -o(ou)f(can)g(giv)o(e)h(whic)o(h)g(are)f(not)f(a)o(v)m(ailable)j(with)f -(the)f Fk(set)0 2521 y Fl(builtin.)0 2670 y Fk(-c)c Fg(string)63 -b Fl(Read)16 b(and)f(execute)h(commands)f(from)g Fg(string)k -Fl(after)14 b(pro)q(cessing)i(the)f(options,)g(then)h(exit.)p -eop -16 17 bop 0 -58 a Fl(16)1623 b(Bash)15 b(F)l(eatures)0 -183 y Fk(-i)192 b Fl(F)l(orce)15 b(the)g(shell)i(to)e(run)g(in)o -(teractiv)o(ely)l(.)0 285 y Fk(-s)192 b Fl(If)11 b(this)h(\015ag)f(is)h -(presen)o(t,)f(or)g(if)h(no)f(argumen)o(ts)f(remain)i(after)f(option)g -(pro)q(cessing,)i(then)e(commands)240 347 y(are)16 b(read)g(from)f(the) -h(standard)g(input.)24 b(This)16 b(option)h(allo)o(ws)f(the)g(p)q -(ositional)i(parameters)d(to)g(b)q(e)240 410 y(set)g(when)h(in)o(v)o -(oking)f(an)h(in)o(teractiv)o(e)f(shell.)62 574 y(An)i -Fg(in)o(teractiv)o(e)j Fl(shell)e(is)f(one)g(whose)f(input)i(and)f -(output)f(are)g(b)q(oth)h(connected)h(to)e(terminals)h(\(as)f(deter-)0 -636 y(mined)g(b)o(y)f Fk(isatty\(\))p Fl(\),)f(or)h(one)g(started)f -(with)i(the)f Fk(-i)g Fl(option.)0 927 y Fj(4.2)33 b(Bash)14 -b(Startup)j(Files)62 1071 y Fl(When)f(and)f(ho)o(w)g(Bash)g(executes)h -(startup)e(\014les.)120 1203 y Fk(For)23 b(Login)h(shells)f(\(subject)f -(to)i(the)f(-noprofile)g(option\):)215 1303 y(On)h(logging)f(in:)287 -1353 y(If)h(`/etc/profile')e(exists,)g(then)i(source)f(it.)287 -1452 y(If)h(`~/.bash_profile')d(exists,)i(then)g(source)g(it,)359 -1502 y(else)g(if)h(`~/.bash_login')d(exists,)i(then)h(source)f(it,)430 -1552 y(else)h(if)f(`~/.profile')f(exists,)h(then)h(source)f(it.)215 -1652 y(On)h(logging)f(out:)287 1701 y(If)h(`~/.bash_logout')d(exists,)i -(source)g(it.)120 1801 y(For)g(non-login)g(interactive)f(shells)h -(\(subject)g(to)h(the)f(-norc)g(and)h(-rcfile)f(options\):)215 -1851 y(On)h(starting)f(up:)287 1901 y(If)h(`~/.bashrc')e(exists,)h -(then)g(source)g(it.)120 2000 y(For)g(non-interactive)f(shells:)215 -2050 y(On)i(starting)f(up:)287 2100 y(If)h(the)f(environment)f -(variable)h(ENV)h(is)f(non-null,)g(expand)g(the)287 2150 -y(variable)g(and)g(source)g(the)h(file)f(named)g(by)h(the)f(value.)47 -b(If)24 b(Bash)f(is)287 2199 y(not)g(started)g(in)h(Posix)f(mode,)g(it) -h(looks)f(for)h(BASH_ENV)e(before)287 2249 y(ENV.)62 -2394 y Fl(So,)15 b(t)o(ypically)l(,)h(y)o(our)f Fk(~/.bash_profile)e -Fl(con)o(tains)j(the)f(line)120 2526 y Fk(if)24 b([)f(-f)h(~/.bashrc)f -(];)g(then)g(source)g(~/.bashrc;)g(fi)0 2670 y Fl(after)14 -b(\(or)h(b)q(efore\))g(an)o(y)g(login)h(sp)q(eci\014c)h -(initializations.)p eop -17 18 bop 0 -58 a Fl(Chapter)15 b(4:)k(Bash)d(Sp)q(eci\014c)h(F)l -(eatures)1226 b(17)62 183 y(If)16 b(Bash)g(is)g(in)o(v)o(ok)o(ed)g(as)f -Fk(sh)p Fl(,)g(it)g(tries)h(to)f(mimic)i(the)f(b)q(eha)o(vior)g(of)f -Fk(sh)g Fl(as)g(closely)i(as)e(p)q(ossible.)23 b(F)l(or)15 -b(a)g(login)0 246 y(shell,)g(it)e(attempts)f(to)g(source)i(only)f(`)p -Fk(/etc/profile)p Fl(')e(and)i(`)p Fk(~/.profile)p Fl(',)e(in)j(that)e -(order.)19 b(The)13 b Fk(-noprofile)0 308 y Fl(option)h(ma)o(y)g(still) -h(b)q(e)g(used)g(to)f(disable)h(this)g(b)q(eha)o(vior.)20 -b(A)14 b(shell)i(in)o(v)o(ok)o(ed)e(as)g Fk(sh)g Fl(do)q(es)g(not)g -(attempt)f(to)h(source)0 370 y(an)o(y)h(other)g(startup)f(\014les.)62 -507 y(When)h(Bash)g(is)g(started)f(in)h Fg(POSIX)21 b -Fl(mo)q(de,)14 b(as)g(with)h(the)g Fk(-posix)f Fl(command)g(line)j -(option,)d(it)h(follo)o(ws)g(the)0 570 y(P)o(osix)j(1003.2)e(standard)h -(for)h(startup)f(\014les.)29 b(In)18 b(this)g(mo)q(de,)h(the)f -Fk(ENV)f Fl(v)m(ariable)i(is)g(expanded)g(and)f(that)f(\014le)0 -632 y(sourced;)e(no)g(other)g(startup)g(\014les)h(are)f(read.)0 -859 y Fj(4.3)33 b(Is)14 b(This)i(Shell)h(In)n(teractiv)n(e?)62 -996 y Fl(Y)l(ou)c(ma)o(y)f(wish)h(to)f(determine)i(within)g(a)e -(startup)g(script)h(whether)g(Bash)g(is)g(running)h(in)o(teractiv)o -(ely)g(or)e(not.)0 1058 y(T)l(o)17 b(do)g(this,)h(examine)g(the)g(v)m -(ariable)g Fk($PS1)p Fl(;)g(it)f(is)h(unset)g(in)g(non-in)o(teractiv)o -(e)g(shells,)h(and)e(set)g(in)i(in)o(teractiv)o(e)0 1120 -y(shells.)i(Th)o(us:)120 1245 y Fk(if)j([)f(-z)h("$PS1")f(];)h(then)120 -1295 y(echo)f(This)h(shell)f(is)g(not)h(interactive)120 -1345 y(else)120 1395 y(echo)f(This)h(shell)f(is)g(interactive)120 -1444 y(fi)62 1582 y Fl(Y)l(ou)16 b(can)f(ask)f(an)h(in)o(teractiv)o(e)h -(Bash)f(to)f(not)h(run)g(y)o(our)g(`)p Fk(~/.bashrc)p -Fl(')e(\014le)j(with)g(the)f Fk(-norc)f Fl(\015ag.)20 -b(Y)l(ou)15 b(can)0 1644 y(c)o(hange)j(the)f(name)h(of)f(the)h(`)p -Fk(~/.bashrc)p Fl(')d(\014le)k(to)e(an)o(y)g(other)g(\014le)i(name)e -(with)h Fk(-rcfile)c Fg(\014lename)s Fl(.)28 b(Y)l(ou)18 -b(can)0 1706 y(ask)d(Bash)g(to)g(not)f(run)i(y)o(our)f(`)p -Fk(~/.bash_profile)p Fl(')d(\014le)k(with)g(the)f Fk(-noprofile)f -Fl(\015ag.)0 1933 y Fj(4.4)33 b(Bash)14 b(Builtin)k(Commands)62 -2070 y Fl(This)e(section)g(describ)q(es)h(builtin)g(commands)e(whic)o -(h)h(are)f(unique)i(to)d(or)h(ha)o(v)o(e)g(b)q(een)h(extended)g(in)g -(Bash.)0 2220 y Fk(builtin)360 2283 y(builtin)23 b([)p -Fg(shell-builti)q(n)k Fk([)p Fg(args)r Fk(]])240 2358 -y Fl(Run)20 b(a)f(shell)h(builtin.)34 b(This)20 b(is)g(useful)g(when)f -(y)o(ou)g(wish)h(to)e(rename)h(a)g(shell)i(builtin)g(to)e(b)q(e)g(a)240 -2420 y(function,)d(but)f(need)h(the)f(functionalit)o(y)i(of)e(the)g -(builtin)i(within)g(the)e(function)h(itself.)0 2508 y -Fk(bind)360 2570 y(bind)23 b([-m)h Fg(k)o(eymap)q Fk(])g([-lvd])f([-q)g -Fg(name)s Fk(])360 2620 y(bind)g([-m)h Fg(k)o(eymap)q -Fk(])g(-f)f Fg(\014lename)360 2670 y Fk(bind)g([-m)h -Fg(k)o(eymap)q Fk(])g Fg(k)o(eyseq:function-name)p eop -18 19 bop 0 -58 a Fl(18)1623 b(Bash)15 b(F)l(eatures)240 -183 y(Displa)o(y)k(curren)o(t)e(Readline)k(\(see)c(Chapter)h(7)g -([Command)f(Line)i(Editing],)g(page)f(37\))f(k)o(ey)h(and)240 -246 y(function)24 b(bindings,)j(or)c(bind)h(a)f(k)o(ey)g(sequence)i(to) -d(a)h(Readline)j(function)e(or)e(macro.)44 b(The)240 -308 y(binding)25 b(syn)o(tax)d(accepted)i(is)g(iden)o(tical)h(to)d -(that)h(of)f(`)p Fk(.inputrc)p Fl(')f(\(see)i(Section)h(7.3)f([Read-) -240 370 y(line)f(Init)g(File],)h(page)d(40\),)h(but)g(eac)o(h)g -(binding)i(m)o(ust)d(b)q(e)i(passed)f(as)f(a)h(separate)f(argumen)o(t:) -240 432 y(`)p Fk("\\C-x\\C-r":re-read-init)o(-file)p -Fl(')o(.)d(Options,)e(if)f(supplied,)i(ha)o(v)o(e)e(the)g(follo)o(wing) -h(meanings:)240 518 y Fk(-m)g(keymap)33 b Fl(Use)14 b -Fg(k)o(eymap)h Fl(as)e(the)h(k)o(eymap)f(to)g(b)q(e)h(a\013ected)g(b)o -(y)f(the)h(subsequen)o(t)g(bindings.)22 b(Ac-)480 580 -y(ceptable)14 b Fg(k)o(eymap)h Fl(names)e(are)g Fk(emacs)p -Fl(,)g Fk(emacs-standard)p Fl(,)e Fk(emacs-meta)p Fl(,)h -Fk(emacs-)480 643 y(ctlx)p Fl(,)k Fk(vi)p Fl(,)h Fk(vi-move)p -Fl(,)f Fk(vi-command)p Fl(,)g(and)h Fk(vi-insert)p Fl(.)23 -b Fk(vi)17 b Fl(is)g(equiv)m(alen)o(t)i(to)d Fk(vi-)480 -705 y(command)p Fl(;)e Fk(emacs)g Fl(is)i(equiv)m(alen)o(t)h(to)d -Fk(emacs-standard)p Fl(.)240 791 y Fk(-l)192 b Fl(List)16 -b(the)f(names)g(of)g(all)h(readline)h(functions)240 877 -y Fk(-v)192 b Fl(List)16 b(curren)o(t)f(function)h(names)f(and)g -(bindings)240 962 y Fk(-d)192 b Fl(Dump)13 b(function)h(names)f(and)h -(bindings)h(in)f(suc)o(h)f(a)g(w)o(a)o(y)f(that)h(they)g(can)g(b)q(e)h -(re-read)240 1036 y Fk(-f)h(filename)480 1099 y Fl(Read)h(k)o(ey)f -(bindings)i(from)d Fg(\014lename)240 1184 y Fk(-q)192 -b Fl(Query)16 b(ab)q(out)f(whic)o(h)h(k)o(eys)f(in)o(v)o(ok)o(e)g(the)g -(named)h Fg(function)0 1270 y Fk(command)360 1332 y(command)23 -b([-pVv])g Fg(command)j Fk([)p Fg(args)e Fk(...])240 -1406 y Fl(Runs)18 b Fg(command)i Fl(with)d Fg(arg)k Fl(ignoring)d -(shell)h(functions.)28 b(If)18 b(y)o(ou)f(ha)o(v)o(e)g(a)g(shell)i -(function)f(called)240 1468 y Fk(ls)p Fl(,)f(and)h(y)o(ou)f(wish)h(to)f -(call)h(the)g(command)f Fk(ls)p Fl(,)g(y)o(ou)g(can)h(sa)o(y)e(`)p -Fk(command)e(ls)p Fl('.)26 b(The)18 b Fk(-p)f Fl(option)240 -1530 y(means)g(to)g(use)g(a)g(default)h(v)m(alue)g(for)f -Fk($PATH)g Fl(that)f(is)i(guaran)o(teed)f(to)f(\014nd)i(all)g(of)f(the) -g(standard)240 1593 y(utilities.)240 1667 y(If)i(either)h(the)f -Fk(-V)g Fl(or)f Fk(-v)h Fl(option)g(is)h(supplied,)i(a)c(description)j -(of)d Fg(command)j Fl(is)f(prin)o(ted.)32 b(The)240 1729 -y Fk(-v)19 b Fl(option)h(causes)f(a)g(single)i(w)o(ord)d(indicating)j -(the)f(command)f(or)g(\014le)h(name)f(used)h(to)f(in)o(v)o(ok)o(e)240 -1791 y Fg(command)e Fl(to)d(b)q(e)i(prin)o(ted;)g(the)f -Fk(-V)g Fl(option)g(pro)q(duces)h(a)f(more)g(v)o(erb)q(ose)g -(description.)0 1877 y Fk(declare)360 1939 y(declare)23 -b([-frxi])g([)p Fg(name)s Fk([=)p Fg(v)m(alue)s Fk(]])240 -2013 y Fl(Declare)15 b(v)m(ariables)h(and/or)d(giv)o(e)i(them)f -(attributes.)20 b(If)15 b(no)f Fg(name)s Fl(s)g(are)g(giv)o(en,)h(then) -f(displa)o(y)i(the)240 2075 y(v)m(alues)k(of)f(v)m(ariables)i(instead.) -33 b Fk(-f)19 b Fl(means)g(to)g(use)h(function)g(names)f(only)l(.)33 -b Fk(-r)19 b Fl(sa)o(ys)g(to)f(mak)o(e)240 2137 y Fg(name)s -Fl(s)d(readonly)l(.)22 b Fk(-x)15 b Fl(sa)o(ys)g(to)g(mark)g -Fg(name)s Fl(s)g(for)g(exp)q(ort.)21 b Fk(-i)16 b Fl(sa)o(ys)f(that)f -(the)i(v)m(ariable)h(is)f(to)f(b)q(e)240 2199 y(treated)c(as)h(an)f(in) -o(teger;)i(arithmetic)f(ev)m(aluation)h(\(see)f(Section)h(4.7)d([Shell) -k(Arithmetic],)e(page)g(24\))240 2262 y(is)17 b(p)q(erformed)f(when)h -(the)g(v)m(ariable)g(is)g(assigned)g(a)f(v)m(alue.)24 -b(Using)17 b Fk(+)f Fl(instead)h(of)f Fk(-)g Fl(turns)g(o\013)g(the)240 -2324 y(attribute)h(instead.)24 b(When)17 b(used)h(in)f(a)f(function,)i -Fk(declare)e Fl(mak)o(es)g Fg(name)s Fl(s)g(lo)q(cal,)i(as)e(with)h -(the)240 2386 y Fk(local)d Fl(command.)0 2472 y Fk(enable)360 -2534 y(enable)23 b([-n])g([-a])h([)p Fg(name)i Fk(...])240 -2608 y Fl(Enable)19 b(and)f(disable)h(builtin)i(shell)e(commands.)28 -b(This)19 b(allo)o(ws)f(y)o(ou)f(to)h(use)g(a)f(disk)i(command)240 -2670 y(whic)o(h)d(has)f(the)g(same)f(name)h(as)g(a)f(shell)j(builtin.) -22 b(If)15 b Fk(-n)g Fl(is)g(used,)g(the)g Fg(name)s -Fl(s)g(b)q(ecome)h(disabled.)p eop -19 20 bop 0 -58 a Fl(Chapter)15 b(4:)k(Bash)d(Sp)q(eci\014c)h(F)l -(eatures)1226 b(19)240 183 y(Otherwise)18 b Fg(name)s -Fl(s)f(are)g(enabled.)28 b(F)l(or)17 b(example,)h(to)f(use)h(the)f -Fk(test)g Fl(binary)h(found)g(via)g Fk($PATH)240 246 -y Fl(instead)c(of)f(the)g(shell)i(builtin)g(v)o(ersion,)e(t)o(yp)q(e)h -(`)p Fk(enable)g(-n)h(test)p Fl('.)j(The)13 b Fk(-a)g -Fl(option)g(means)h(to)e(list)240 308 y(eac)o(h)j(builtin)j(with)d(an)g -(indication)j(of)c(whether)i(or)e(not)h(it)h(is)f(enabled.)0 -396 y Fk(help)360 459 y(help)23 b([)p Fg(pattern)p Fk(])240 -535 y Fl(Displa)o(y)13 b(helpful)i(information)e(ab)q(out)f(builtin)j -(commands.)k(If)13 b Fg(pattern)f Fl(is)i(sp)q(eci\014ed,)h -Fk(help)d Fl(giv)o(es)240 597 y(detailed)22 b(help)g(on)f(all)h -(commands)f(matc)o(hing)f Fg(pattern)p Fl(,)i(otherwise)f(a)f(list)i -(of)f(the)f(builtins)j(is)240 659 y(prin)o(ted.)0 748 -y Fk(local)360 811 y(local)g Fg(name)s Fk([=)p Fg(v)m(alue)s -Fk(])240 886 y Fl(F)l(or)10 b(eac)o(h)g(argumen)o(t,)g(create)h(a)f(lo) -q(cal)h(v)m(ariable)h(called)g Fg(name)p Fl(,)f(and)f(giv)o(e)h(it)g -Fg(v)m(alue)p Fl(.)19 b Fk(local)10 b Fl(can)g(only)240 -948 y(b)q(e)18 b(used)f(within)i(a)d(function;)j(it)e(mak)o(es)f(the)i -(v)m(ariable)g Fg(name)i Fl(ha)o(v)o(e)c(a)h(visible)i(scop)q(e)f -(restricted)240 1010 y(to)d(that)f(function)i(and)f(its)h(c)o(hildren.) -0 1099 y Fk(type)360 1162 y(type)23 b([-all])g([-type)g(|)h(-path])f([) -p Fg(name)k Fk(...])240 1237 y Fl(F)l(or)15 b(eac)o(h)g -Fg(name)p Fl(,)g(indicate)h(ho)o(w)f(it)h(w)o(ould)f(b)q(e)h(in)o -(terpreted)g(if)f(used)h(as)f(a)g(command)g(name.)240 -1313 y(If)e(the)g Fk(-type)g Fl(\015ag)f(is)i(used,)f -Fk(type)g Fl(returns)g(a)f(single)j(w)o(ord)d(whic)o(h)i(is)f(one)g(of) -g(\\alias",)g(\\function",)240 1375 y(\\builtin",)i(\\\014le")f(or)g -(\\k)o(eyw)o(ord",)e(if)i Fg(name)i Fl(is)e(an)g(alias,)g(shell)h -(function,)g(shell)g(builtin,)h(disk)e(\014le,)240 1437 -y(or)h(shell)h(reserv)o(ed)g(w)o(ord,)e(resp)q(ectiv)o(ely)l(.)240 -1512 y(If)j(the)g Fk(-path)g Fl(\015ag)f(is)i(used,)g -Fk(type)e Fl(either)i(returns)f(the)g(name)g(of)g(the)g(disk)g(\014le)i -(that)d(w)o(ould)h(b)q(e)240 1575 y(executed,)f(or)e(nothing)i(if)g -Fk(-type)e Fl(w)o(ould)i(not)f(return)g(\\\014le".)240 -1650 y(If)f(the)g Fk(-all)g Fl(\015ag)f(is)i(used,)f(returns)g(all)h -(of)f(the)g(places)g(that)g(con)o(tain)g(an)g(executable)h(named)f -Fg(\014le)p Fl(.)240 1712 y(This)i(includes)h(aliases)f(and)g -(functions,)f(if)h(and)f(only)h(if)g(the)f Fk(-path)f -Fl(\015ag)h(is)h(not)f(also)g(used.)240 1788 y Fk(Type)g -Fl(accepts)g Fk(-a)p Fl(,)f Fk(-t)p Fl(,)h(and)g Fk(-p)g -Fl(as)g(equiv)m(alen)o(t)i(to)d Fk(-all)p Fl(,)h Fk(-type)p -Fl(,)f(and)h Fk(-path)p Fl(,)f(resp)q(ectiv)o(ely)l(.)0 -1876 y Fk(ulimit)360 1939 y(ulimit)23 b([-acdmstfpnuvSH])f([)p -Fg(limit)q Fk(])240 2015 y(Ulimit)15 b Fl(pro)o(vides)i(con)o(trol)f(o) -o(v)o(er)f(the)i(resources)f(a)o(v)m(ailable)i(to)d(pro)q(cesses)i -(started)e(b)o(y)h(the)h(shell,)240 2077 y(on)e(systems)g(that)f(allo)o -(w)i(suc)o(h)f(con)o(trol.)20 b(If)15 b(an)g(option)h(is)g(giv)o(en,)f -(it)g(is)h(in)o(terpreted)g(as)f(follo)o(ws:)240 2165 -y Fk(-S)192 b Fl(c)o(hange)16 b(and)g(rep)q(ort)g(the)g(soft)f(limit)i -(asso)q(ciated)f(with)h(a)e(resource)h(\(the)g(default)g(if)480 -2228 y(the)f Fk(-H)g Fl(option)h(is)f(not)g(giv)o(en\).)240 -2316 y Fk(-H)192 b Fl(c)o(hange)15 b(and)h(rep)q(ort)f(the)g(hard)g -(limit)i(asso)q(ciated)e(with)h(a)e(resource.)240 2405 -y Fk(-a)192 b Fl(all)16 b(curren)o(t)f(limits)i(are)e(rep)q(orted.)240 -2493 y Fk(-c)192 b Fl(the)15 b(maxim)o(um)g(size)i(of)d(core)h(\014les) -i(created.)240 2582 y Fk(-d)192 b Fl(the)15 b(maxim)o(um)g(size)i(of)d -(a)h(pro)q(cess's)g(data)g(segmen)o(t.)240 2670 y Fk(-m)192 -b Fl(the)15 b(maxim)o(um)g(residen)o(t)h(set)f(size.)p -eop -20 21 bop 0 -58 a Fl(20)1623 b(Bash)15 b(F)l(eatures)240 -183 y Fk(-s)192 b Fl(the)15 b(maxim)o(um)g(stac)o(k)g(size.)240 -268 y Fk(-t)192 b Fl(the)15 b(maxim)o(um)g(amoun)o(t)g(of)g(cpu)g(time) -h(in)g(seconds.)240 353 y Fk(-f)192 b Fl(the)15 b(maxim)o(um)g(size)i -(of)d(\014les)i(created)g(b)o(y)f(the)g(shell.)240 438 -y Fk(-p)192 b Fl(the)15 b(pip)q(e)i(bu\013er)e(size.)240 -523 y Fk(-n)192 b Fl(the)15 b(maxim)o(um)g(n)o(um)o(b)q(er)h(of)f(op)q -(en)h(\014le)g(descriptors.)240 608 y Fk(-u)192 b Fl(the)15 -b(maxim)o(um)g(n)o(um)o(b)q(er)h(of)f(pro)q(cesses)g(a)o(v)m(ailable)i -(to)e(a)g(single)h(user.)240 693 y Fk(-v)192 b Fl(the)15 -b(maxim)o(um)g(amoun)o(t)g(of)g(virtual)g(memory)g(a)o(v)m(ailable)i -(to)d(the)i(pro)q(cess.)240 778 y(If)i Fg(limit)i Fl(is)e(giv)o(en,)g -(it)g(is)g(the)f(new)h(v)m(alue)h(of)e(the)g(sp)q(eci\014ed)j -(resource.)27 b(Otherwise,)18 b(the)g(curren)o(t)240 -841 y(v)m(alue)h(of)d(the)i(sp)q(eci\014ed)h(resource)f(is)f(prin)o -(ted.)27 b(If)18 b(no)f(option)h(is)g(giv)o(en,)f(then)h(`)p -Fk(-f)p Fl(')e(is)i(assumed.)240 903 y(V)l(alues)f(are)e(in)i(1024-b)o -(yte)d(incremen)o(ts,)i(except)h(for)e(`)p Fk(-t)p Fl(',)f(whic)o(h)j -(is)f(in)h(seconds,)e(`)p Fk(-p)p Fl(',)g(whic)o(h)h(is)240 -965 y(in)g(units)g(of)f(512-b)o(yte)f(blo)q(c)o(ks,)i(and)f(`)p -Fk(-n)p Fl(')f(and)h(`)p Fk(-u)p Fl(',)f(whic)o(h)i(are)f(unscaled)i(v) -m(alues.)0 1185 y Fj(4.5)33 b(The)15 b(Set)g(Builtin)62 -1322 y Fl(This)h(builtin)i(is)d(so)g(o)o(v)o(erloaded)g(that)g(it)g -(deserv)o(es)h(its)f(o)o(wn)g(section.)0 1470 y Fk(set)360 -1531 y(set)23 b([-abefhkmnptuvxldCHP])e([-o)j Fg(option)p -Fk(])g([)p Fg(argumen)o(t)g Fk(...])240 1616 y(-a)192 -b Fl(Mark)14 b(v)m(ariables)j(whic)o(h)f(are)f(mo)q(di\014ed)h(or)f -(created)g(for)g(exp)q(ort.)240 1701 y Fk(-b)192 b Fl(Cause)19 -b(the)g(status)f(of)g(terminated)h(bac)o(kground)g(jobs)g(to)f(b)q(e)h -(rep)q(orted)g(immedi-)480 1764 y(ately)l(,)c(rather)g(than)g(b)q -(efore)g(prin)o(ting)h(the)g(next)f(primary)g(prompt.)240 -1849 y Fk(-e)192 b Fl(Exit)15 b(immediately)i(if)f(a)f(command)g(exits) -g(with)h(a)f(non-zero)g(status.)240 1934 y Fk(-f)192 -b Fl(Disable)16 b(\014le)g(name)g(generation)f(\(globbing\).)240 -2019 y Fk(-h)192 b Fl(Lo)q(cate)19 b(and)h(remem)o(b)q(er)f(\(hash\))f -(commands)h(as)g(functions)h(are)e(de\014ned,)k(rather)480 -2081 y(than)15 b(when)h(the)f(function)h(is)g(executed.)240 -2166 y Fk(-k)192 b Fl(All)16 b(k)o(eyw)o(ord)d(argumen)o(ts)h(are)g -(placed)i(in)f(the)g(en)o(vironmen)o(t)f(for)g(a)g(command,)g(not)480 -2228 y(just)h(those)g(that)f(precede)j(the)e(command)g(name.)240 -2313 y Fk(-m)192 b Fl(Job)15 b(con)o(trol)g(is)h(enabled)h(\(see)e -(Chapter)g(5)g([Job)g(Con)o(trol],)f(page)h(29\).)240 -2398 y Fk(-n)192 b Fl(Read)16 b(commands)f(but)g(do)g(not)g(execute)h -(them.)240 2472 y Fk(-o)f Fg(option-name)480 2534 y Fl(Set)g(the)h -(\015ag)e(corresp)q(onding)j(to)d Fg(option-name)s Fl(:)480 -2608 y Fk(allexport)720 2670 y Fl(same)h(as)g Fk(-a)p -Fl(.)p eop -21 22 bop 0 -58 a Fl(Chapter)15 b(4:)k(Bash)d(Sp)q(eci\014c)h(F)l -(eatures)1226 b(21)480 183 y Fk(braceexpand)720 246 y -Fl(the)16 b(shell)i(will)g(p)q(erform)e(brace)g(expansion)h(\(see)f -(Section)h(2.2)e([Brace)720 308 y(Expansion],)g(page)g(7\).)480 -396 y Fk(emacs)120 b Fl(use)15 b(an)g(emacs-st)o(yle)h(line)g(editing)h -(in)o(terface)e(\(see)g(Chapter)g(7)g([Com-)720 458 y(mand)g(Line)i -(Editing],)e(page)g(37\).)480 547 y Fk(errexit)72 b Fl(same)15 -b(as)g Fk(-e)p Fl(.)480 622 y Fk(histexpand)720 685 y -Fl(same)g(as)g Fk(-H)p Fl(.)480 760 y Fk(ignoreeof)720 -822 y Fl(the)g(shell)i(will)g(not)e(exit)g(up)q(on)h(reading)g(EOF.)480 -898 y Fk(interactive-comments)720 960 y Fl(allo)o(w)h(a)g(w)o(ord)g(b)q -(eginning)i(with)f(a)e(`)p Fk(#)p Fl(')h(to)f(cause)i(that)e(w)o(ord)h -(and)g(all)720 1022 y(remaining)11 b(c)o(haracters)f(on)g(that)f(line)j -(to)e(b)q(e)h(ignored)f(in)h(an)g(in)o(teractiv)o(e)720 -1084 y(shell.)480 1173 y Fk(monitor)72 b Fl(same)15 b(as)g -Fk(-m)p Fl(.)480 1248 y Fk(noclobber)720 1310 y Fl(same)g(as)g -Fk(-C)p Fl(.)480 1399 y Fk(noexec)96 b Fl(same)15 b(as)g -Fk(-n)p Fl(.)480 1487 y Fk(noglob)96 b Fl(same)15 b(as)g -Fk(-f)p Fl(.)480 1576 y Fk(nohash)96 b Fl(same)15 b(as)g -Fk(-d)p Fl(.)480 1664 y Fk(notify)96 b Fl(same)15 b(as)g -Fk(-b)p Fl(.)480 1753 y Fk(nounset)72 b Fl(same)15 b(as)g -Fk(-u)p Fl(.)480 1841 y Fk(physical)48 b Fl(same)15 b(as)g -Fk(-P)p Fl(.)480 1930 y Fk(posix)120 b Fl(c)o(hange)11 -b(the)h(b)q(eha)o(vior)f(of)g(Bash)h(where)f(the)g(default)h(op)q -(eration)g(di\013ers)720 1992 y(from)17 b(the)g(P)o(osix)g(1003.2)f -(standard)h(to)f(matc)o(h)h(the)h(standard.)25 b(This)720 -2054 y(is)19 b(in)o(tended)g(to)f(mak)o(e)g(Bash)g(b)q(eha)o(v)o(e)g -(as)g(a)g(strict)g(sup)q(erset)h(of)f(that)720 2116 y(standard.)480 -2192 y Fk(privileged)720 2254 y Fl(same)d(as)g Fk(-p)p -Fl(.)480 2342 y Fk(verbose)72 b Fl(same)15 b(as)g Fk(-v)p -Fl(.)480 2431 y Fk(vi)192 b Fl(use)16 b(a)e Fk(vi)p Fl(-st)o(yle)i -(line)g(editing)h(in)o(terface.)480 2519 y Fk(xtrace)96 -b Fl(same)15 b(as)g Fk(-x)p Fl(.)240 2608 y Fk(-p)192 -b Fl(T)l(urn)14 b(on)g(privileged)j(mo)q(de.)j(In)14 -b(this)h(mo)q(de,)f(the)g Fk($ENV)g Fl(\014le)h(is)f(not)g(pro)q -(cessed,)h(and)480 2670 y(shell)21 b(functions)g(are)f(not)f(inherited) -j(from)d(the)h(en)o(vironmen)o(t.)34 b(This)20 b(is)g(enabled)p -eop -22 23 bop 0 -58 a Fl(22)1623 b(Bash)15 b(F)l(eatures)480 -183 y(automatically)g(on)f(startup)f(if)i(the)f(e\013ectiv)o(e)g(user)h -(\(group\))e(id)i(is)g(not)e(equal)i(to)f(the)480 246 -y(real)j(user)g(\(group\))e(id.)25 b(T)l(urning)18 b(this)f(option)g -(o\013)f(causes)g(the)h(e\013ectiv)o(e)g(user)g(and)480 -308 y(group)e(ids)h(to)e(b)q(e)i(set)f(to)g(the)g(real)h(user)f(and)g -(group)g(ids.)240 396 y Fk(-t)192 b Fl(Exit)15 b(after)g(reading)h(and) -f(executing)h(one)g(command.)240 485 y Fk(-u)192 b Fl(T)l(reat)15 -b(unset)g(v)m(ariables)i(as)d(an)i(error)e(when)i(substituting.)240 -573 y Fk(-v)192 b Fl(Prin)o(t)15 b(shell)i(input)f(lines)h(as)e(they)g -(are)g(read.)240 661 y Fk(-x)192 b Fl(Prin)o(t)15 b(commands)g(and)h -(their)f(argumen)o(ts)g(as)f(they)i(are)f(executed.)240 -750 y Fk(-l)192 b Fl(Sa)o(v)o(e)15 b(and)g(restore)g(the)g(binding)i -(of)e(the)g Fg(name)j Fl(in)e(a)f Fk(for)g Fl(command.)240 -838 y Fk(-d)192 b Fl(Disable)18 b(the)f(hashing)h(of)f(commands)f(that) -h(are)f(lo)q(ok)o(ed)i(up)f(for)g(execution.)26 b(Nor-)480 -900 y(mally)l(,)15 b(commands)g(are)f(remem)o(b)q(ered)h(in)h(a)e(hash) -h(table,)f(and)h(once)g(found,)g(do)f(not)480 963 y(ha)o(v)o(e)h(to)f -(b)q(e)i(lo)q(ok)o(ed)g(up)g(again.)240 1051 y Fk(-C)192 -b Fl(Disallo)o(w)16 b(output)f(redirection)h(to)f(existing)h(\014les.) -240 1140 y Fk(-H)192 b Fl(Enable)16 b(!)k(st)o(yle)15 -b(history)g(substitution.)21 b(This)16 b(\015ag)f(is)h(on)f(b)o(y)g -(default.)240 1228 y Fk(-P)192 b Fl(If)14 b(set,)g(do)g(not)g(follo)o -(w)g(sym)o(b)q(olic)h(links)h(when)f(p)q(erforming)f(commands)g(suc)o -(h)h(as)e Fk(cd)480 1290 y Fl(whic)o(h)h(c)o(hange)f(the)g(curren)o(t)g -(directory)l(.)20 b(The)13 b(ph)o(ysical)i(directory)e(is)h(used)g -(instead.)240 1379 y Fk(--)192 b Fl(If)16 b(no)f(argumen)o(ts)f(follo)o -(w)i(this)f(\015ag,)g(then)h(the)f(p)q(ositional)i(parameters)d(are)h -(unset.)480 1441 y(Otherwise,)e(the)e(p)q(ositional)i(parameters)e(are) -g(set)h(to)f(the)g Fg(argumen)o(ts)p Fl(,)g(ev)o(en)h(if)g(some)480 -1503 y(of)j(them)g(b)q(egin)h(with)g(a)f Fk(-)p Fl(.)240 -1592 y Fk(-)216 b Fl(Signal)15 b(the)g(end)f(of)g(options,)g(cause)h -(all)g(remaining)g Fg(argumen)o(ts)g Fl(to)f(b)q(e)h(assigned)g(to)480 -1654 y(the)h(p)q(ositional)h(parameters.)22 b(The)16 -b Fk(-x)f Fl(and)i Fk(-v)e Fl(options)h(are)g(turned)g(o\013.)22 -b(If)16 b(there)480 1716 y(are)f(no)g(argumen)o(ts,)f(the)h(p)q -(ositional)i(parameters)d(remain)i(unc)o(hanged.)240 -1805 y(Using)21 b(`)p Fk(+)p Fl(')e(rather)g(than)h(`)p -Fk(-)p Fl(')f(causes)h(these)h(\015ags)e(to)h(b)q(e)g(turned)h(o\013.) -33 b(The)21 b(\015ags)e(can)h(also)g(b)q(e)240 1867 y(used)e(up)q(on)g -(in)o(v)o(o)q(cation)g(of)f(the)g(shell.)28 b(The)17 -b(curren)o(t)h(set)f(of)g(\015ags)f(ma)o(y)h(b)q(e)h(found)g(in)g -Fk($-)p Fl(.)26 b(The)240 1929 y(remaining)14 b(N)f Fg(argumen)o(ts)h -Fl(are)f(p)q(ositional)h(parameters)e(and)i(are)e(assigned,)i(in)g -(order,)f(to)f Fk($1)p Fl(,)h Fk($2)p Fl(,)240 1991 y(..)19 -b Fk($N)p Fl(.)h(If)15 b(no)h(argumen)o(ts)e(are)h(giv)o(en,)g(all)h -(shell)h(v)m(ariables)g(are)d(prin)o(ted.)0 2221 y Fj(4.6)33 -b(Bash)14 b(V)-6 b(ariables)62 2359 y Fl(These)16 b(v)m(ariables)g(are) -f(set)g(or)g(used)h(b)o(y)f(bash,)g(but)g(other)g(shells)i(do)e(not)g -(normally)g(treat)g(them)g(sp)q(ecially)l(.)0 2496 y -Fk(HISTCONTROL)0 2545 y(history_control)240 2608 y Fl(Set)i(to)g(a)g(v) -m(alue)h(of)f(`)p Fk(ignorespace)p Fl(',)e(it)j(means)f(don't)g(en)o -(ter)g(lines)i(whic)o(h)f(b)q(egin)g(with)g(a)f(space)240 -2670 y(or)f(tab)f(in)o(to)h(the)h(history)f(list.)23 -b(Set)16 b(to)g(a)g(v)m(alue)h(of)f(`)p Fk(ignoredups)p -Fl(',)d(it)k(means)f(don't)f(en)o(ter)h(lines)p eop -23 24 bop 0 -58 a Fl(Chapter)15 b(4:)k(Bash)d(Sp)q(eci\014c)h(F)l -(eatures)1226 b(23)240 183 y(whic)o(h)16 b(matc)o(h)f(the)g(last)g(en)o -(tered)g(line.)22 b(A)15 b(v)m(alue)h(of)f(`)p Fk(ignoreboth)p -Fl(')e(com)o(bines)j(the)f(t)o(w)o(o)f(options.)240 246 -y(Unset,)f(or)f(set)g(to)g(an)o(y)h(other)f(v)m(alue)i(than)e(those)h -(ab)q(o)o(v)o(e,)f(means)h(to)f(sa)o(v)o(e)g(all)h(lines)i(on)d(the)h -(history)240 308 y(list.)0 398 y Fk(HISTFILE)48 b Fl(The)15 -b(name)h(of)e(the)i(\014le)g(to)e(whic)o(h)j(the)e(command)g(history)g -(is)h(sa)o(v)o(ed.)0 488 y Fk(HISTSIZE)48 b Fl(If)15 -b(set,)g(this)h(is)f(the)h(maxim)o(um)f(n)o(um)o(b)q(er)g(of)g -(commands)g(to)g(remem)o(b)q(er)g(in)h(the)f(history)l(.)0 -564 y Fk(histchars)240 627 y Fl(Up)j(to)g(three)g(c)o(haracters)g(whic) -o(h)h(con)o(trol)e(history)h(expansion,)i(quic)o(k)f(substitution,)g -(and)f(tok-)240 689 y(enization)j(\(see)e(Section)i(6.1)e([History)g -(In)o(teraction],)h(page)f(33\).)33 b(The)20 b(\014rst)f(c)o(haracter)g -(is)h(the)240 751 y Fg(history-expansion-c)o(har)p Fl(,)d(that)e(is,)i -(the)f(c)o(haracter)f(whic)o(h)i(signi\014es)g(the)g(start)d(of)i(a)g -(history)g(ex-)240 814 y(pansion,)23 b(normally)f(`)p -Fk(!)p Fl('.)37 b(The)21 b(second)h(c)o(haracter)e(is)i(the)f(c)o -(haracter)g(whic)o(h)h(signi\014es)h(`quic)o(k)240 876 -y(substitution')d(when)h(seen)f(as)g(the)g(\014rst)g(c)o(haracter)f(on) -h(a)g(line,)i(normally)f(`)p Fk(^)p Fl('.)33 b(The)20 -b(optional)240 938 y(third)15 b(c)o(haracter)f(is)h(the)f(c)o(haracter) -g(whic)o(h)h(signi\014es)h(the)f(remainder)g(of)f(the)h(line)h(is)f(a)f -(commen)o(t,)240 1000 y(when)f(found)f(as)g(the)g(\014rst)g(c)o -(haracter)f(of)h(a)g(w)o(ord,)f(usually)j(`)p Fk(#)p -Fl('.)k(The)12 b(history)g(commen)o(t)g(c)o(haracter)240 -1063 y(causes)k(history)g(substitution)g(to)f(b)q(e)h(skipp)q(ed)i(for) -d(the)h(remaining)h(w)o(ords)d(on)i(the)g(line.)23 b(It)16 -b(do)q(es)240 1125 y(not)f(necessarily)h(cause)g(the)f(shell)i(parser)e -(to)f(treat)h(the)g(rest)g(of)f(the)i(line)h(as)d(a)h(commen)o(t.)0 -1215 y Fk(HISTCMD)72 b Fl(The)16 b(history)g(n)o(um)o(b)q(er,)f(or)h -(index)h(in)f(the)g(history)g(list,)g(of)f(the)h(curren)o(t)g(command.) -21 b(If)16 b Fk(HISTCMD)240 1277 y Fl(is)g(unset,)f(it)g(loses)h(its)f -(sp)q(ecial)i(prop)q(erties,)f(ev)o(en)f(if)h(it)f(is)h(subsequen)o -(tly)h(reset.)0 1354 y Fk(hostname_completion_file)0 -1416 y(HOSTFILE)48 b Fl(Con)o(tains)17 b(the)h(name)g(of)f(a)h(\014le)h -(in)f(the)g(same)f(format)g(as)g(`)p Fk(/etc/hosts)p -Fl(')f(that)h(should)i(b)q(e)f(read)240 1478 y(when)g(the)g(shell)i -(needs)f(to)e(complete)i(a)e(hostname.)28 b(Y)l(ou)18 -b(can)g(c)o(hange)g(the)g(\014le)h(in)o(teractiv)o(ely;)240 -1540 y(the)c(next)h(time)g(y)o(ou)f(attempt)f(to)h(complete)h(a)f -(hostname,)g(Bash)g(will)i(add)f(the)f(con)o(ten)o(ts)g(of)g(the)240 -1603 y(new)g(\014le)i(to)d(the)i(already)f(existing)h(database.)0 -1679 y Fk(MAILCHECK)240 1741 y Fl(Ho)o(w)k(often)g(\(in)h(seconds\))f -(that)g(the)g(shell)i(should)f(c)o(hec)o(k)g(for)f(mail)h(in)g(the)f -(\014les)i(sp)q(eci\014ed)g(in)240 1803 y Fk(MAILPATH)p -Fl(.)0 1880 y Fk(PROMPT_COMMAND)240 1942 y Fl(If)15 b(presen)o(t,)g -(this)g(con)o(tains)g(a)g(string)g(whic)o(h)h(is)f(a)g(command)f(to)h -(execute)g(b)q(efore)h(the)f(prin)o(ting)g(of)240 2004 -y(eac)o(h)g(primary)h(prompt)e(\()p Fk($PS1)p Fl(\).)0 -2094 y Fk(UID)168 b Fl(The)15 b(n)o(umeric)i(real)e(user)g(id)h(of)f -(the)g(curren)o(t)h(user.)0 2185 y Fk(EUID)144 b Fl(The)15 -b(n)o(umeric)i(e\013ectiv)o(e)e(user)g(id)h(of)f(the)g(curren)o(t)h -(user.)0 2275 y Fk(HOSTTYPE)48 b Fl(A)15 b(string)g(describing)i(the)f -(mac)o(hine)g(Bash)f(is)h(running)g(on.)0 2365 y Fk(OSTYPE)96 -b Fl(A)15 b(string)g(describing)i(the)f(op)q(erating)f(system)g(Bash)g -(is)h(running)g(on.)0 2455 y Fk(FIGNORE)72 b Fl(A)14 -b(colon-separated)h(list)g(of)f(su\016xes)g(to)g(ignore)g(when)h(p)q -(erforming)g(\014lename)g(completion)h(A)e(\014le)240 -2518 y(name)j(whose)h(su\016x)f(matc)o(hes)g(one)g(of)g(the)h(en)o -(tries)f(in)i Fk(FIGNORE)d Fl(is)i(excluded)h(from)e(the)g(list)h(of) -240 2580 y(matc)o(hed)d(\014le)h(names.)k(A)15 b(sample)h(v)m(alue)h -(is)e(`)p Fk(.o:~)p Fl(')0 2670 y Fk(INPUTRC)72 b Fl(The)15 -b(name)h(of)e(the)i(Readline)h(startup)e(\014le,)h(o)o(v)o(erriding)f -(the)g(default)h(of)f(`)p Fk(~/.inputrc)p Fl('.)p eop -24 25 bop 0 -58 a Fl(24)1623 b(Bash)15 b(F)l(eatures)0 -183 y Fk(BASH_VERSION)240 246 y Fl(The)g(v)o(ersion)h(n)o(um)o(b)q(er)f -(of)g(the)g(curren)o(t)h(instance)g(of)e(Bash.)0 318 -y Fk(IGNOREEOF)240 380 y Fl(Con)o(trols)g(the)h(action)f(of)g(the)h -(shell)h(on)f(receipt)g(of)g(an)f Fk(EOF)g Fl(c)o(haracter)g(as)g(the)h -(sole)g(input.)21 b(If)15 b(set,)240 443 y(then)j(the)g(v)m(alue)h(of)f -(it)g(is)g(the)g(n)o(um)o(b)q(er)h(of)e(consecutiv)o(e)i -Fk(EOF)f Fl(c)o(haracters)f(that)g(can)h(b)q(e)g(read)g(as)240 -505 y(the)d(\014rst)f(c)o(haracters)f(on)i(an)f(input)h(line)i(b)q -(efore)d(the)h(shell)h(will)g(exit.)k(If)15 b(the)f(v)m(ariable)i -(exists)f(but)240 567 y(do)q(es)h(not)f(ha)o(v)o(e)g(a)g(n)o(umeric)h -(v)m(alue)h(\(or)d(has)h(no)h(v)m(alue\))g(then)f(the)h(default)g(is)g -(10.)k(If)15 b(the)h(v)m(ariable)240 629 y(do)q(es)e(not)g(exist,)g -(then)g Fk(EOF)f Fl(signi\014es)j(the)e(end)g(of)g(input)h(to)e(the)h -(shell.)21 b(This)14 b(is)h(only)f(in)h(e\013ect)f(for)240 -692 y(in)o(teractiv)o(e)i(shells.)0 764 y Fk(no_exit_on_failed_exec)240 -826 y Fl(If)e(this)h(v)m(ariable)g(exists,)g(the)f(shell)h(will)h(not)e -(exit)g(in)h(the)g(case)f(that)f(it)h(couldn't)h(execute)g(the)f -(\014le)240 889 y(sp)q(eci\014ed)j(in)f(the)g Fk(exec)e -Fl(command.)0 972 y Fk(nolinks)72 b Fl(If)20 b(presen)o(t,)g(sa)o(ys)e -(not)h(to)g(follo)o(w)g(sym)o(b)q(olic)i(links)f(when)g(doing)g -(commands)f(that)g(c)o(hange)g(the)240 1034 y(curren)o(t)i(w)o(orking)h -(directory)l(.)39 b(By)22 b(default,)h(bash)f(follo)o(ws)f(the)h -(logical)h(c)o(hain)f(of)f(directories)240 1096 y(when)16 -b(p)q(erforming)f(commands)g(suc)o(h)h(as)f Fk(cd)f Fl(whic)o(h)j(c)o -(hange)e(the)g(curren)o(t)g(directory)l(.)240 1169 y(F)l(or)g(example,) -g(if)h(`)p Fk(/usr/sys)p Fl(')d(is)j(a)f(link)h(to)f(`)p -Fk(/usr/local/sys)p Fl(')d(then:)360 1229 y Fk($)24 b(cd)f(/usr/sys;)g -(echo)g($PWD)360 1278 y(/usr/sys)360 1328 y($)h(cd)f(..;)h(pwd)360 -1378 y(/usr)240 1451 y Fl(If)15 b Fk(nolinks)g Fl(exists,)g(then:)360 -1511 y Fk($)24 b(cd)f(/usr/sys;)g(echo)g($PWD)360 1561 -y(/usr/local/sys)360 1610 y($)h(cd)f(..;)h(pwd)360 1660 -y(/usr/local)240 1733 y Fl(See)12 b(also)e(the)i(description)g(of)e -(the)i Fk(-P)e Fl(option)h(to)g(the)g Fk(set)f Fl(builtin,)k(Section)e -(4.5)e([The)g(Set)h(Builtin],)240 1795 y(page)k(20.)0 -2010 y Fj(4.7)33 b(Shell)16 b(Arithmetic)0 2209 y Ff(4.7.1)30 -b(Arithmetic)16 b(Ev)m(aluation)62 2346 y Fl(The)f(shell)g(allo)o(ws)f -(arithmetic)h(expressions)g(to)e(b)q(e)i(ev)m(aluated,)g(as)e(one)h(of) -g(the)g(shell)i(expansions)e(or)g(b)o(y)g(the)0 2408 -y Fk(let)h Fl(builtin.)62 2545 y(Ev)m(aluation)i(is)g(done)f(in)h(long) -f(in)o(tegers)g(with)g(no)g(c)o(hec)o(k)g(for)g(o)o(v)o(er\015o)o(w,)e -(though)i(division)i(b)o(y)e(0)f(is)i(trapp)q(ed)0 2608 -y(and)g(\015agged)f(as)g(an)h(error.)23 b(The)17 b(follo)o(wing)g(list) -h(of)e(op)q(erators)g(is)h(group)q(ed)g(in)o(to)f(lev)o(els)i(of)e -(equal-precedence)0 2670 y(op)q(erators.)j(The)c(lev)o(els)i(are)e -(listed)h(in)g(order)f(of)g(decreasing)h(precedence.)p -eop -25 26 bop 0 -58 a Fl(Chapter)15 b(4:)k(Bash)d(Sp)q(eci\014c)h(F)l -(eatures)1226 b(25)0 183 y Fk(-)15 b(+)177 b Fl(unary)15 -b(min)o(us)h(and)f(plus)0 271 y Fk(!)g(~)177 b Fl(logical)16 -b(and)g(bit)o(wise)g(negation)0 359 y Fk(*)f(/)g(\045)138 -b Fl(m)o(ultiplication,)17 b(division,)g(remainder)0 -447 y Fk(+)e(-)177 b Fl(addition,)16 b(subtraction)0 -535 y Fk(<<)f(>>)129 b Fl(left)16 b(and)f(righ)o(t)g(bit)o(wise)h -(shifts)0 622 y Fk(<=)f(>=)g(<)g(>)51 b Fl(comparison)0 -710 y Fk(==)15 b(!=)129 b Fl(equalit)o(y)16 b(and)f(inequalit)o(y)0 -798 y Fk(&)216 b Fl(bit)o(wise)16 b(AND)0 886 y Fk(^)216 -b Fl(bit)o(wise)16 b(exclusiv)o(e)h(OR)0 974 y Fk(|)216 -b Fl(bit)o(wise)16 b(OR)0 1062 y Fk(&&)192 b Fl(logical)16 -b(AND)0 1149 y Fk(||)192 b Fl(logical)16 b(OR)0 1225 -y Fk(=)f(*=)g(/=)g(\045=)g(+=)g(-=)f(<<=)h(>>=)g(&=)g(^=)g(|=)240 -1287 y Fl(assignmen)o(t)62 1437 y(Shell)h(v)m(ariables)e(are)f(allo)o -(w)o(ed)h(as)f(op)q(erands;)h(parameter)e(expansion)j(is)e(p)q -(erformed)h(b)q(efore)g(the)f(expression)0 1499 y(is)k(ev)m(aluated.)26 -b(The)17 b(v)m(alue)i(of)d(a)h(parameter)f(is)h(co)q(erced)h(to)e(a)h -(long)g(in)o(teger)g(within)h(an)f(expression.)25 b(A)17 -b(shell)0 1561 y(v)m(ariable)g(need)f(not)e(ha)o(v)o(e)h(its)h(in)o -(teger)f(attribute)g(turned)h(on)f(to)f(b)q(e)i(used)g(in)g(an)f -(expression.)62 1699 y(Constan)o(ts)21 b(with)i(a)f(leading)i(0)e(are)g -(in)o(terpreted)h(as)f(o)q(ctal)h(n)o(um)o(b)q(ers.)41 -b(A)23 b(leading)h Fk(0x)e Fl(or)g Fk(0X)g Fl(denotes)0 -1761 y(hexadecimal.)e(Otherwise,)14 b(n)o(um)o(b)q(ers)e(tak)o(e)f(the) -i(form)e([)p Fg(base#)r Fl(]n,)g(where)i Fg(base)h Fl(is)f(a)f(decimal) -h(n)o(um)o(b)q(er)g(b)q(et)o(w)o(een)0 1823 y(2)h(and)g(36)g(represen)o -(ting)g(the)h(arithmetic)f(base,)g(and)h Fg(n)f Fl(is)h(a)e(n)o(um)o(b) -q(er)i(in)g(that)e(base.)20 b(If)14 b Fg(base)j Fl(is)e(omitted,)f -(then)0 1886 y(base)h(10)g(is)h(used.)62 2023 y(Op)q(erators)i(are)f -(ev)m(aluated)i(in)g(order)e(of)h(precedence.)29 b(Sub-expressions)20 -b(in)e(paren)o(theses)g(are)g(ev)m(aluated)0 2085 y(\014rst)d(and)g(ma) -o(y)g(o)o(v)o(erride)g(the)g(precedence)i(rules)f(ab)q(o)o(v)o(e.)0 -2296 y Ff(4.7.2)30 b(Arithmetic)16 b(Expansion)62 2433 -y Fl(Arithmetic)h(expansion)f(allo)o(ws)g(the)f(ev)m(aluation)i(of)e -(an)g(arithmetic)i(expression)f(and)g(the)f(substitution)h(of)0 -2495 y(the)f(result.)21 b(There)15 b(are)g(t)o(w)o(o)f(formats)g(for)g -(arithmetic)i(expansion:)120 2620 y Fk($[)24 b(expression)e(])120 -2670 y($\(\()h(expression)g(\)\))p eop -26 27 bop 0 -58 a Fl(26)1623 b(Bash)15 b(F)l(eatures)62 -183 y(The)e(expression)h(is)f(treated)f(as)g(if)h(it)g(w)o(ere)g -(within)h(double)g(quotes,)e(but)h(a)f(double)i(quote)f(inside)h(the)f -(braces)0 246 y(or)i(paren)o(theses)g(is)h(not)f(treated)g(sp)q -(ecially)l(.)22 b(All)17 b(tok)o(ens)e(in)h(the)f(expression)h(undergo) -g(parameter)e(expansion,)0 308 y(command)h(substitution,)h(and)f(quote) -g(remo)o(v)m(al.)20 b(Arithmetic)c(substitutions)g(ma)o(y)f(b)q(e)h -(nested.)62 446 y(The)k(ev)m(aluation)g(is)g(p)q(erformed)f(according)h -(to)f(the)g(rules)h(listed)h(ab)q(o)o(v)o(e.)31 b(If)20 -b(the)f(expression)h(is)g(in)o(v)m(alid,)0 508 y(Bash)15 -b(prin)o(ts)h(a)f(message)f(indicating)j(failure)g(and)e(no)g -(substitution)h(o)q(ccurs.)0 724 y Ff(4.7.3)30 b(Arithmetic)16 -b(Builtins)0 875 y Fk(let)360 938 y(let)23 b Fg(expression)i -Fk([)p Fg(expression)p Fk(])240 1014 y Fl(The)16 b Fk(let)f -Fl(builtin)i(allo)o(ws)f(arithmetic)g(to)f(b)q(e)h(p)q(erformed)g(on)f -(shell)i(v)m(ariables.)22 b(Eac)o(h)15 b Fg(expression)240 -1076 y Fl(is)e(ev)m(aluated)h(according)g(to)e(the)h(rules)g(giv)o(en)h -(previously)g(\(see)f(Section)g(4.7.1)f([Arithmetic)h(Ev)m(al-)240 -1138 y(uation],)18 b(page)f(24\).)27 b(If)18 b(the)g(last)f -Fg(expression)i Fl(ev)m(aluates)f(to)f(0,)h Fk(let)f -Fl(returns)h(1;)g(otherwise)g(0)f(is)240 1201 y(returned.)0 -1433 y Fj(4.8)33 b(Con)n(trolling)17 b(the)e(Prompt)62 -1571 y Fl(The)j(v)m(alue)g(of)e(the)h(v)m(ariable)i Fk($PROMPT_COMMAND) -c Fl(is)i(examined)h(just)f(b)q(efore)g(Bash)h(prin)o(ts)f(eac)o(h)g -(primary)0 1633 y(prompt.)32 b(If)19 b(it)h(is)f(set)g(and)h(non-n)o -(ull,)h(then)f(the)f(v)m(alue)i(is)f(executed)g(just)f(as)g(if)g(y)o -(ou)g(had)h(t)o(yp)q(ed)f(it)h(on)f(the)0 1696 y(command)c(line.)62 -1833 y(In)20 b(addition,)g(the)f(follo)o(wing)h(table)f(describ)q(es)h -(the)f(sp)q(ecial)i(c)o(haracters)d(whic)o(h)i(can)f(app)q(ear)g(in)g -(the)g Fk(PS1)0 1896 y Fl(v)m(ariable:)0 2047 y Fk(\\t)192 -b Fl(the)15 b(time,)g(in)h(HH:MM:SS)f(format.)0 2136 -y Fk(\\d)192 b Fl(the)15 b(date,)g(in)h Fk(")p Fl(W)l(eekda)o(y)f(Mon)o -(th)f(Date)p Fk(")h Fl(format)f(\(e.g.)19 b Fk(")p Fl(T)l(ue)c(Ma)o(y)g -(26)p Fk(")p Fl(\).)0 2225 y Fk(\\n)192 b Fl(newline.)0 -2314 y Fk(\\s)g Fl(the)15 b(name)g(of)g(the)h(shell,)g(the)f(basename)h -(of)e Fk($0)h Fl(\(the)g(p)q(ortion)h(follo)o(wing)g(the)f(\014nal)h -(slash\).)0 2403 y Fk(\\w)192 b Fl(the)15 b(curren)o(t)g(w)o(orking)g -(directory)l(.)0 2492 y Fk(\\W)192 b Fl(the)15 b(basename)h(of)e -Fk($PWD)p Fl(.)0 2581 y Fk(\\u)192 b Fl(y)o(our)15 b(username.)0 -2670 y Fk(\\h)192 b Fl(the)15 b(hostname.)p eop -27 28 bop 0 -58 a Fl(Chapter)15 b(4:)k(Bash)d(Sp)q(eci\014c)h(F)l -(eatures)1226 b(27)0 183 y Fk(\\#)192 b Fl(the)15 b(command)g(n)o(um)o -(b)q(er)h(of)f(this)g(command.)0 270 y Fk(\\!)192 b Fl(the)15 -b(history)g(n)o(um)o(b)q(er)h(of)f(this)g(command.)0 -358 y Fk(\\nnn)144 b Fl(the)15 b(c)o(haracter)g(corresp)q(onding)h(to)e -(the)i(o)q(ctal)f(n)o(um)o(b)q(er)h Fk(nnn)p Fl(.)0 445 -y Fk(\\$)192 b Fl(if)16 b(the)f(e\013ectiv)o(e)g(uid)i(is)e(0,)g -Fk(#)p Fl(,)g(otherwise)g Fk($)p Fl(.)0 532 y Fk(\\\\)192 -b Fl(a)15 b(bac)o(kslash.)0 619 y Fk(\\[)192 b Fl(b)q(egin)18 -b(a)e(sequence)i(of)e(non-prin)o(ting)h(c)o(haracters.)23 -b(This)17 b(could)h(b)q(e)f(used)g(to)f(em)o(b)q(ed)h(a)f(terminal)240 -681 y(con)o(trol)f(sequence)h(in)o(to)f(the)h(prompt.)0 -769 y Fk(\\])192 b Fl(end)16 b(a)f(sequence)h(of)f(non-prin)o(ting)h(c) -o(haracters.)p eop -28 29 bop 0 -58 a Fl(28)1623 b(Bash)15 b(F)l(eatures)p -eop -29 30 bop 0 -58 a Fl(Chapter)15 b(5:)k(Job)d(Con)o(trol)1435 -b(29)0 183 y Fh(5)41 b(Job)15 b(Con)n(trol)62 391 y Fl(This)i(c)o -(hapter)e(disusses)i(what)e(job)h(con)o(trol)g(is,)g(ho)o(w)f(it)h(w)o -(orks,)f(and)h(ho)o(w)f(Bash)h(allo)o(ws)g(y)o(ou)g(to)f(access)h(its)0 -453 y(facilities.)0 715 y Fj(5.1)33 b(Job)14 b(Con)n(trol)i(Basics)62 -856 y Fl(Job)21 b(con)o(trol)e(refers)h(to)g(the)g(abilit)o(y)h(to)e -(selectiv)o(ely)j(stop)e(\(susp)q(end\))h(the)f(execution)h(of)e(pro)q -(cesses)i(and)0 918 y(con)o(tin)o(ue)f(\(resume\))e(their)h(execution)i -(at)d(a)g(later)h(p)q(oin)o(t.)32 b(A)19 b(user)g(t)o(ypically)h(emplo) -o(ys)f(this)h(facilit)o(y)g(via)f(an)0 980 y(in)o(teractiv)o(e)d(in)o -(terface)f(supplied)j(join)o(tly)d(b)o(y)g(the)h(system's)e(terminal)i -(driv)o(er)g(and)f(Bash.)62 1122 y(The)22 b(shell)h(asso)q(ciates)e(a)h -Fg(job)g Fl(with)g(eac)o(h)f(pip)q(elin)q(e.)41 b(It)22 -b(k)o(eeps)g(a)f(table)h(of)f(curren)o(tly)h(executing)h(jobs,)0 -1184 y(whic)o(h)e(ma)o(y)e(b)q(e)i(listed)g(with)g(the)f -Fk(jobs)f Fl(command.)34 b(When)21 b(Bash)f(starts)e(a)i(job)g(async)o -(hronously)g(\(in)h(the)0 1246 y(bac)o(kground\),)14 -b(it)i(prin)o(ts)f(a)g(line)i(that)d(lo)q(oks)i(lik)o(e:)120 -1375 y Fk([1])23 b(25647)62 1516 y Fl(indicating)14 b(that)d(this)h -(job)g(is)g(job)f(n)o(um)o(b)q(er)i(1)e(and)h(that)f(the)h(pro)q(cess)g -(ID)g(of)f(the)h(last)f(pro)q(cess)h(in)h(the)f(pip)q(eline)0 -1578 y(asso)q(ciated)j(with)f(this)h(job)f(is)h(25647.)k(All)c(of)f -(the)h(pro)q(cesses)g(in)g(a)f(single)i(pip)q(eline)h(are)d(mem)o(b)q -(ers)h(of)f(the)g(same)0 1641 y(job.)20 b(Bash)15 b(uses)g(the)h -Fg(job)g Fl(abstraction)e(as)h(the)h(basis)f(for)g(job)g(con)o(trol.)62 -1782 y(T)l(o)i(facilitate)g(the)g(implemen)o(tation)h(of)e(the)h(user)f -(in)o(terface)h(to)f(job)h(con)o(trol,)f(the)h(system)f(main)o(tains)h -(the)0 1844 y(notion)i(of)g(a)g(curren)o(t)g(terminal)h(pro)q(cess)f -(group)g(ID.)g(Mem)o(b)q(ers)g(of)g(this)h(pro)q(cess)f(group)g(\(pro)q -(cesses)g(whose)0 1906 y(pro)q(cess)g(group)g(ID)g(is)g(equal)g(to)g -(the)g(curren)o(t)f(terminal)i(pro)q(cess)f(group)g(ID\))f(receiv)o(e)i -(k)o(eyb)q(oard-generated)0 1968 y(signals)14 b(suc)o(h)f(as)f -Fk(SIGINT)p Fl(.)18 b(These)13 b(pro)q(cesses)g(are)g(said)g(to)f(b)q -(e)i(in)f(the)g(foreground.)19 b(Bac)o(kground)12 b(pro)q(cesses)h(are) -0 2031 y(those)i(whose)f(pro)q(cess)i(group)e(ID)h(di\013ers)h(from)e -(the)h(terminal's;)g(suc)o(h)g(pro)q(cesses)g(are)g(imm)o(une)h(to)e(k) -o(eyb)q(oard-)0 2093 y(generated)19 b(signals.)30 b(Only)20 -b(foreground)e(pro)q(cesses)h(are)f(allo)o(w)o(ed)h(to)f(read)h(from)e -(or)h(write)h(to)f(the)h(terminal.)0 2155 y(Bac)o(kground)i(pro)q -(cesses)h(whic)o(h)h(attempt)e(to)g(read)g(from)g(\(write)g(to\))g(the) -h(terminal)g(are)f(sen)o(t)h(a)f Fk(SIGTTIN)0 2218 y -Fl(\()p Fk(SIGTTOU)p Fl(\))14 b(signal)i(b)o(y)f(the)g(terminal)h(driv) -o(er,)f(whic)o(h,)h(unless)g(caugh)o(t,)f(susp)q(ends)h(the)f(pro)q -(cess.)62 2359 y(If)h(the)g(op)q(erating)g(system)f(on)g(whic)o(h)i -(Bash)e(is)h(running)h(supp)q(orts)f(job)f(con)o(trol,)g(Bash)h(allo)o -(ws)f(y)o(ou)h(to)f(use)0 2421 y(it.)20 b(T)o(yping)15 -b(the)g Fg(susp)q(end)j Fl(c)o(haracter)c(\(t)o(ypically)i(`)p -Fk(^Z)p Fl(',)e(Con)o(trol-Z\))f(while)k(a)d(pro)q(cess)h(is)h(running) -g(causes)f(that)0 2483 y(pro)q(cess)i(to)f(b)q(e)i(stopp)q(ed)f(and)g -(returns)g(y)o(ou)f(to)g(Bash.)25 b(T)o(yping)17 b(the)g -Fg(dela)o(y)o(ed)h(susp)q(end)i Fl(c)o(haracter)c(\(t)o(ypically)0 -2545 y(`)p Fk(^Y)p Fl(',)11 b(Con)o(trol-Y\))h(causes)g(the)h(pro)q -(cess)f(to)g(b)q(e)h(stopp)q(ed)f(when)h(it)g(attempts)e(to)g(read)i -(input)g(from)e(the)i(terminal,)0 2608 y(and)k(con)o(trol)f(to)f(b)q(e) -i(returned)g(to)f(Bash.)23 b(Y)l(ou)16 b(ma)o(y)g(then)h(manipulate)g -(the)g(state)e(of)h(this)h(job,)f(using)h(the)f Fk(bg)0 -2670 y Fl(command)h(to)f(con)o(tin)o(ue)h(it)g(in)h(the)f(bac)o -(kground,)g(the)g Fk(fg)f Fl(command)h(to)f(con)o(tin)o(ue)h(it)g(in)h -(the)f(foreground,)f(or)p eop -30 31 bop 0 -58 a Fl(30)1623 b(Bash)15 b(F)l(eatures)0 -183 y(the)h Fk(kill)f Fl(command)g(to)g(kill)i(it.)k(A)16 -b(`)p Fk(^Z)p Fl(')f(tak)o(es)f(e\013ect)i(immediately)l(,)h(and)f(has) -f(the)h(additional)h(side)f(e\013ect)f(of)0 246 y(causing)h(p)q(ending) -h(output)e(and)g(t)o(yp)q(eahead)h(to)e(b)q(e)i(discarded.)62 -382 y(There)i(are)g(a)f(n)o(um)o(b)q(er)i(of)e(w)o(a)o(ys)g(to)g(refer) -h(to)f(a)g(job)h(in)h(the)e(shell.)30 b(The)18 b(c)o(haracter)f(`)p -Fk(\045)p Fl(')g(in)o(tro)q(duces)i(a)e(job)0 445 y(name.)i(Job)c(n)o -(um)o(b)q(er)f Fk(n)f Fl(ma)o(y)h(b)q(e)g(referred)g(to)f(as)h(`)p -Fk(\045n)p Fl('.)k(A)c(job)g(ma)o(y)f(also)g(b)q(e)i(referred)f(to)f -(using)i(a)e(pre\014x)h(of)g(the)0 507 y(name)j(used)g(to)f(start)g -(it,)h(or)f(using)h(a)g(substring)g(that)f(app)q(ears)g(in)i(its)f -(command)f(line.)27 b(F)l(or)16 b(example,)h(`)p Fk(\045ce)p -Fl(')0 569 y(refers)d(to)g(a)g(stopp)q(ed)h Fk(ce)f Fl(job.)20 -b(Using)15 b(`)p Fk(\045?ce)p Fl(',)e(on)h(the)h(other)f(hand,)h -(refers)f(to)g(an)o(y)g(job)g(con)o(taining)h(the)g(string)0 -632 y(`)p Fk(ce)p Fl(')h(in)j(its)e(command)h(line.)28 -b(If)18 b(the)g(pre\014x)g(or)f(substring)h(matc)o(hes)f(more)g(than)g -(one)h(job,)f(Bash)h(rep)q(orts)f(an)0 694 y(error.)i(The)c(sym)o(b)q -(ols)g(`)p Fk(\045\045)p Fl(')f(and)h(`)p Fk(\045+)p -Fl(')f(refer)h(to)f(the)h(shell's)h(notion)f(of)g(the)g(curren)o(t)g -(job,)f(whic)o(h)i(is)f(the)g(last)g(job)0 756 y(stopp)q(ed)h(while)h -(it)f(w)o(as)f(in)h(the)g(foreground.)k(The)c(previous)g(job)f(ma)o(y)g -(b)q(e)h(referenced)h(using)f(`)p Fk(\045-)p Fl('.)k(In)c(output)0 -818 y(p)q(ertaining)h(to)f(jobs)g(\(e.g.,)f(the)h(output)g(of)f(the)i -Fk(jobs)e Fl(command\),)h(the)g(curren)o(t)g(job)g(is)g(alw)o(a)o(ys)g -(\015agged)g(with)0 881 y(a)f(`)p Fk(+)p Fl(',)f(and)h(the)g(previous)h -(job)f(with)h(a)f(`)p Fk(-)p Fl('.)62 1018 y(Simply)21 -b(naming)f(a)f(job)g(can)h(b)q(e)g(used)g(to)f(bring)h(it)g(in)o(to)f -(the)g(foreground:)28 b(`)p Fk(\0451)p Fl(')19 b(is)h(a)f(synon)o(ym)g -(for)g(`)p Fk(fg)0 1080 y(\0451)p Fl(')14 b(bringing)j(job)e(1)g(from)f -(the)h(bac)o(kground)h(in)o(to)f(the)g(foreground.)k(Similarly)l(,)f(`) -p Fk(\0451)c(&)p Fl(')h(resumes)g(job)g(1)g(in)h(the)0 -1142 y(bac)o(kground,)f(equiv)m(alen)o(t)i(to)d(`)p Fk(bg)h(\0451)p -Fl(')62 1279 y(The)20 b(shell)h(learns)e(immediately)i(whenev)o(er)f(a) -f(job)g(c)o(hanges)g(state.)31 b(Normally)l(,)21 b(Bash)e(w)o(aits)g -(un)o(til)h(it)f(is)0 1341 y(ab)q(out)14 b(to)g(prin)o(t)h(a)f(prompt)g -(b)q(efore)g(rep)q(orting)h(c)o(hanges)f(in)i(a)e(job's)f(status)h(so)g -(as)g(to)g(not)g(in)o(terrupt)g(an)o(y)g(other)0 1404 -y(output.)21 b(If)15 b(the)h(the)g Fk(-b)f Fl(option)g(to)g(the)h -Fk(set)f Fl(builtin)j(is)e(set,)f(Bash)g(rep)q(orts)g(suc)o(h)h(c)o -(hanges)g(immediately)h(\(see)0 1466 y(Section)f(4.5)e([The)h(Set)h -(Builtin],)g(page)f(20\).)k(This)d(feature)f(is)h(also)f(con)o(trolled) -h(b)o(y)f(the)g(v)m(ariable)i Fk(notify)p Fl(.)62 1603 -y(If)j(y)o(ou)g(attempt)f(to)g(exit)h(bash)g(while)i(jobs)e(are)f -(stopp)q(ed,)i(the)f(shell)i(prin)o(ts)e(a)f(message)h(w)o(arning)g(y)o -(ou.)0 1665 y(Y)l(ou)d(ma)o(y)f(then)h(use)g(the)g Fk(jobs)f -Fl(command)g(to)g(insp)q(ect)i(their)f(status.)24 b(If)17 -b(y)o(ou)f(do)h(this,)g(or)f(try)g(to)g(exit)h(again)0 -1727 y(immediately)l(,)g(y)o(ou)e(are)f(not)h(w)o(arned)g(again,)g(and) -g(the)h(stopp)q(ed)f(jobs)g(are)g(terminated.)0 1950 -y Fj(5.2)33 b(Job)14 b(Con)n(trol)i(Builtins)0 2100 y -Fk(bg)360 2162 y(bg)24 b([)p Fg(jobsp)q(ec)s Fk(])240 -2236 y Fl(Place)16 b Fg(jobsp)q(ec)i Fl(in)o(to)d(the)g(bac)o(kground,) -f(as)h(if)g(it)g(had)g(b)q(een)h(started)e(with)i(`)p -Fk(&)p Fl('.)i(If)e Fg(jobsp)q(ec)i Fl(is)d(not)240 2298 -y(supplied,)i(the)e(curren)o(t)h(job)f(is)g(used.)0 2385 -y Fk(fg)360 2447 y(fg)24 b([)p Fg(jobsp)q(ec)s Fk(])240 -2521 y Fl(Bring)f Fg(jobsp)q(ec)j Fl(in)o(to)c(the)h(foreground)f(and)g -(mak)o(e)g(it)h(the)f(curren)o(t)h(job.)41 b(If)23 b -Fg(jobsp)q(ec)i Fl(is)e(not)240 2583 y(supplied,)17 b(the)e(curren)o(t) -h(job)f(is)g(used.)0 2670 y Fk(jobs)p eop -31 32 bop 0 -58 a Fl(Chapter)15 b(5:)k(Job)d(Con)o(trol)1435 -b(31)360 183 y Fk(jobs)23 b([-lpn])g([)p Fg(jobsp)q(ec)s -Fk(])360 233 y(jobs)g(-x)h Fg(command)h Fk([)p Fg(jobsp)q(ec)s -Fk(])240 308 y Fl(The)16 b(\014rst)g(form)f(lists)i(the)f(activ)o(e)g -(jobs.)22 b(The)16 b Fk(-l)g Fl(option)g(lists)g(pro)q(cess)h(IDs)f(in) -g(addition)i(to)d(the)240 370 y(normal)h(information;)f(the)h -Fk(-p)g Fl(option)g(lists)g(only)g(the)g(pro)q(cess)g(ID)g(of)f(the)h -(job's)f(pro)q(cess)h(group)240 432 y(leader.)k(The)14 -b Fk(-n)g Fl(option)g(displa)o(ys)h(only)f(jobs)g(that)f(ha)o(v)o(e)h -(c)o(hanged)g(status)f(since)i(last)f(not\014ed.)20 b(If)240 -495 y Fg(jobsp)q(ec)g Fl(is)d(giv)o(en,)h(output)e(is)h(restricted)g -(to)f(information)h(ab)q(out)g(that)f(job.)24 b(If)17 -b Fg(jobsp)q(ec)j Fl(is)d(not)240 557 y(supplied,)g(the)e(status)g(of)g -(all)h(jobs)f(is)g(listed.)240 632 y(If)e(the)f Fk(-x)g -Fl(option)g(is)h(supplied,)i Fk(jobs)d Fl(replaces)h(an)o(y)f -Fg(jobsp)q(ec)j Fl(found)e(in)g Fg(command)h Fl(or)e -Fg(argumen)o(ts)240 694 y Fl(with)f(the)h(corresp)q(onding)g(pro)q -(cess)f(group)g(ID,)g(and)g(executes)h Fg(command)p Fl(,)f(passing)h -(it)f Fg(argumen)o(t)q Fl(s,)240 756 y(returning)16 b(its)f(exit)h -(status.)0 843 y Fk(suspend)360 906 y(suspend)23 b([-f])240 -980 y Fl(Susp)q(end)c(the)e(execution)i(of)e(this)g(shell)i(un)o(til)g -(it)e(receiv)o(es)i(a)e Fk(SIGCONT)f Fl(signal.)27 b(The)18 -b Fk(-f)f Fl(option)240 1043 y(means)e(to)g(susp)q(end)h(ev)o(en)g(if)f -(the)h(shell)g(is)g(a)f(login)h(shell.)62 1192 y(When)g(job)f(con)o -(trol)g(is)g(activ)o(e,)g(the)h Fk(kill)e Fl(and)i Fk(wait)e -Fl(builtins)k(also)d(accept)g Fg(jobsp)q(ec)k Fl(argumen)o(ts.)0 -1416 y Fj(5.3)33 b(Job)14 b(Con)n(trol)i(V)-6 b(ariables)0 -1553 y Fk(auto_resume)240 1615 y Fl(This)20 b(v)m(ariable)h(con)o -(trols)e(ho)o(w)g(the)h(shell)h(in)o(teracts)e(with)h(the)g(user)f(and) -h(job)f(con)o(trol.)33 b(If)20 b(this)240 1678 y(v)m(ariable)k(exists)e -(then)h(single)g(w)o(ord)f(simple)i(commands)e(without)g(redirects)h -(are)f(treated)f(as)240 1740 y(candidates)f(for)e(resumption)i(of)e(an) -h(existing)h(job.)32 b(There)19 b(is)h(no)f(am)o(biguit)o(y)g(allo)o(w) -o(ed;)i(if)e(y)o(ou)240 1802 y(ha)o(v)o(e)c(more)f(than)h(one)h(job)e -(b)q(eginning)k(with)d(the)g(string)g(that)g(y)o(ou)f(ha)o(v)o(e)h(t)o -(yp)q(ed,)g(then)h(the)f(most)240 1864 y(recen)o(tly)j(accessed)g(job)f -(will)i(b)q(e)e(selected.)28 b(The)17 b(name)g(of)g(a)g(stopp)q(ed)h -(job,)f(in)h(this)g(con)o(text,)e(is)240 1927 y(the)f(command)g(line)h -(used)g(to)e(start)g(it.)20 b(If)15 b(this)g(v)m(ariable)i(is)e(set)g -(to)f(the)h(v)m(alue)h Fk(exact)p Fl(,)e(the)h(string)240 -1989 y(supplied)h(m)o(ust)c(matc)o(h)h(the)g(name)g(of)g(a)g(stopp)q -(ed)h(job)f(exactly;)h(if)f(set)g(to)g Fk(substring)p -Fl(,)f(the)h(string)240 2051 y(supplied)22 b(needs)d(to)g(matc)o(h)g(a) -f(substring)i(of)f(the)g(name)g(of)g(a)g(stopp)q(ed)g(job.)32 -b(The)19 b Fk(substring)240 2114 y Fl(v)m(alue)g(pro)o(vides)g -(functionalit)o(y)g(analogous)f(to)f(the)h Fk(\045?)g -Fl(job)g(id)h(\(see)f(Section)h(5.1)e([Job)h(Con)o(trol)240 -2176 y(Basics],)f(page)g(29\).)25 b(If)17 b(set)g(to)f(an)o(y)h(other)f -(v)m(alue,)j(the)e(supplied)i(string)e(m)o(ust)g(b)q(e)g(a)g(pre\014x)h -(of)e(a)240 2238 y(stopp)q(ed)g(job's)e(name;)h(this)h(pro)o(vides)f -(functionalit)o(y)i(analogous)e(to)f(the)i Fk(\045)f -Fl(job)g(id.)0 2325 y Fk(notify)96 b Fl(Setting)18 b(this)g(v)m -(ariable)g(to)f(a)g(v)m(alue)i(is)f(equiv)m(alen)o(t)h(to)d(`)p -Fk(set)f(-b)p Fl(';)i(unsetting)h(it)g(is)g(equiv)m(alen)o(t)h(to)240 -2387 y(`)p Fk(set)14 b(+b)p Fl(')h(\(see)g(Section)h(4.5)e([The)h(Set)h -(Builtin],)g(page)f(20\).)p eop -32 33 bop 0 -58 a Fl(32)1623 b(Bash)15 b(F)l(eatures)p -eop -33 34 bop 0 -58 a Fl(Chapter)15 b(6:)k(Using)d(History)f(In)o(teractiv) -o(ely)1135 b(33)0 183 y Fh(6)41 b(Using)14 b(History)h(In)n(teractiv)n -(ely)62 355 y Fl(This)i(c)o(hapter)e(describ)q(es)j(ho)o(w)d(to)h(use)g -(the)g(GNU)g(History)f(Library)i(in)o(teractiv)o(ely)l(,)g(from)e(a)g -(user's)h(stand-)0 417 y(p)q(oin)o(t.)23 b(It)16 b(should)h(b)q(e)f -(considered)i(a)d(user's)h(guide.)23 b(F)l(or)15 b(information)h(on)g -(using)h(the)f(GNU)g(History)f(Library)0 479 y(in)h(y)o(our)f(o)o(wn)f -(programs,)g(see)i(the)f(GNU)g(Readline)i(Library)f(Man)o(ual.)0 -688 y Fj(6.1)33 b(History)15 b(In)n(teraction)62 825 -y Fl(The)j(History)g(library)g(pro)o(vides)h(a)e(history)h(expansion)h -(feature)e(that)g(is)i(similar)g(to)e(the)h(history)f(expan-)0 -887 y(sion)k(pro)o(vided)h(b)o(y)f Fk(csh)p Fl(.)36 b(The)22 -b(follo)o(wing)f(text)g(describ)q(es)h(the)f(syn)o(tax)f(used)i(to)e -(manipulate)i(the)f(history)0 949 y(information.)62 1086 -y(History)11 b(expansion)i(tak)o(es)d(place)i(in)h(t)o(w)o(o)d(parts.) -18 b(The)11 b(\014rst)g(is)h(to)f(determine)h(whic)o(h)g(line)h(from)e -(the)g(previous)0 1148 y(history)h(should)h(b)q(e)f(used)h(during)f -(substitution.)20 b(The)12 b(second)g(is)h(to)e(select)h(p)q(ortions)g -(of)g(that)f(line)i(for)f(inclusion)0 1211 y(in)o(to)f(the)h(curren)o -(t)f(one.)18 b(The)12 b(line)h(selected)f(from)f(the)g(previous)h -(history)g(is)f(called)i(the)e Fg(ev)o(en)o(t)p Fl(,)h(and)f(the)h(p)q -(ortions)0 1273 y(of)h(that)g(line)i(that)e(are)g(acted)g(up)q(on)h -(are)g(called)h Fg(w)o(ords)p Fl(.)j(The)c(line)h(is)f(brok)o(en)f(in)o -(to)h(w)o(ords)f(in)h(the)f(same)h(fashion)0 1335 y(that)j(Bash)h(do)q -(es,)h(so)e(that)g(sev)o(eral)h(English)i(\(or)d(Unix\))h(w)o(ords)f -(surrounded)i(b)o(y)f(quotes)f(are)h(considered)h(as)0 -1398 y(one)c(w)o(ord.)0 1590 y Ff(6.1.1)30 b(Ev)n(en)n(t)16 -b(Designators)62 1727 y Fl(An)g(ev)o(en)o(t)f(designator)g(is)g(a)g -(reference)h(to)f(a)g(command)g(line)i(en)o(try)d(in)i(the)g(history)f -(list.)0 1872 y Fk(!)216 b Fl(Start)14 b(a)g(history)h(substitution,)g -(except)h(when)f(follo)o(w)o(ed)g(b)o(y)g(a)f(space,)h(tab,)f(the)h -(end)g(of)g(the)g(line,)240 1934 y Fk(=)g Fl(or)g Fk(\()p -Fl(.)0 2014 y Fk(!!)192 b Fl(Refer)16 b(to)e(the)i(previous)f(command.) -20 b(This)c(is)g(a)f(synon)o(ym)g(for)f Fk(!-1)p Fl(.)0 -2093 y Fk(!n)192 b Fl(Refer)16 b(to)e(command)h(line)i -Fg(n)p Fl(.)0 2173 y Fk(!-n)168 b Fl(Refer)16 b(to)e(the)i(command)f -Fg(n)g Fl(lines)i(bac)o(k.)0 2252 y Fk(!string)72 b Fl(Refer)16 -b(to)e(the)i(most)e(recen)o(t)h(command)g(starting)g(with)g -Fg(string)p Fl(.)0 2323 y Fk(!?string)p Fl([)p Fk(?)p -Fl(])240 2385 y(Refer)h(to)e(the)i(most)e(recen)o(t)h(command)g(con)o -(taining)h Fg(string)p Fl(.)0 2465 y Fk(!#)192 b Fl(The)15 -b(en)o(tire)h(command)f(line)i(t)o(yp)q(ed)f(so)e(far.)0 -2535 y Fk(^string1^string2^)240 2598 y Fl(Quic)o(k)j(Substitution.)22 -b(Rep)q(eat)16 b(the)g(last)f(command,)h(replacing)h -Fg(string1)h Fl(with)e Fg(string2)p Fl(.)21 b(Equiv-)240 -2660 y(alen)o(t)15 b(to)g Fk(!!:s/string1/string2/)p -Fl(.)p eop -34 35 bop 0 -58 a Fl(34)1623 b(Bash)15 b(F)l(eatures)0 -183 y Ff(6.1.2)30 b(W)-5 b(ord)15 b(Designators)62 320 -y Fl(A)i Fk(:)g Fl(separates)f(the)h(ev)o(en)o(t)f(sp)q(eci\014cation)j -(from)d(the)g(w)o(ord)g(designator.)25 b(It)17 b(can)g(b)q(e)g(omitted) -g(if)g(the)g(w)o(ord)0 382 y(designator)d(b)q(egins)h(with)f(a)f -Fk(^)p Fl(,)h Fk($)p Fl(,)f Fk(*)h Fl(or)f Fk(\045)p -Fl(.)20 b(W)l(ords)13 b(are)h(n)o(um)o(b)q(ered)g(from)f(the)h(b)q -(eginning)i(of)d(the)h(line,)i(with)e(the)0 445 y(\014rst)h(w)o(ord)f -(b)q(eing)j(denoted)f(b)o(y)f(a)g(0)f(\(zero\).)0 593 -y Fk(0)h(\(zero\))57 b Fl(The)15 b Fk(0)p Fl(th)g(w)o(ord.)20 -b(F)l(or)14 b(man)o(y)h(applications,)h(this)g(is)g(the)f(command)g(w)o -(ord.)0 679 y Fk(n)216 b Fl(The)15 b Fg(n)p Fl(th)h(w)o(ord.)0 -765 y Fk(^)216 b Fl(The)15 b(\014rst)g(argumen)o(t;)f(that)h(is,)g(w)o -(ord)g(1.)0 851 y Fk($)216 b Fl(The)15 b(last)h(argumen)o(t.)0 -937 y Fk(\045)216 b Fl(The)15 b(w)o(ord)g(matc)o(hed)g(b)o(y)g(the)g -(most)g(recen)o(t)g Fk(?string?)f Fl(searc)o(h.)0 1022 -y Fk(x-y)168 b Fl(A)15 b(range)g(of)g(w)o(ords;)f Fk(-)p -Fg(y)19 b Fl(abbreviates)c Fk(0-)p Fg(y)t Fl(.)0 1108 -y Fk(*)216 b Fl(All)17 b(of)f(the)g(w)o(ords,)f(except)i(the)f -Fk(0)p Fl(th.)22 b(This)17 b(is)f(a)g(synon)o(ym)g(for)f -Fk(1-$)p Fl(.)22 b(It)17 b(is)f(not)g(an)g(error)f(to)h(use)240 -1170 y Fk(*)f Fl(if)h(there)f(is)h(just)f(one)g(w)o(ord)f(in)i(the)g -(ev)o(en)o(t;)e(the)i(empt)o(y)e(string)i(is)f(returned)h(in)g(that)e -(case.)0 1256 y Fk(x*)192 b Fl(Abbreviates)16 b Fk(x-$)0 -1342 y(x-)192 b Fl(Abbreviates)16 b Fk(x-$)f Fl(lik)o(e)h -Fk(x*)p Fl(,)e(but)i(omits)f(the)g(last)g(w)o(ord.)0 -1547 y Ff(6.1.3)30 b(Mo)r(di\014ers)62 1684 y Fl(After)20 -b(the)f(optional)i(w)o(ord)e(designator,)h(y)o(ou)f(can)h(add)g(a)g -(sequence)h(of)e(one)h(or)f(more)g(of)g(the)h(follo)o(wing)0 -1746 y(mo)q(di\014ers,)c(eac)o(h)f(preceded)i(b)o(y)e(a)g -Fk(:)p Fl(.)0 1895 y Fk(h)216 b Fl(Remo)o(v)o(e)15 b(a)g(trailing)h -(pathname)f(comp)q(onen)o(t,)g(lea)o(ving)h(only)g(the)f(head.)0 -1980 y Fk(r)216 b Fl(Remo)o(v)o(e)15 b(a)g(trailing)h(su\016x)f(of)g -(the)g(form)g(`)p Fk(.)p Fl(')p Fg(su\016x)p Fl(,)f(lea)o(ving)i(the)f -(basename.)0 2066 y Fk(e)216 b Fl(Remo)o(v)o(e)15 b(all)h(but)g(the)f -(trailing)h(su\016x.)0 2152 y Fk(t)216 b Fl(Remo)o(v)o(e)15 -b(all)h(leading)h(pathname)e(comp)q(onen)o(ts,)g(lea)o(ving)h(the)f -(tail.)0 2238 y Fk(p)216 b Fl(Prin)o(t)15 b(the)g(new)h(command)f(but)g -(do)g(not)g(execute)h(it.)0 2323 y Fk(q)216 b Fl(Quote)15 -b(the)h(substituted)g(w)o(ords,)e(escaping)i(further)f(substitutions.)0 -2409 y Fk(x)216 b Fl(Quote)22 b(the)f(substituted)h(w)o(ords)f(as)g -(with)h Fk(q)p Fl(,)h(but)e(break)h(in)o(to)f(w)o(ords)g(at)g(spaces,)i -(tabs,)f(and)240 2471 y(newlines.)0 2545 y Fk(s/old/new/)240 -2608 y Fl(Substitute)16 b Fg(new)k Fl(for)15 b(the)h(\014rst)f(o)q -(ccurrence)h(of)g Fg(old)h Fl(in)g(the)e(ev)o(en)o(t)h(line.)22 -b(An)o(y)16 b(delimiter)h(ma)o(y)e(b)q(e)240 2670 y(used)e(in)f(place)h -(of)f Fk(/)p Fl(.)19 b(The)12 b(delimiter)i(ma)o(y)d(b)q(e)i(quoted)f -(in)h Fg(old)h Fl(and)e Fg(new)17 b Fl(with)12 b(a)g(single)h(bac)o -(kslash.)p eop -35 36 bop 0 -58 a Fl(Chapter)15 b(6:)k(Using)d(History)f(In)o(teractiv) -o(ely)1135 b(35)240 183 y(If)13 b Fk(&)h Fl(app)q(ears)f(in)h -Fg(new)p Fl(,)f(it)h(is)g(replaced)g(b)o(y)f Fg(old)p -Fl(.)20 b(A)13 b(single)i(bac)o(kslash)e(will)i(quote)e(the)h -Fk(&)p Fl(.)19 b(The)13 b(\014nal)240 246 y(delimiter)k(is)f(optional)g -(if)f(it)h(is)f(the)h(last)f(c)o(haracter)f(on)h(the)h(input)g(line.)0 -333 y Fk(&)216 b Fl(Rep)q(eat)16 b(the)f(previous)h(substitution.)0 -420 y Fk(g)216 b Fl(Cause)15 b(c)o(hanges)g(to)f(b)q(e)i(applied)h(o)o -(v)o(er)d(the)h(en)o(tire)g(ev)o(en)o(t)g(line.)21 b(Used)16 -b(in)g(conjunction)g(with)f Fk(s)p Fl(,)f(as)240 482 -y(in)i Fk(gs/old/new/)p Fl(,)d(or)i(with)h Fk(&)p Fl(.)p -eop -36 37 bop 0 -58 a Fl(36)1623 b(Bash)15 b(F)l(eatures)p -eop -37 38 bop 0 -58 a Fl(Chapter)15 b(7:)k(Command)c(Line)i(Editing)1205 -b(37)0 183 y Fh(7)41 b(Command)16 b(Line)f(Editing)62 -408 y Fl(This)h(c)o(hapter)f(describ)q(es)i(the)e(basic)h(features)f -(of)g(the)g(GNU)g(command)g(line)i(editing)f(in)o(terface.)0 -701 y Fj(7.1)33 b(In)n(tro)r(duction)17 b(to)e(Line)h(Editing)62 -845 y Fl(The)g(follo)o(wing)g(paragraphs)e(describ)q(e)j(the)e -(notation)g(used)h(to)e(represen)o(t)i(k)o(eystrok)o(es.)62 -990 y(The)f(text)e Fk(C-K)h Fl(is)g(read)g(as)g(`Con)o(trol-K')f(and)h -(describ)q(es)i(the)e(c)o(haracter)f(pro)q(duced)i(when)g(the)f(Con)o -(trol)f(k)o(ey)0 1052 y(is)j(depressed)g(and)f(the)h -Fk(K)f Fl(k)o(ey)g(is)g(struc)o(k.)62 1197 y(The)i(text)f -Fk(M-K)g Fl(is)i(read)e(as)g(`Meta-K')g(and)h(describ)q(es)h(the)f(c)o -(haracter)f(pro)q(duced)h(when)h(the)e(meta)g(k)o(ey)h(\(if)0 -1259 y(y)o(ou)g(ha)o(v)o(e)f(one\))h(is)g(depressed,)h(and)f(the)g -Fk(K)g Fl(k)o(ey)g(is)g(struc)o(k.)25 b(If)17 b(y)o(ou)f(do)h(not)g(ha) -o(v)o(e)f(a)h(meta)f(k)o(ey)l(,)h(the)g(iden)o(tical)0 -1321 y(k)o(eystrok)o(e)i(can)g(b)q(e)i(generated)e(b)o(y)h(t)o(yping)f -Fk(ESC)h Fg(\014rst)p Fl(,)g(and)f(then)h(t)o(yping)g -Fk(K)p Fl(.)33 b(Either)20 b(pro)q(cess)g(is)g(kno)o(wn)f(as)0 -1383 y Fg(metafying)g Fl(the)c Fk(K)g Fl(k)o(ey)l(.)62 -1528 y(The)h(text)e Fk(M-C-K)g Fl(is)i(read)f(as)f(`Meta-Con)o(trol-k') -g(and)h(describ)q(es)h(the)g(c)o(haracter)e(pro)q(duced)i(b)o(y)f -Fg(metafying)0 1590 y Fk(C-K)p Fl(.)62 1735 y(In)i(addition,)h(sev)o -(eral)e(k)o(eys)g(ha)o(v)o(e)g(their)h(o)o(wn)f(names.)23 -b(Sp)q(eci\014cally)m(,)c Fk(DEL)p Fl(,)d Fk(ESC)p Fl(,)f -Fk(LFD)p Fl(,)h Fk(SPC)p Fl(,)g Fk(RET)p Fl(,)g(and)g -Fk(TAB)0 1797 y Fl(all)e(stand)f(for)f(themselv)o(es)i(when)f(seen)h -(in)g(this)f(text,)g(or)g(in)g(an)g(init)i(\014le)f(\(see)f(Section)h -(7.3)e([Readline)j(Init)f(File],)0 1859 y(page)h(40,)f(for)h(more)g -(info\).)0 2152 y Fj(7.2)33 b(Readline)16 b(In)n(teraction)62 -2296 y Fl(Often)g(during)h(an)f(in)o(teractiv)o(e)g(session)h(y)o(ou)e -(t)o(yp)q(e)h(in)h(a)f(long)g(line)h(of)f(text,)f(only)h(to)g(notice)g -(that)f(the)h(\014rst)0 2359 y(w)o(ord)d(on)i(the)f(line)i(is)e(missp)q -(elled.)23 b(The)14 b(Readline)i(library)f(giv)o(es)g(y)o(ou)e(a)h(set) -g(of)g(commands)g(for)f(manipulating)0 2421 y(the)18 -b(text)g(as)g(y)o(ou)g(t)o(yp)q(e)g(it)h(in,)g(allo)o(wing)g(y)o(ou)f -(to)g(just)g(\014x)g(y)o(our)g(t)o(yp)q(o,)g(and)h(not)f(forcing)g(y)o -(ou)g(to)g(ret)o(yp)q(e)g(the)0 2483 y(ma)s(jorit)o(y)d(of)h(the)g -(line.)25 b(Using)17 b(these)g(editing)h(commands,)e(y)o(ou)g(mo)o(v)o -(e)f(the)i(cursor)f(to)g(the)g(place)h(that)f(needs)0 -2545 y(correction,)g(and)h(delete)g(or)f(insert)g(the)h(text)e(of)h -(the)g(corrections.)23 b(Then,)17 b(when)g(y)o(ou)f(are)g(satis\014ed)g -(with)h(the)0 2608 y(line,)h(y)o(ou)e(simply)i(press)f -Fk(RETURN)p Fl(.)23 b(Y)l(ou)17 b(do)f(not)g(ha)o(v)o(e)g(to)g(b)q(e)i -(at)e(the)g(end)h(of)f(the)h(line)h(to)e(press)h Fk(RETURN)p -Fl(;)f(the)0 2670 y(en)o(tire)g(line)h(is)e(accepted)h(regardless)f(of) -g(the)g(lo)q(cation)h(of)f(the)h(cursor)e(within)j(the)e(line.)p -eop -38 39 bop 0 -58 a Fl(38)1623 b(Bash)15 b(F)l(eatures)0 -183 y Ff(7.2.1)30 b(Readline)15 b(Bare)g(Essen)n(tials)62 -320 y Fl(In)f(order)f(to)f(en)o(ter)h(c)o(haracters)g(in)o(to)g(the)g -(line,)i(simply)f(t)o(yp)q(e)f(them.)19 b(The)14 b(t)o(yp)q(ed)f(c)o -(haracter)f(app)q(ears)i(where)0 383 y(the)h(cursor)h(w)o(as,)e(and)h -(then)h(the)g(cursor)f(mo)o(v)o(es)f(one)i(space)g(to)e(the)i(righ)o -(t.)k(If)c(y)o(ou)f(mist)o(yp)q(e)h(a)f(c)o(haracter,)f(y)o(ou)0 -445 y(can)h(use)h(y)o(our)f(erase)g(c)o(haracter)f(to)h(bac)o(k)g(up)g -(and)h(delete)g(the)f(mist)o(yp)q(ed)h(c)o(haracter.)62 -582 y(Sometimes)f(y)o(ou)e(ma)o(y)h(miss)g(t)o(yping)g(a)g(c)o -(haracter)g(that)f(y)o(ou)h(w)o(an)o(ted)f(to)g(t)o(yp)q(e,)h(and)h -(not)e(notice)i(y)o(our)f(error)0 644 y(un)o(til)k(y)o(ou)e(ha)o(v)o(e) -g(t)o(yp)q(ed)h(sev)o(eral)g(other)f(c)o(haracters.)23 -b(In)18 b(that)d(case,)i(y)o(ou)f(can)h(t)o(yp)q(e)g -Fk(C-B)f Fl(to)g(mo)o(v)o(e)g(the)g(cursor)0 706 y(to)f(the)h(left,)g -(and)g(then)g(correct)f(y)o(our)h(mistak)o(e.)21 b(Afterw)o(ards,)14 -b(y)o(ou)i(can)g(mo)o(v)o(e)f(the)h(cursor)f(to)g(the)h(righ)o(t)g -(with)0 769 y Fk(C-F)p Fl(.)62 906 y(When)i(y)o(ou)f(add)g(text)g(in)h -(the)f(middle)i(of)e(a)g(line,)i(y)o(ou)e(will)i(notice)e(that)g(c)o -(haracters)f(to)h(the)g(righ)o(t)g(of)g(the)0 968 y(cursor)h(are)h -(`pushed)g(o)o(v)o(er')e(to)h(mak)o(e)g(ro)q(om)g(for)g(the)h(text)f -(that)g(y)o(ou)g(ha)o(v)o(e)h(inserted.)31 b(Lik)o(ewise,)20 -b(when)f(y)o(ou)0 1030 y(delete)f(text)f(b)q(ehind)i(the)f(cursor,)f(c) -o(haracters)f(to)h(the)g(righ)o(t)g(of)g(the)h(cursor)f(are)g(`pulled)i -(bac)o(k')d(to)h(\014ll)i(in)f(the)0 1092 y(blank)g(space)f(created)g -(b)o(y)g(the)h(remo)o(v)m(al)f(of)f(the)i(text.)25 b(A)17 -b(list)h(of)e(the)h(basic)h(bare)f(essen)o(tials)h(for)e(editing)j(the) -0 1155 y(text)c(of)f(an)i(input)g(line)h(follo)o(ws.)0 -1304 y Fk(C-B)168 b Fl(Mo)o(v)o(e)14 b(bac)o(k)h(one)h(c)o(haracter.)0 -1391 y Fk(C-F)168 b Fl(Mo)o(v)o(e)14 b(forw)o(ard)g(one)h(c)o -(haracter.)0 1478 y Fk(DEL)168 b Fl(Delete)16 b(the)f(c)o(haracter)g -(to)f(the)h(left)h(of)f(the)g(cursor.)0 1566 y Fk(C-D)168 -b Fl(Delete)16 b(the)f(c)o(haracter)g(underneath)h(the)f(cursor.)0 -1640 y(Prin)o(ting)h(c)o(haracters)240 1703 y(Insert)f(the)h(c)o -(haracter)e(in)o(to)h(the)h(line)h(at)d(the)h(cursor.)0 -1790 y Fk(C-_)168 b Fl(Undo)15 b(the)h(last)f(thing)h(that)e(y)o(ou)h -(did.)21 b(Y)l(ou)15 b(can)h(undo)f(all)h(the)g(w)o(a)o(y)e(bac)o(k)h -(to)f(an)i(empt)o(y)e(line.)0 1997 y Ff(7.2.2)30 b(Readline)15 -b(Mo)n(v)n(emen)n(t)h(Commands)62 2134 y Fl(The)c(ab)q(o)o(v)o(e)g -(table)g(describ)q(es)i(the)e(most)f(basic)h(p)q(ossible)i(k)o(eystrok) -o(es)d(that)g(y)o(ou)g(need)i(in)g(order)f(to)f(do)h(editing)0 -2197 y(of)g(the)h(input)h(line.)21 b(F)l(or)12 b(y)o(our)g(con)o(v)o -(enience,)i(man)o(y)f(other)f(commands)h(ha)o(v)o(e)f(b)q(een)i(added)f -(in)h(addition)g(to)e Fk(C-B)p Fl(,)0 2259 y Fk(C-F)p -Fl(,)i Fk(C-D)p Fl(,)h(and)g Fk(DEL)p Fl(.)20 b(Here)15 -b(are)g(some)g(commands)g(for)f(mo)o(ving)h(more)g(rapidly)i(ab)q(out)e -(the)g(line.)0 2408 y Fk(C-A)168 b Fl(Mo)o(v)o(e)14 b(to)h(the)g(start) -f(of)h(the)g(line.)0 2496 y Fk(C-E)168 b Fl(Mo)o(v)o(e)14 -b(to)h(the)g(end)h(of)f(the)g(line.)0 2583 y Fk(M-F)168 -b Fl(Mo)o(v)o(e)14 b(forw)o(ard)g(a)h(w)o(ord.)0 2670 -y Fk(M-B)168 b Fl(Mo)o(v)o(e)14 b(bac)o(kw)o(ard)h(a)g(w)o(ord.)p -eop -39 40 bop 0 -58 a Fl(Chapter)15 b(7:)k(Command)c(Line)i(Editing)1205 -b(39)0 183 y Fk(C-L)168 b Fl(Clear)15 b(the)h(screen,)f(reprin)o(ting)h -(the)f(curren)o(t)g(line)i(at)e(the)g(top.)62 350 y(Notice)22 -b(ho)o(w)e Fk(C-F)h Fl(mo)o(v)o(es)f(forw)o(ard)g(a)g(c)o(haracter,)i -(while)g Fk(M-F)f Fl(mo)o(v)o(es)f(forw)o(ard)g(a)h(w)o(ord.)36 -b(It)21 b(is)h(a)f(lo)q(ose)0 412 y(con)o(v)o(en)o(tion)15 -b(that)g(con)o(trol)g(k)o(eystrok)o(es)f(op)q(erate)h(on)g(c)o -(haracters)f(while)j(meta)e(k)o(eystrok)o(es)f(op)q(erate)h(on)g(w)o -(ords.)0 696 y Ff(7.2.3)30 b(Readline)15 b(Killing)g(Commands)62 -841 y Fg(Killing)25 b Fl(text)18 b(means)g(to)f(delete)i(the)g(text)e -(from)h(the)g(line,)i(but)e(to)g(sa)o(v)o(e)f(it)i(a)o(w)o(a)o(y)d(for) -i(later)g(use,)h(usually)0 903 y(b)o(y)c Fg(y)o(anking)k -Fl(\(re-inserting\))c(it)g(bac)o(k)g(in)o(to)g(the)g(line.)21 -b(If)16 b(the)f(description)h(for)e(a)h(command)f(sa)o(ys)h(that)f(it)h -(`kills')0 966 y(text,)f(then)i(y)o(ou)f(can)g(b)q(e)h(sure)f(that)g(y) -o(ou)g(can)g(get)g(the)g(text)g(bac)o(k)g(in)h(a)f(di\013eren)o(t)g -(\(or)f(the)i(same\))e(place)i(later.)62 1111 y(When)g(y)o(ou)f(use)g -(a)g(kill)i(command,)e(the)h(text)e(is)i(sa)o(v)o(ed)f(in)h(a)f -Fg(kill-ring)p Fl(.)22 b(An)o(y)16 b(n)o(um)o(b)q(er)f(of)g(consecutiv) -o(e)h(kills)0 1173 y(sa)o(v)o(e)g(all)i(of)e(the)h(killed)i(text)d -(together,)g(so)g(that)g(when)h(y)o(ou)f(y)o(ank)h(it)g(bac)o(k,)f(y)o -(ou)h(get)f(it)h(all.)25 b(The)17 b(kill)h(ring)f(is)0 -1236 y(not)e(line)i(sp)q(eci\014c;)g(the)f(text)f(that)g(y)o(ou)g -(killed)j(on)d(a)h(previously)g(t)o(yp)q(ed)g(line)h(is)f(a)o(v)m -(ailable)i(to)d(b)q(e)h(y)o(ank)o(ed)f(bac)o(k)0 1298 -y(later,)g(when)h(y)o(ou)e(are)h(t)o(yping)h(another)e(line.)62 -1443 y(Here)i(is)f(the)h(list)g(of)e(commands)h(for)g(killing)j(text.)0 -1610 y Fk(C-K)168 b Fl(Kill)17 b(the)f(text)e(from)h(the)g(curren)o(t)g -(cursor)g(p)q(osition)h(to)f(the)g(end)h(of)f(the)g(line.)0 -1714 y Fk(M-D)168 b Fl(Kill)17 b(from)d(the)h(cursor)g(to)f(the)h(end)g -(of)g(the)g(curren)o(t)f(w)o(ord,)g(or)g(if)i(b)q(et)o(w)o(een)f(w)o -(ords,)f(to)g(the)h(end)g(of)240 1776 y(the)g(next)h(w)o(ord.)0 -1880 y Fk(M-DEL)120 b Fl(Kill)16 b(from)d(the)i(cursor)e(the)h(start)f -(of)h(the)g(previous)h(w)o(ord,)e(or)g(if)i(b)q(et)o(w)o(een)f(w)o -(ords,)f(to)h(the)g(start)e(of)240 1942 y(the)j(previous)h(w)o(ord.)0 -2046 y Fk(C-W)168 b Fl(Kill)18 b(from)e(the)g(cursor)g(to)f(the)h -(previous)h(whitespace.)24 b(This)17 b(is)f(di\013eren)o(t)h(than)f -Fk(M-DEL)f Fl(b)q(ecause)240 2109 y(the)g(w)o(ord)g(b)q(oundaries)h -(di\013er.)62 2275 y(And,)e(here)g(is)h(ho)o(w)e(to)g -Fg(y)o(ank)j Fl(the)e(text)f(bac)o(k)g(in)o(to)h(the)f(line.)22 -b(Y)l(anking)14 b(means)g(to)f(cop)o(y)g(the)h(most-recen)o(tly-)0 -2337 y(killed)j(text)e(from)g(the)g(kill)i(bu\013er.)0 -2504 y Fk(C-Y)168 b Fl(Y)l(ank)15 b(the)h(most)e(recen)o(tly)i(killed)h -(text)e(bac)o(k)g(in)o(to)g(the)h(bu\013er)f(at)f(the)i(cursor.)0 -2608 y Fk(M-Y)168 b Fl(Rotate)13 b(the)h(kill-ring,)i(and)e(y)o(ank)g -(the)g(new)g(top.)19 b(Y)l(ou)14 b(can)g(only)g(do)g(this)g(if)g(the)g -(prior)g(command)240 2670 y(is)i Fk(C-Y)e Fl(or)h Fk(M-Y)p -Fl(.)p eop -40 41 bop 0 -58 a Fl(40)1623 b(Bash)15 b(F)l(eatures)0 -183 y Ff(7.2.4)30 b(Readline)15 b(Argumen)n(ts)62 330 -y Fl(Y)l(ou)k(can)g(pass)f(n)o(umeric)i(argumen)o(ts)d(to)h(Readline)j -(commands.)30 b(Sometimes)19 b(the)f(argumen)o(t)g(acts)g(as)g(a)0 -392 y(rep)q(eat)f(coun)o(t,)f(other)g(times)g(it)h(is)g(the)g -Fg(sign)f Fl(of)g(the)h(argumen)o(t)f(that)f(is)i(signi\014can)o(t.)25 -b(If)16 b(y)o(ou)h(pass)f(a)g(negativ)o(e)0 455 y(argumen)o(t)g(to)g(a) -h(command)g(whic)o(h)h(normally)f(acts)g(in)h(a)e(forw)o(ard)g -(direction,)i(that)f(command)f(will)j(act)d(in)i(a)0 -517 y(bac)o(kw)o(ard)13 b(direction.)21 b(F)l(or)13 b(example,)h(to)f -(kill)i(text)e(bac)o(k)h(to)f(the)h(start)e(of)h(the)h(line,)h(y)o(ou)e -(migh)o(t)h(t)o(yp)q(e)g Fk(M--)f(C-K)p Fl(.)62 664 y(The)19 -b(general)g(w)o(a)o(y)f(to)g(pass)g(n)o(umeric)i(argumen)o(ts)e(to)g(a) -g(command)h(is)g(to)f(t)o(yp)q(e)g(meta)g(digits)i(b)q(efore)f(the)0 -726 y(command.)36 b(If)21 b(the)g(\014rst)f(`digit')h(y)o(ou)g(t)o(yp)q -(e)f(is)i(a)e(min)o(us)h(sign)g(\()p Fk(-)p Fl(\),)g(then)g(the)g(sign) -g(of)g(the)f(argumen)o(t)g(will)0 788 y(b)q(e)i(negativ)o(e.)40 -b(Once)22 b(y)o(ou)f(ha)o(v)o(e)h(t)o(yp)q(ed)g(one)f(meta)g(digit)i -(to)e(get)g(the)h(argumen)o(t)f(started,)h(y)o(ou)f(can)h(t)o(yp)q(e)0 -851 y(the)c(remainder)h(of)f(the)g(digits,)h(and)f(then)h(the)f -(command.)29 b(F)l(or)17 b(example,)i(to)f(giv)o(e)g(the)g -Fk(C-D)g Fl(command)g(an)0 913 y(argumen)o(t)c(of)h(10,)f(y)o(ou)h -(could)h(t)o(yp)q(e)g Fk(M-1)23 b(0)h(C-D)p Fl(.)0 1226 -y Fj(7.3)33 b(Readline)16 b(Init)g(File)62 1373 y Fl(Although)g(the)g -(Readline)h(library)g(comes)e(with)h(a)f(set)g(of)g(Emacs-lik)o(e)h(k)o -(eybindings)h(installed)g(b)o(y)f(default,)0 1435 y(it)e(is)g(p)q -(ossible)i(that)d(y)o(ou)g(w)o(ould)h(lik)o(e)h(to)e(use)h(a)f -(di\013eren)o(t)h(set)g(of)f(k)o(eybindings.)21 b(Y)l(ou)14 -b(can)g(customize)g(programs)0 1497 y(that)i(use)i(Readline)h(b)o(y)e -(putting)h(commands)f(in)h(an)f Fg(init)i Fl(\014le)f(in)g(y)o(our)f -(home)g(directory)l(.)26 b(The)18 b(name)f(of)g(this)0 -1559 y(\014le)h(is)g(tak)o(en)f(from)g(the)g(v)m(alue)i(of)e(the)g -(shell)i(v)m(ariable)g Fk(INPUTRC)p Fl(.)25 b(If)18 b(that)f(v)m -(ariable)h(is)g(unset,)g(the)f(default)h(is)0 1622 y(`)p -Fk(~/.inputrc)p Fl('.)62 1769 y(When)h(a)g(program)e(whic)o(h)j(uses)f -(the)g(Readline)i(library)e(starts)f(up,)h(the)g(init)h(\014le)g(is)f -(read,)g(and)g(the)g(k)o(ey)0 1831 y(bindings)e(are)e(set.)62 -1978 y(In)j(addition,)h(the)f Fk(C-x)c(C-r)k Fl(command)f(re-reads)g -(this)h(init)h(\014le,)g(th)o(us)e(incorp)q(orating)h(an)o(y)f(c)o -(hanges)h(that)0 2040 y(y)o(ou)d(migh)o(t)g(ha)o(v)o(e)g(made)g(to)f -(it.)0 2336 y Ff(7.3.1)30 b(Readline)15 b(Init)g(Syn)n(tax)62 -2483 y Fl(There)h(are)f(only)h(a)f(few)g(basic)h(constructs)f(allo)o(w) -o(ed)h(in)g(the)g(Readline)i(init)e(\014le.)22 b(Blank)16 -b(lines)h(are)e(ignored.)0 2545 y(Lines)j(b)q(eginning)g(with)f(a)f -Fk(#)g Fl(are)g(commen)o(ts.)22 b(Lines)c(b)q(eginning)g(with)f(a)f -Fk($)g Fl(indicate)h(conditional)h(constructs)0 2608 -y(\(see)d(Section)g(7.3.2)e([Conditional)j(Init)f(Constructs],)f(page)g -(43\).)19 b(Other)c(lines)h(denote)f(v)m(ariable)h(settings)f(and)0 -2670 y(k)o(ey)g(bindings.)p eop -41 42 bop 0 -58 a Fl(Chapter)15 b(7:)k(Command)c(Line)i(Editing)1205 -b(41)0 183 y(V)l(ariable)16 b(Settings)240 246 y(Y)l(ou)j(can)g(c)o -(hange)g(the)g(state)f(of)g(a)g(few)h(v)m(ariables)h(in)g(Readline)h(b) -o(y)d(using)i(the)f Fk(set)f Fl(command)240 308 y(within)e(the)f(init)h -(\014le.)k(Here)15 b(is)g(ho)o(w)g(y)o(ou)f(w)o(ould)h(sp)q(ecify)h -(that)e(y)o(ou)g(wish)i(to)e(use)h Fk(vi)f Fl(line)j(editing)240 -370 y(commands:)360 433 y Fk(set)23 b(editing-mode)g(vi)240 -509 y Fl(Righ)o(t)14 b(no)o(w,)f(there)h(are)f(only)h(a)f(few)h(v)m -(ariables)g(whic)o(h)h(can)f(b)q(e)g(set;)f(so)g(few,)h(in)g(fact,)f -(that)g(w)o(e)g(just)240 571 y(list)j(them)f(here:)240 -647 y Fk(editing-mode)480 709 y Fl(The)e Fk(editing-mode)e -Fl(v)m(ariable)j(con)o(trols)e(whic)o(h)h(editing)h(mo)q(de)f(y)o(ou)f -(are)g(using.)20 b(By)480 771 y(default,)f(Readline)h(starts)c(up)i(in) -h(Emacs)e(editing)i(mo)q(de,)f(where)g(the)g(k)o(eystrok)o(es)480 -833 y(are)c(most)g(similar)h(to)f(Emacs.)19 b(This)c(v)m(ariable)h(can) -f(b)q(e)g(set)f(to)g(either)h Fk(emacs)f Fl(or)g Fk(vi)p -Fl(.)240 909 y Fk(horizontal-scroll-mode)480 971 y Fl(This)k(v)m -(ariable)g(can)f(b)q(e)g(set)g(to)f(either)i Fk(On)f -Fl(or)f Fk(Off)p Fl(.)25 b(Setting)17 b(it)g(to)f Fk(On)h -Fl(means)g(that)480 1033 y(the)d(text)g(of)f(the)h(lines)i(that)d(y)o -(ou)h(edit)h(will)g(scroll)g(horizon)o(tally)g(on)f(a)g(single)h -(screen)480 1096 y(line)f(when)f(they)g(are)f(longer)h(than)f(the)h -(width)g(of)f(the)g(screen,)h(instead)g(of)g(wrapping)480 -1158 y(on)o(to)h(a)h(new)h(screen)f(line.)22 b(By)15 -b(default,)h(this)f(v)m(ariable)i(is)f(set)e(to)h Fk(Off)p -Fl(.)240 1234 y Fk(mark-modified-lines)480 1296 y Fl(This)h(v)m -(ariable,)g(when)g(set)f(to)f Fk(On)p Fl(,)h(sa)o(ys)f(to)g(displa)o(y) -j(an)e(asterisk)g(\(`)p Fk(*)p Fl('\))e(at)i(the)g(start)480 -1358 y(of)f(history)h(lines)i(whic)o(h)e(ha)o(v)o(e)g(b)q(een)h(mo)q -(di\014ed.)21 b(This)15 b(v)m(ariable)h(is)g Fk(off)e -Fl(b)o(y)h(default.)240 1434 y Fk(bell-style)480 1496 -y Fl(Con)o(trols)h(what)f(happ)q(ens)j(when)f(Readline)h(w)o(an)o(ts)e -(to)f(ring)i(the)f(terminal)h(b)q(ell.)26 b(If)480 1558 -y(set)13 b(to)g Fk(none)p Fl(,)g(Readline)j(nev)o(er)e(rings)g(the)g(b) -q(ell.)21 b(If)14 b(set)f(to)g Fk(visible)p Fl(,)g(Readline)j(uses)480 -1621 y(a)g(visible)j(b)q(ell)g(if)e(one)g(is)g(a)o(v)m(ailable.)27 -b(If)17 b(set)f(to)g Fk(audible)g Fl(\(the)h(default\),)g(Readline)480 -1683 y(attempts)d(to)h(ring)g(the)h(terminal's)f(b)q(ell.)240 -1758 y Fk(comment-begin)480 1821 y Fl(The)21 b(string)h(to)e(insert)i -(at)e(the)h(b)q(eginning)j(of)c(the)i(line)g(when)g(the)f -Fk(vi-comment)480 1883 y Fl(command)15 b(is)h(executed.)21 -b(The)15 b(default)h(v)m(alue)g(is)g Fk("#")p Fl(.)240 -1958 y Fk(meta-flag)480 2021 y Fl(If)d(set)g(to)f Fk(on)p -Fl(,)g(Readline)j(will)g(enable)f(eigh)o(t-bit)f(input)h(\(it)f(will)h -(not)f(strip)g(the)g(eigh)o(th)480 2083 y(bit)i(from)g(the)g(c)o -(haracters)f(it)h(reads\),)f(regardless)h(of)g(what)f(the)h(terminal)h -(claims)g(it)480 2145 y(can)f(supp)q(ort.)20 b(The)c(default)g(v)m -(alue)g(is)g Fk(off)p Fl(.)240 2221 y Fk(convert-meta)480 -2283 y Fl(If)23 b(set)f(to)f Fk(on)p Fl(,)j(Readline)h(will)f(con)o(v)o -(ert)d(c)o(haracters)h(with)g(the)h(eigth)g(bit)f(set)h(to)480 -2345 y(an)17 b(ASCI)q(I)g(k)o(ey)g(sequence)h(b)o(y)e(stripping)i(the)f -(eigth)g(bit)g(and)g(prep)q(ending)i(an)d Fk(ESC)480 -2408 y Fl(c)o(haracter,)h(con)o(v)o(erting)g(them)g(to)f(a)h -(meta-pre\014xed)h(k)o(ey)f(sequence.)27 b(The)17 b(default)480 -2470 y(v)m(alue)f(is)g Fk(on)p Fl(.)240 2545 y Fk(output-meta)480 -2608 y Fl(If)d(set)f(to)g Fk(on)p Fl(,)h(Readline)i(will)f(displa)o(y)g -(c)o(haracters)d(with)i(the)g(eigh)o(th)g(bit)g(set)g(directly)480 -2670 y(rather)i(than)g(as)f(a)h(meta-pre\014xed)h(escap)q(e)g -(sequence.)21 b(The)16 b(default)f(is)h Fk(off)p Fl(.)p -eop -42 43 bop 0 -58 a Fl(42)1623 b(Bash)15 b(F)l(eatures)240 -183 y Fk(completion-query-items)480 246 y Fl(The)d(n)o(um)o(b)q(er)g -(of)f(p)q(ossible)j(completions)e(that)f(determines)i(when)f(the)g -(user)g(is)g(ask)o(ed)480 308 y(whether)k(he)h(w)o(an)o(ts)d(to)i(see)g -(the)g(list)h(of)e(p)q(ossibiliti)q(es.)25 b(If)16 b(the)g(n)o(um)o(b)q -(er)h(of)e(p)q(ossible)480 370 y(completions)i(is)f(greater)f(than)h -(this)h(v)m(alue,)f(Readline)j(will)e(ask)f(the)g(user)g(whether)480 -432 y(or)k(not)h(he)h(wishes)f(to)g(view)g(them;)j(otherwise,)e(they)f -(are)g(simply)h(listed.)39 b(The)480 495 y(default)16 -b(limit)g(is)g Fk(100)p Fl(.)240 588 y Fk(keymap)96 b -Fl(Sets)13 b(Readline's)i(idea)e(of)g(the)g(curren)o(t)f(k)o(eymap)h -(for)f(k)o(ey)h(binding)i(commands.)k(Ac-)480 651 y(ceptable)d -Fk(keymap)e Fl(names)h(are)g Fk(emacs)p Fl(,)f Fk(emacs-standard)p -Fl(,)f Fk(emacs-meta)p Fl(,)g Fk(emacs-)480 713 y(ctlx)p -Fl(,)j Fk(vi)p Fl(,)h Fk(vi-move)p Fl(,)f Fk(vi-command)p -Fl(,)g(and)h Fk(vi-insert)p Fl(.)23 b Fk(vi)17 b Fl(is)g(equiv)m(alen)o -(t)i(to)d Fk(vi-)480 775 y(command)p Fl(;)22 b Fk(emacs)e -Fl(is)h(equiv)m(alen)o(t)h(to)e Fk(emacs-standard)p Fl(.)35 -b(The)20 b(default)i(v)m(alue)f(is)480 838 y Fk(emacs)p -Fl(.)33 b(The)21 b(v)m(alue)g(of)e(the)i Fk(editing-mode)d -Fl(v)m(ariable)j(also)f(a\013ects)f(the)h(default)480 -900 y(k)o(eymap.)240 978 y Fk(show-all-if-ambiguous)480 -1040 y Fl(This)d(alters)f(the)h(default)g(b)q(eha)o(vior)g(of)f(the)g -(completion)i(functions.)24 b(If)17 b(set)f(to)g Fk(on)p -Fl(,)480 1102 y(w)o(ords)d(whic)o(h)h(ha)o(v)o(e)f(more)h(than)f(one)h -(p)q(ossible)h(completion)g(cause)f(the)f(matc)o(hes)h(to)480 -1165 y(b)q(e)h(listed)g(immediately)h(instead)f(of)f(ringing)h(the)f(b) -q(ell.)22 b(The)14 b(default)h(v)m(alue)g(is)g Fk(off)p -Fl(.)240 1243 y Fk(expand-tilde)480 1305 y Fl(If)20 b(set)f(to)g -Fk(on)p Fl(,)h(tilde)h(expansion)f(is)g(p)q(erformed)g(when)g(Readline) -i(attempts)d(w)o(ord)480 1367 y(completion.)i(The)15 -b(default)h(is)g Fk(off)p Fl(.)0 1445 y(Key)g(Bindings)240 -1508 y(The)k(syn)o(tax)f(for)g(con)o(trolling)i(k)o(ey)e(bindings)j(in) -e(the)g(init)h(\014le)g(is)f(simple.)35 b(First)19 b(y)o(ou)g(ha)o(v)o -(e)h(to)240 1570 y(kno)o(w)13 b(the)h(name)g(of)f(the)h(command)g(that) -f(y)o(ou)g(w)o(an)o(t)g(to)g(c)o(hange.)20 b(The)14 b(follo)o(wing)g -(pages)g(con)o(tain)240 1632 y(tables)i(of)f(the)h(command)g(name,)f -(the)h(default)g(k)o(eybinding,)i(and)e(a)f(short)g(description)i(of)f -(what)240 1694 y(the)f(command)g(do)q(es.)240 1772 y(Once)h(y)o(ou)e -(kno)o(w)g(the)h(name)g(of)f(the)h(command,)f(simply)i(place)g(the)f -(name)f(of)h(the)f(k)o(ey)h(y)o(ou)f(wish)240 1835 y(to)g(bind)j(the)e -(command)g(to,)f(a)g(colon,)i(and)f(then)g(the)g(name)g(of)g(the)g -(command)g(on)g(a)f(line)j(in)f(the)240 1897 y(init)h(\014le.)22 -b(The)16 b(name)g(of)f(the)h(k)o(ey)f(can)h(b)q(e)g(expressed)h(in)f -(di\013eren)o(t)g(w)o(a)o(ys,)f(dep)q(ending)i(on)f(whic)o(h)240 -1959 y(is)g(most)e(comfortable)h(for)g(y)o(ou.)240 2037 -y Fg(k)o(eyname)s Fl(:)k Fg(function-name)g Fl(or)c Fg(macro)480 -2100 y(k)o(eyname)j Fl(is)d(the)h(name)f(of)g(a)g(k)o(ey)g(sp)q(elled)i -(out)e(in)h(English.)21 b(F)l(or)15 b(example:)600 2165 -y Fk(Control-u:)22 b(universal-argument)600 2215 y(Meta-Rubout:)g -(backward-kill-word)600 2265 y(Control-o:)g(">&output")480 -2343 y Fl(In)12 b(the)g(ab)q(o)o(v)o(e)f(example,)h(`)p -Fk(C-u)p Fl(')f(is)h(b)q(ound)g(to)f(the)h(function)g -Fk(universal-argument)p Fl(,)480 2405 y(and)h(`)p Fk(C-o)p -Fl(')f(is)h(b)q(ound)h(to)f(run)g(the)g(macro)f(expressed)i(on)f(the)g -(righ)o(t)g(hand)g(side)h(\(that)480 2467 y(is,)h(to)g(insert)h(the)f -(text)g(`)p Fk(>&output)p Fl(')e(in)o(to)i(the)g(line\).)240 -2545 y Fk(")p Fg(k)o(eyseq)q Fk(")p Fl(:)20 b Fg(function-name)e -Fl(or)d Fg(macro)480 2608 y(k)o(eyseq)j Fl(di\013ers)f(from)f -Fg(k)o(eyname)k Fl(ab)q(o)o(v)o(e)c(in)i(that)e(strings)h(denoting)h -(an)f(en)o(tire)g(k)o(ey)480 2670 y(sequence)i(can)f(b)q(e)h(sp)q -(eci\014ed,)i(b)o(y)d(placing)h(the)f(k)o(ey)g(sequence)h(in)g(double)h -(quotes.)p eop -43 44 bop 0 -58 a Fl(Chapter)15 b(7:)k(Command)c(Line)i(Editing)1205 -b(43)480 183 y(Some)18 b(GNU)g(Emacs)f(st)o(yle)h(k)o(ey)g(escap)q(es)g -(can)g(b)q(e)h(used,)g(as)e(in)i(the)f(follo)o(wing)h(ex-)480 -246 y(ample,)c(but)h(the)f(sp)q(ecial)i(c)o(haracter)e(names)g(are)g -(not)f(recognized.)600 308 y Fk("\\C-u":)23 b(universal-argument)600 -358 y("\\C-x\\C-r":)f(re-read-init-file)600 407 y("\\e[11~":)h -("Function)f(Key)i(1")480 482 y Fl(In)13 b(the)g(ab)q(o)o(v)o(e)g -(example,)g(`)p Fk(C-u)p Fl(')f(is)h(b)q(ound)h(to)e(the)h(function)g -Fk(universal-argument)480 544 y Fl(\(just)g(as)f(it)i(w)o(as)e(in)i -(the)f(\014rst)g(example\),)h(`)p Fk(C-x)g(C-r)p Fl(')f(is)g(b)q(ound)i -(to)d(the)h(function)h Fk(re-)480 607 y(read-init-file)p -Fl(,)g(and)i(`)p Fk(ESC)e([)h(1)g(1)g(~)p Fl(')h(is)g(b)q(ound)h(to)f -(insert)g(the)g(text)f(`)p Fk(Function)480 669 y(Key)g(1)p -Fl('.)24 b(The)18 b(follo)o(wing)f(escap)q(e)h(sequences)g(are)f(a)o(v) -m(ailable)i(when)e(sp)q(ecifying)i(k)o(ey)480 731 y(sequences:)480 -818 y Fk(\\C-)168 b Fl(con)o(trol)15 b(pre\014x)480 906 -y Fk(\\M-)168 b Fl(meta)15 b(pre\014x)480 993 y Fk(\\e)192 -b Fl(an)15 b(escap)q(e)h(c)o(haracter)480 1080 y Fk(\\\\)192 -b Fl(bac)o(kslash)480 1167 y Fk(\\")g(")480 1254 y(\\')g(')480 -1342 y Fl(When)14 b(en)o(tering)h(the)f(text)f(of)h(a)f(macro,)g -(single)j(or)d(double)i(quotes)f(should)h(b)q(e)f(used)480 -1404 y(to)g(indicate)j(a)e(macro)f(de\014nition.)22 b(Unquoted)15 -b(text)g(is)g(assumed)g(to)g(b)q(e)g(a)g(function)480 -1466 y(name.)27 b(Bac)o(kslash)18 b(will)h(quote)e(an)o(y)g(c)o -(haracter)g(in)h(the)g(macro)f(text,)g(including)j Fk(")480 -1528 y Fl(and)c Fk(')p Fl(.)22 b(F)l(or)16 b(example,)h(the)f(follo)o -(wing)h(binding)h(will)f(mak)o(e)f Fk(C-x)f(\\)g Fl(insert)i(a)f -(single)480 1591 y Fk(\\)f Fl(in)o(to)g(the)g(line:)600 -1653 y Fk("\\C-x\\\\":)23 b("\\\\")0 1860 y Ff(7.3.2)30 -b(Conditional)15 b(Init)g(Constructs)62 1997 y Fl(Readline)j(implemen)o -(ts)e(a)f(facilit)o(y)h(similar)g(in)g(spirit)g(to)f(the)g(conditional) -i(compilation)f(features)f(of)g(the)g(C)0 2060 y(prepro)q(cessor)f -(whic)o(h)h(allo)o(ws)f(k)o(ey)g(bindings)h(and)f(v)m(ariable)i -(settings)e(to)f(b)q(e)h(p)q(erformed)h(as)e(the)h(result)g(of)g -(tests.)0 2122 y(There)h(are)g(three)h(parser)e(directiv)o(es)j(used.)0 -2271 y Fk($if)168 b Fl(The)14 b Fk($if)e Fl(construct)h(allo)o(ws)h -(bindings)h(to)e(b)q(e)h(made)f(based)h(on)f(the)h(editing)g(mo)q(de,)g -(the)f(terminal)240 2334 y(b)q(eing)k(used,)e(or)g(the)g(application)i -(using)f(Readline.)22 b(The)16 b(text)f(of)g(the)g(test)g(extends)g(to) -g(the)g(end)240 2396 y(of)g(the)g(line;)i(no)e(c)o(haracters)f(are)h -(required)h(to)f(isolate)g(it.)240 2483 y Fk(mode)144 -b Fl(The)19 b Fk(mode=)f Fl(form)g(of)h(the)g Fk($if)f -Fl(directiv)o(e)i(is)f(used)h(to)e(test)g(whether)h(Readline)i(is)480 -2545 y(in)h Fk(emacs)f Fl(or)f Fk(vi)h Fl(mo)q(de.)38 -b(This)22 b(ma)o(y)f(b)q(e)h(used)g(in)g(conjunction)g(with)f(the)h(`)p -Fk(set)480 2608 y(keymap)p Fl(')d(command,)i(for)e(instance,)j(to)d -(set)h(bindings)i(in)f(the)f Fk(emacs-standard)480 2670 -y Fl(and)15 b Fk(emacs-ctlx)f Fl(k)o(eymaps)h(only)h(if)f(Readline)j -(is)e(starting)e(out)h(in)h Fk(emacs)f Fl(mo)q(de.)p -eop -44 45 bop 0 -58 a Fl(44)1623 b(Bash)15 b(F)l(eatures)240 -183 y Fk(term)144 b Fl(The)21 b Fk(term=)f Fl(form)g(ma)o(y)h(b)q(e)g -(used)h(to)e(include)j(terminal-sp)q(eci\014c)h(k)o(ey)c(bindings,)480 -246 y(p)q(erhaps)15 b(to)f(bind)j(the)d(k)o(ey)h(sequences)h(output)e -(b)o(y)h(the)g(terminal's)g(function)h(k)o(eys.)480 308 -y(The)f(w)o(ord)g(on)f(the)i(righ)o(t)e(side)i(of)f(the)g(`)p -Fk(=)p Fl(')f(is)h(tested)g(against)g(the)g(full)h(name)f(of)g(the)480 -370 y(terminal)k(and)g(the)g(p)q(ortion)g(of)f(the)h(terminal)g(name)g -(b)q(efore)g(the)g(\014rst)f(`)p Fk(-)p Fl('.)29 b(This)480 -432 y(allo)o(ws)15 b Fg(sun)h Fl(to)e(matc)o(h)h(b)q(oth)g -Fg(sun)h Fl(and)f Fg(sun-cmd)p Fl(,)h(for)f(instance.)240 -510 y Fk(application)480 572 y Fl(The)j Fg(application)i -Fl(construct)e(is)g(used)h(to)e(include)k(application-sp)q(eci\014c)g -(settings.)480 634 y(Eac)o(h)d(program)g(using)h(the)f(Readline)j -(library)e(sets)f(the)h Fg(application)h(name)p Fl(,)f(and)480 -697 y(y)o(ou)c(can)h(test)f(for)g(it.)21 b(This)16 b(could)g(b)q(e)h -(used)f(to)e(bind)j(k)o(ey)f(sequences)g(to)f(functions)480 -759 y(useful)h(for)e(a)h(sp)q(eci\014c)i(program.)h(F)l(or)d(instance,) -g(the)g(follo)o(wing)h(command)e(adds)h(a)480 821 y(k)o(ey)g(sequence)h -(that)f(quotes)g(the)g(curren)o(t)g(or)g(previous)h(w)o(ord)e(in)i -(Bash:)600 886 y Fk($if)23 b(bash)600 936 y(#)h(Quote)f(the)g(current)g -(or)h(previous)f(word)600 986 y("\\C-xq":)g("\\eb\\"\\ef\\"")600 -1036 y($endif)0 1129 y($endif)96 b Fl(This)16 b(command,)e(as)h(y)o(ou) -g(sa)o(w)g(in)h(the)f(previous)h(example,)f(terminates)h(an)f -Fk($if)f Fl(command.)0 1222 y Fk($else)120 b Fl(Commands)15 -b(in)h(this)f(branc)o(h)h(of)e(the)i Fk($if)e Fl(directiv)o(e)j(are)e -(executed)h(if)g(the)f(test)g(fails.)0 1472 y Fj(7.4)33 -b(Bindable)16 b(Readline)h(Commands)0 1706 y Ff(7.4.1)30 -b(Commands)15 b(F)-5 b(or)15 b(Mo)n(ving)0 1846 y Fk(beginning-of-line) -e(\(C-a\))240 1908 y Fl(Mo)o(v)o(e)h(to)h(the)g(start)f(of)h(the)g -(curren)o(t)g(line.)0 1986 y Fk(end-of-line)f(\(C-e\))240 -2048 y Fl(Mo)o(v)o(e)g(to)h(the)g(end)h(of)f(the)g(line.)0 -2126 y Fk(forward-char)f(\(C-f\))240 2188 y Fl(Mo)o(v)o(e)g(forw)o(ard) -g(a)h(c)o(haracter.)0 2266 y Fk(backward-char)e(\(C-b\))240 -2328 y Fl(Mo)o(v)o(e)h(bac)o(k)h(a)g(c)o(haracter.)0 -2406 y Fk(forward-word)f(\(M-f\))240 2468 y Fl(Mo)o(v)o(e)g(forw)o(ard) -g(to)h(the)g(end)h(of)f(the)g(next)g(w)o(ord.)k(W)l(ords)c(are)g(comp)q -(osed)h(of)e(letters)i(and)f(digits.)0 2545 y Fk(backward-word)e -(\(M-b\))240 2608 y Fl(Mo)o(v)o(e)j(bac)o(k)g(to)g(the)h(start)f(of)g -(this,)h(or)g(the)f(previous,)i(w)o(ord.)24 b(W)l(ords)16 -b(are)g(comp)q(osed)i(of)e(letters)240 2670 y(and)f(digits.)p -eop -45 46 bop 0 -58 a Fl(Chapter)15 b(7:)k(Command)c(Line)i(Editing)1205 -b(45)0 183 y Fk(clear-screen)14 b(\(C-l\))240 246 y Fl(Clear)h(the)g -(screen)g(and)g(redra)o(w)f(the)h(curren)o(t)g(line,)h(lea)o(ving)g -(the)f(curren)o(t)f(line)j(at)d(the)h(top)f(of)h(the)240 -308 y(screen.)0 386 y Fk(redraw-current-line)e(\(\))240 -448 y Fl(Refresh)j(the)f(curren)o(t)g(line.)22 b(By)15 -b(default,)h(this)f(is)h(un)o(b)q(ound.)0 688 y Ff(7.4.2)30 -b(Commands)15 b(F)-5 b(or)15 b(Manipulating)g(The)g(History)0 -829 y Fk(accept-line)f(\(Newline,)g(Return\))240 891 -y Fl(Accept)k(the)g(line)h(regardless)f(of)f(where)h(the)g(cursor)f -(is.)28 b(If)18 b(this)g(line)h(is)g(non-empt)o(y)l(,)f(add)g(it)g(to) -240 953 y(the)d(history)f(list)h(according)g(to)f(the)g(setting)h(of)f -(the)g Fk(HISTCONTROL)f Fl(v)m(ariable.)21 b(If)15 b(this)g(line)h(w)o -(as)d(a)240 1015 y(history)i(line,)i(then)e(restore)g(the)g(history)g -(line)i(to)e(its)g(original)h(state.)0 1094 y Fk(previous-history)d -(\(C-p\))240 1156 y Fl(Mo)o(v)o(e)h(`up')h(through)g(the)g(history)g -(list.)0 1234 y Fk(next-history)f(\(C-n\))240 1296 y -Fl(Mo)o(v)o(e)g(`do)o(wn')g(through)h(the)h(history)f(list.)0 -1375 y Fk(beginning-of-history)d(\(M-<\))240 1437 y Fl(Mo)o(v)o(e)i(to) -h(the)g(\014rst)g(line)i(in)f(the)f(history)l(.)0 1515 -y Fk(end-of-history)e(\(M->\))240 1578 y Fl(Mo)o(v)o(e)h(to)h(the)g -(end)h(of)f(the)g(input)h(history)l(,)f(i.e.,)g(the)g(line)i(y)o(ou)e -(are)g(en)o(tering.)0 1656 y Fk(reverse-search-history)d(\(C-r\))240 -1718 y Fl(Searc)o(h)18 b(bac)o(kw)o(ard)f(starting)g(at)g(the)g(curren) -o(t)h(line)h(and)f(mo)o(ving)f(`up')h(through)f(the)h(history)f(as)240 -1780 y(necessary)l(.)j(This)c(is)g(an)f(incremen)o(tal)h(searc)o(h.)0 -1859 y Fk(forward-search-history)c(\(C-s\))240 1921 y -Fl(Searc)o(h)j(forw)o(ard)e(starting)h(at)g(the)g(curren)o(t)h(line)h -(and)f(mo)o(ving)f(`do)o(wn')g(through)g(the)g(the)h(history)240 -1983 y(as)g(necessary)l(.)20 b(This)c(is)g(an)f(incremen)o(tal)h(searc) -o(h.)0 2062 y Fk(non-incremental-reverse-se)o(arch-hi)o(story)c -(\(M-p\))240 2124 y Fl(Searc)o(h)18 b(bac)o(kw)o(ard)f(starting)g(at)g -(the)g(curren)o(t)h(line)h(and)f(mo)o(ving)f(`up')h(through)f(the)h -(history)f(as)240 2186 y(necessary)e(using)h(a)f(non-incremen)o(tal)i -(searc)o(h)e(for)g(a)f(string)i(supplied)h(b)o(y)e(the)h(user.)0 -2264 y Fk(non-incremental-forward-se)o(arch-hi)o(story)c(\(M-n\))240 -2327 y Fl(Searc)o(h)j(forw)o(ard)e(starting)h(at)g(the)g(curren)o(t)h -(line)h(and)f(mo)o(ving)f(`do)o(wn')g(through)g(the)g(the)h(history)240 -2389 y(as)g(necessary)g(using)h(a)f(non-incremen)o(tal)i(searc)o(h)e -(for)f(a)h(string)g(supplied)j(b)o(y)d(the)g(user.)0 -2467 y Fk(history-search-forward)d(\(\))240 2529 y Fl(Searc)o(h)h(forw) -o(ard)f(through)h(the)g(history)g(for)g(the)g(string)g(of)g(c)o -(haracters)f(b)q(et)o(w)o(een)i(the)f(start)f(of)h(the)240 -2592 y(curren)o(t)j(line)i(and)e(the)h(curren)o(t)f(p)q(oin)o(t.)23 -b(This)17 b(is)f(a)g(non-incremen)o(tal)i(searc)o(h.)23 -b(By)16 b(default,)h(this)240 2654 y(command)e(is)h(un)o(b)q(ound.)p -eop -46 47 bop 0 -58 a Fl(46)1623 b(Bash)15 b(F)l(eatures)0 -183 y Fk(history-search-backward)d(\(\))240 246 y Fl(Searc)o(h)k(bac)o -(kw)o(ard)g(through)g(the)g(history)g(for)g(the)g(string)g(of)g(c)o -(haracters)g(b)q(et)o(w)o(een)g(the)g(start)f(of)240 -308 y(the)i(curren)o(t)g(line)h(and)f(the)g(curren)o(t)g(p)q(oin)o(t.) -25 b(This)17 b(is)g(a)g(non-incremen)o(tal)h(searc)o(h.)25 -b(By)17 b(default,)240 370 y(this)f(command)f(is)g(un)o(b)q(ound.)0 -450 y Fk(yank-nth-arg)f(\(M-C-y\))240 512 y Fl(Insert)19 -b(the)g(\014rst)f(argumen)o(t)g(to)g(the)h(previous)g(command)g -(\(usually)g(the)g(second)g(w)o(ord)f(on)h(the)240 575 -y(previous)e(line\).)23 b(With)16 b(an)g(argumen)o(t)f -Fg(n)p Fl(,)h(insert)h(the)f Fg(n)p Fl(th)g(w)o(ord)f(from)g(the)h -(previous)h(command)240 637 y(\(the)d(w)o(ords)g(in)h(the)g(previous)g -(command)f(b)q(egin)i(with)f(w)o(ord)f(0\).)19 b(A)14 -b(negativ)o(e)h(argumen)o(t)f(inserts)240 699 y(the)h -Fg(n)p Fl(th)h(w)o(ord)e(from)h(the)g(end)h(of)e(the)i(previous)g -(command.)0 779 y Fk(yank-last-arg)d(\(M-.,)i(M-_\))240 -841 y Fl(Insert)k(last)g(argumen)o(t)g(to)f(the)h(previous)h(command)f -(\(the)g(last)g(w)o(ord)f(on)h(the)g(previous)h(line\).)240 -904 y(With)15 b(an)h(argumen)o(t,)e(b)q(eha)o(v)o(e)h(exactly)h(lik)o -(e)g Fk(yank-nth-arg)p Fl(.)0 1158 y Ff(7.4.3)30 b(Commands)15 -b(F)-5 b(or)15 b(Changing)g(T)-5 b(ext)0 1301 y Fk(delete-char)14 -b(\(C-d\))240 1363 y Fl(Delete)f(the)f(c)o(haracter)f(under)i(the)f -(cursor.)19 b(If)12 b(the)g(cursor)g(is)g(at)g(the)g(b)q(eginning)i(of) -e(the)g(line,)i(there)240 1425 y(are)k(no)g(c)o(haracters)g(in)h(the)g -(line,)h(and)f(the)f(last)g(c)o(haracter)g(t)o(yp)q(ed)h(w)o(as)e(not)h -(C-d,)h(then)g(return)240 1487 y(EOF.)0 1567 y Fk(backward-delete-char) -12 b(\(Rubout\))240 1630 y Fl(Delete)g(the)f(c)o(haracter)f(b)q(ehind)j -(the)e(cursor.)18 b(A)11 b(n)o(umeric)h(arg)e(sa)o(ys)g(to)g(kill)j -(the)e(c)o(haracters)f(instead)240 1692 y(of)15 b(deleting)h(them.)0 -1772 y Fk(quoted-insert)d(\(C-q,)i(C-v\))240 1834 y Fl(Add)i(the)f -(next)h(c)o(haracter)f(that)f(y)o(ou)h(t)o(yp)q(e)h(to)f(the)g(line)i -(v)o(erbatim.)24 b(This)17 b(is)g(ho)o(w)e(to)h(insert)h(k)o(ey)240 -1897 y(sequences)f(lik)o(e)h Fk(C-Q)p Fl(,)d(for)h(example.)0 -1976 y Fk(tab-insert)f(\(M-TAB\))240 2039 y Fl(Insert)h(a)g(tab)g(c)o -(haracter.)0 2119 y Fk(self-insert)f(\(a,)g(b,)h(A,)g(1,)g(!,)g(...\)) -240 2181 y Fl(Insert)g(y)o(ourself.)0 2261 y Fk(transpose-chars)e -(\(C-t\))240 2323 y Fl(Drag)h(the)h(c)o(haracter)g(b)q(efore)g(the)h -(cursor)f(forw)o(ard)f(o)o(v)o(er)g(the)h(c)o(haracter)g(at)f(the)i -(cursor,)e(mo)o(ving)240 2386 y(the)k(cursor)h(forw)o(ard)e(as)h(w)o -(ell.)30 b(If)19 b(the)f(insertion)i(p)q(oin)o(t)f(is)g(at)e(the)i(end) -g(of)f(the)g(line,)j(then)e(this)240 2448 y(transp)q(oses)c(the)g(last) -g(t)o(w)o(o)f(c)o(haracters)h(of)f(the)i(line.)21 b(Negativ)o(e)15 -b(argumen)o(tss)f(don't)h(w)o(ork.)0 2528 y Fk(transpose-words)e -(\(M-t\))240 2590 y Fl(Drag)f(the)h(w)o(ord)f(b)q(ehind)i(the)f(cursor) -g(past)f(the)h(w)o(ord)f(in)h(fron)o(t)f(of)h(the)f(cursor)h(mo)o(ving) -f(the)h(cursor)240 2652 y(o)o(v)o(er)h(that)h(w)o(ord)f(as)h(w)o(ell.)p -eop -47 48 bop 0 -58 a Fl(Chapter)15 b(7:)k(Command)c(Line)i(Editing)1205 -b(47)0 183 y Fk(upcase-word)14 b(\(M-u\))240 246 y Fl(Upp)q(ercase)h -(the)e(curren)o(t)h(\(or)f(follo)o(wing\))h(w)o(ord.)k(With)c(a)f -(negativ)o(e)h(argumen)o(t,)f(do)g(the)h(previous)240 -308 y(w)o(ord,)g(but)h(do)h(not)e(mo)o(v)o(e)h(the)g(cursor.)0 -383 y Fk(downcase-word)e(\(M-l\))240 445 y Fl(Lo)o(w)o(ercase)g(the)i -(curren)o(t)f(\(or)f(follo)o(wing\))h(w)o(ord.)19 b(With)14 -b(a)g(negativ)o(e)g(argumen)o(t,)f(do)h(the)g(previous)240 -507 y(w)o(ord,)g(but)h(do)h(not)e(mo)o(v)o(e)h(the)g(cursor.)0 -582 y Fk(capitalize-word)e(\(M-c\))240 644 y Fl(Capitalize)j(the)e -(curren)o(t)g(\(or)f(follo)o(wing\))i(w)o(ord.)j(With)d(a)f(negativ)o -(e)g(argumen)o(t,)f(do)h(the)g(previous)240 707 y(w)o(ord,)g(but)h(do)h -(not)e(mo)o(v)o(e)h(the)g(cursor.)0 916 y Ff(7.4.4)30 -b(Killing)15 b(And)h(Y)-5 b(anking)0 1053 y Fk(kill-line)14 -b(\(C-k\))240 1115 y Fl(Kill)j(the)f(text)e(from)h(the)g(curren)o(t)g -(cursor)g(p)q(osition)h(to)f(the)g(end)h(of)f(the)g(line.)0 -1190 y Fk(backward-kill-line)e(\(C-x)h(Rubout\))240 1252 -y Fl(Kill)j(bac)o(kw)o(ard)e(to)f(the)i(b)q(eginning)h(of)e(the)g -(line.)0 1327 y Fk(unix-line-discard)e(\(C-u\))240 1390 -y Fl(Kill)j(bac)o(kw)o(ard)d(from)f(the)i(cursor)f(to)g(the)h(b)q -(eginning)i(of)d(the)g(curren)o(t)h(line.)21 b(Sa)o(v)o(e)13 -b(the)h(killed)h(text)240 1452 y(on)g(the)g(kill-ring.)0 -1527 y Fk(kill-whole-line)e(\(\))240 1589 y Fl(Kill)18 -b(all)f(c)o(haracters)e(on)h(the)g(curren)o(t)f(line,)j(no)e(matter)e -(where)i(the)g(cursor)g(is.)22 b(By)16 b(default,)h(this)240 -1651 y(is)f(un)o(b)q(ound.)0 1726 y Fk(kill-word)e(\(M-d\))240 -1789 y Fl(Kill)j(from)d(the)h(cursor)g(to)f(the)h(end)g(of)g(the)g -(curren)o(t)f(w)o(ord,)g(or)g(if)i(b)q(et)o(w)o(een)f(w)o(ords,)f(to)g -(the)h(end)g(of)240 1851 y(the)g(next)h(w)o(ord.)j(W)l(ord)c(b)q -(oundaries)h(are)f(the)g(same)g(as)g Fk(forward-word)p -Fl(.)0 1926 y Fk(backward-kill-word)e(\(M-DEL\))240 1988 -y Fl(Kill)k(the)f(w)o(ord)e(b)q(ehind)j(the)f(cursor.)j(W)l(ord)c(b)q -(oundaries)i(are)d(the)i(same)f(as)f Fk(backward-word)p -Fl(.)0 2063 y Fk(unix-word-rubout)f(\(C-w\))240 2125 -y Fl(Kill)i(the)e(w)o(ord)f(b)q(ehind)j(the)f(cursor,)e(using)i(white)f -(space)h(as)e(a)h(w)o(ord)f(b)q(oundary)l(.)20 b(The)13 -b(killed)i(text)240 2187 y(is)h(sa)o(v)o(ed)e(on)i(the)f(kill-ring.)0 -2262 y Fk(delete-horizontal-space)d(\(\))240 2325 y Fl(Delete)k(all)g -(spaces)f(and)h(tabs)e(around)i(p)q(oin)o(t.)k(By)15 -b(default,)h(this)f(is)h(un)o(b)q(ound.)0 2399 y Fk(yank)f(\(C-y\))240 -2462 y Fl(Y)l(ank)g(the)h(top)f(of)f(the)i(kill)h(ring)e(in)o(to)g(the) -h(bu\013er)f(at)f(the)i(curren)o(t)f(cursor)g(p)q(osition.)0 -2537 y Fk(yank-pop)f(\(M-y\))240 2599 y Fl(Rotate)f(the)h(kill-ring,)i -(and)e(y)o(ank)g(the)g(new)g(top.)19 b(Y)l(ou)14 b(can)g(only)g(do)g -(this)g(if)g(the)g(prior)g(command)240 2661 y(is)i(y)o(ank)f(or)f(y)o -(ank-p)q(op.)p eop -48 49 bop 0 -58 a Fl(48)1623 b(Bash)15 b(F)l(eatures)0 -183 y Ff(7.4.5)30 b(Sp)r(ecifying)15 b(Numeric)h(Argumen)n(ts)0 -324 y Fk(digit-argument)d(\(M-0,)i(M-1,)f(...)h(M--\))240 -386 y Fl(Add)k(this)f(digit)h(to)f(the)g(argumen)o(t)f(already)i(accum) -o(ulating,)g(or)f(start)f(a)g(new)i(argumen)o(t.)28 b(M{)240 -448 y(starts)14 b(a)h(negativ)o(e)g(argumen)o(t.)0 527 -y Fk(universal-argument)e(\(\))240 589 y Fl(Eac)o(h)k(time)h(this)g(is) -f(executed,)i(the)e(argumen)o(t)g(coun)o(t)g(is)h(m)o(ultiplied)i(b)o -(y)d(four.)26 b(The)18 b(argumen)o(t)240 651 y(coun)o(t)i(is)h -(initially)j(one,)d(so)f(executing)i(this)f(function)g(the)g(\014rst)f -(time)h(mak)o(es)f(the)h(argumen)o(t)240 714 y(coun)o(t)15 -b(four.)20 b(By)15 b(default,)g(this)h(is)g(not)e(b)q(ound)j(to)d(a)h -(k)o(ey)l(.)0 954 y Ff(7.4.6)30 b(Letting)14 b(Readline)h(T)n(yp)r(e)h -(F)-5 b(or)14 b(Y)-5 b(ou)0 1095 y Fk(complete)14 b(\(TAB\))240 -1157 y Fl(A)o(ttempt)i(to)h(do)g(completion)i(on)e(the)g(text)g(b)q -(efore)h(the)f(cursor.)26 b(This)18 b(is)g(application-sp)q(eci\014c.) -240 1219 y(Generally)l(,)h(if)f(y)o(ou)f(are)h(t)o(yping)g(a)f -(\014lename)i(argumen)o(t,)e(y)o(ou)g(can)h(do)f(\014lename)i -(completion;)g(if)240 1282 y(y)o(ou)f(are)f(t)o(yping)i(a)e(command,)i -(y)o(ou)e(can)i(do)f(command)g(completion,)h(if)g(y)o(ou)e(are)h(t)o -(yping)g(in)h(a)240 1344 y(sym)o(b)q(ol)e(to)f(GDB,)g(y)o(ou)g(can)h -(do)g(sym)o(b)q(ol)g(name)g(completion,)h(if)f(y)o(ou)f(are)h(t)o -(yping)g(in)g(a)g(v)m(ariable)240 1406 y(to)e(Bash,)h(y)o(ou)f(can)h -(do)g(v)m(ariable)h(name)f(completion,)h(and)f(so)f(on.)22 -b(See)16 b(the)g(Bash)g(man)o(ual)g(page)240 1468 y(for)f(a)f(complete) -i(list)g(of)f(a)o(v)m(ailable)i(completion)f(functions.)0 -1547 y Fk(possible-completions)c(\(M-?\))240 1609 y Fl(List)k(the)f(p)q -(ossible)i(completions)f(of)f(the)g(text)g(b)q(efore)h(the)f(cursor.)0 -1687 y Fk(insert-completions)e(\(\))240 1750 y Fl(Insert)22 -b(all)h(completions)g(of)f(the)g(text)f(b)q(efore)h(p)q(oin)o(t)h(that) -e(w)o(ould)h(ha)o(v)o(e)g(b)q(een)h(generated)f(b)o(y)240 -1812 y Fk(possible-completions)p Fl(.)17 b(By)e(default,)h(this)f(is)h -(not)f(b)q(ound)h(to)f(a)g(k)o(ey)l(.)0 2052 y Ff(7.4.7)30 -b(Keyb)r(oard)15 b(Macros)0 2193 y Fk(start-kbd-macro)e(\(C-x)i(\(\)) -240 2255 y Fl(Begin)h(sa)o(ving)f(the)h(c)o(haracters)e(t)o(yp)q(ed)i -(in)o(to)f(the)g(curren)o(t)g(k)o(eyb)q(oard)g(macro.)0 -2334 y Fk(end-kbd-macro)e(\(C-x)i(\)\))240 2396 y Fl(Stop)f(sa)o(ving)h -(the)g(c)o(haracters)f(t)o(yp)q(ed)h(in)o(to)f(the)h(curren)o(t)f(k)o -(eyb)q(oard)h(macro)f(and)h(sa)o(v)o(e)f(the)g(de\014ni-)240 -2458 y(tion.)0 2537 y Fk(call-last-kbd-macro)f(\(C-x)h(e\))240 -2599 y Fl(Re-execute)20 b(the)f(last)f(k)o(eyb)q(oard)g(macro)g -(de\014ned,)i(b)o(y)f(making)f(the)h(c)o(haracters)f(in)h(the)g(macro) -240 2661 y(app)q(ear)c(as)g(if)h(t)o(yp)q(ed)f(at)g(the)g(k)o(eyb)q -(oard.)p eop -49 50 bop 0 -58 a Fl(Chapter)15 b(7:)k(Command)c(Line)i(Editing)1205 -b(49)0 183 y Ff(7.4.8)30 b(Some)15 b(Miscellaneous)h(Commands)0 -320 y Fk(re-read-init-file)d(\(C-x)h(C-r\))240 382 y -Fl(Read)i(in)g(the)f(con)o(ten)o(ts)f(of)h(y)o(our)g(init)h(\014le,)g -(and)f(incorp)q(orate)h(an)o(y)e(bindings)j(or)e(v)m(ariable)i(assign-) -240 445 y(men)o(ts)e(found)g(there.)0 515 y Fk(abort)f(\(C-g\))240 -578 y Fl(Ab)q(ort)f(the)h(curren)o(t)f(editing)i(command)e(and)h(ring)g -(the)f(terminal's)h(b)q(ell)h(\(sub)s(ject)f(to)e(the)i(setting)240 -640 y(of)h Fk(bell-style)p Fl(\).)0 710 y Fk(do-uppercase-version)d -(\(M-a,)j(M-b,)f(...\))240 773 y Fl(Run)i(the)f(command)g(that)g(is)h -(b)q(ound)g(to)e(the)i(corresop)q(onding)g(upp)q(ercase)g(c)o -(haracter.)0 843 y Fk(prefix-meta)e(\(ESC\))240 906 y -Fl(Mak)o(e)g(the)g(next)h(c)o(haracter)f(that)g(y)o(ou)g(t)o(yp)q(e)h -(b)q(e)g(meta\014ed.)20 b(This)15 b(is)g(for)f(p)q(eople)i(without)e(a) -h(meta)240 968 y(k)o(ey)l(.)20 b(T)o(yping)c(`)p Fk(ESC)e(f)p -Fl(')h(is)g(equiv)m(alen)o(t)i(to)e(t)o(yping)g(`)p Fk(M-f)p -Fl('.)0 1038 y Fk(undo)g(\(C-_,)f(C-x)h(C-u\))240 1101 -y Fl(Incremen)o(tal)h(undo,)f(separately)h(remem)o(b)q(ered)g(for)e -(eac)o(h)h(line.)0 1171 y Fk(revert-line)f(\(M-r\))240 -1234 y Fl(Undo)20 b(all)h(c)o(hanges)f(made)g(to)f(this)i(line.)35 -b(This)21 b(is)f(lik)o(e)h(t)o(yping)f(the)g Fk(undo)g -Fl(command)g(enough)240 1296 y(times)15 b(to)g(get)g(bac)o(k)g(to)f -(the)i(b)q(eginning.)0 1366 y Fk(tilde-expand)e(\(M-~\))240 -1429 y Fl(P)o(erform)g(tilde)j(expansion)f(on)f(the)g(curren)o(t)g(w)o -(ord.)0 1499 y Fk(dump-functions)e(\(\))240 1562 y Fl(Prin)o(t)18 -b(all)h(of)f(the)g(functions)h(and)g(their)g(k)o(ey)f(bindings)i(to)d -(the)i(readline)h(output)e(stream.)28 b(If)18 b(a)240 -1624 y(n)o(umeric)i(argumen)o(t)d(is)i(supplied,)j(the)d(output)f(is)h -(formatted)f(in)h(suc)o(h)g(a)f(w)o(a)o(y)g(that)g(it)h(can)f(b)q(e)240 -1686 y(made)d(part)g(of)g(an)g Fg(inputrc)k Fl(\014le.)0 -1757 y Fk(display-shell-version)12 b(\(C-x)j(C-v\))240 -1819 y Fl(Displa)o(y)h(v)o(ersion)f(information)h(ab)q(out)f(the)g -(curren)o(t)g(instance)h(of)f(Bash.)0 1890 y Fk(shell-expand-line)e -(\(M-C-e\))240 1952 y Fl(Expand)f(the)h(line)g(the)f(w)o(a)o(y)g(the)g -(shell)h(do)q(es)g(when)f(it)h(reads)f(it.)19 b(This)12 -b(p)q(erforms)g(alias)h(and)f(history)240 2014 y(expansion)k(as)f(w)o -(ell)h(as)f(all)h(of)f(the)g(shell)i(w)o(ord)d(expansions.)0 -2085 y Fk(history-expand-line)f(\(M-^\))240 2147 y Fl(P)o(erform)h -(history)h(expansion)h(on)g(the)f(curren)o(t)g(line.)0 -2217 y Fk(insert-last-argument)d(\(M-.,)j(M-_\))240 2280 -y Fl(A)g(synon)o(ym)g(for)g Fk(yank-last-arg)p Fl(.)0 -2350 y Fk(operate-and-get-next)d(\(C-o\))240 2413 y Fl(Accept)i(the)f -(curren)o(t)h(line)g(for)f(execution)i(and)e(fetc)o(h)g(the)h(next)f -(line)i(relativ)o(e)f(to)f(the)g(curren)o(t)g(line)240 -2475 y(from)h(the)i(history)f(for)f(editing.)22 b(An)o(y)15 -b(argumen)o(t)f(is)i(ignored.)0 2545 y Fk(emacs-editing-mode)d(\(C-e\)) -240 2608 y Fl(When)k(in)h Fk(vi)e Fl(editing)i(mo)q(de,)f(this)g -(causes)g(a)g(switc)o(h)g(bac)o(k)f(to)h(emacs)f(editing)i(mo)q(de,)f -(as)g(if)g(the)240 2670 y(command)e Fk(set)g(-o)g(emacs)f -Fl(had)i(b)q(een)g(executed.)p eop -50 51 bop 0 -58 a Fl(50)1623 b(Bash)15 b(F)l(eatures)0 -183 y Fj(7.5)33 b(Readline)16 b(vi)g(Mo)r(de)62 320 y -Fl(While)d(the)f(Readline)i(library)e(do)q(es)g(not)g(ha)o(v)o(e)f(a)g -(full)i(set)f(of)f Fk(vi)g Fl(editing)i(functions,)g(it)f(do)q(es)g -(con)o(tain)g(enough)0 382 y(to)i(allo)o(w)h(simple)i(editing)f(of)f -(the)g(line.)21 b(The)15 b(Readline)i Fk(vi)e Fl(mo)q(de)g(b)q(eha)o(v) -o(es)h(as)e(sp)q(eci\014ed)j(in)f(the)f(P)o(osix)g(1003.2)0 -445 y(standard.)62 582 y(In)f(order)g(to)e(switc)o(h)i(in)o(teractiv)o -(ely)g(b)q(et)o(w)o(een)g Fk(Emacs)f Fl(and)h Fk(Vi)f -Fl(editing)h(mo)q(des,)g(use)g(the)f Fk(set)i(-o)g(emacs)e -Fl(and)0 644 y Fk(set)i(-o)g(vi)h Fl(commands)h(\(see)f(Section)i(4.5)e -([The)g(Set)h(Builtin],)i(page)d(20\).)24 b(The)17 b(Readline)i -(default)e(is)h Fk(emacs)0 706 y Fl(mo)q(de.)62 843 y(When)h(y)o(ou)f -(en)o(ter)g(a)g(line)i(in)g Fk(vi)e Fl(mo)q(de,)h(y)o(ou)f(are)g -(already)g(placed)i(in)f(`insertion')g(mo)q(de,)g(as)f(if)h(y)o(ou)f -(had)0 906 y(t)o(yp)q(ed)e(an)f(`)p Fk(i)p Fl('.)20 b(Pressing)c -Fk(ESC)f Fl(switc)o(hes)h(y)o(ou)f(in)o(to)h(`command')f(mo)q(de,)g -(where)h(y)o(ou)f(can)h(edit)g(the)g(text)f(of)g(the)0 -968 y(line)20 b(with)e(the)g(standard)g Fk(vi)f Fl(mo)o(v)o(emen)o(t)g -(k)o(eys,)h(mo)o(v)o(e)g(to)f(previous)i(history)f(lines)h(with)g(`)p -Fk(k)p Fl(',)e(and)h(follo)o(wing)0 1030 y(lines)f(with)e(`)p -Fk(j)p Fl(',)f(and)i(so)e(forth.)p eop -51 52 bop 0 -58 a Fl(App)q(endix)17 b(A:)e(V)l(ariable)i(Index)1345 -b(51)0 183 y Fh(App)r(endix)13 b(A)41 b(V)-7 b(ariable)14 -b(Index)0 438 y Fj(A)0 504 y Fe(auto)p 82 504 12 2 v -13 w(resume)7 b Fd(:)s(:)f(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g -(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:) -g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)20 b Fc(31)0 616 y Fj(B)0 -683 y Fe(BASH)p 82 683 V 13 w(VERSION)5 b Fd(:)s(:)h(:)h(:)f(:)g(:)g(:) -g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g -(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)18 -b Fc(24)0 741 y Fe(bell-style)t Fd(:)s(:)7 b(:)f(:)g(:)g(:)g(:)g(:)g(:) -g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g -(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)18 -b Fc(41)0 853 y Fj(C)0 919 y Fe(cdable)p 122 919 V 12 -w(vars)7 b Fd(:)t(:)f(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g -(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:) -g(:)g(:)g(:)g(:)g(:)g(:)g(:)20 b Fc(10)0 977 y Fe(CDPATH)9 -b Fd(:)d(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:) -g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g -(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)24 b Fc(4)0 -1035 y Fe(comment-be)o(gi)o(n)7 b Fd(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:) -h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g -(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)23 b Fc(41)0 1093 -y Fe(completion)o(-q)o(uer)o(y-)o(ite)o(ms)7 b Fd(:)s(:)f(:)g(:)g(:)g -(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:) -g(:)g(:)g(:)20 b Fc(42)0 1152 y Fe(convert-me)o(ta)8 -b Fd(:)e(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:) -g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g -(:)g(:)g(:)24 b Fc(41)0 1263 y Fj(E)0 1330 y Fe(editing-mo)o(de)8 -b Fd(:)e(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:) -g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g -(:)g(:)g(:)24 b Fc(41)0 1388 y Fe(EUID)t Fd(:)5 b(:)h(:)g(:)g(:)g(:)g -(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:) -g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h -(:)f(:)g(:)g(:)g(:)g(:)17 b Fc(23)0 1446 y Fe(expand-til)o(de)8 -b Fd(:)e(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:) -g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g -(:)g(:)g(:)24 b Fc(42)0 1558 y Fj(F)0 1624 y Fe(FIGNORE)9 -b Fd(:)s(:)e(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:) -h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f -(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)22 b Fc(23)0 1736 -y Fj(H)0 1803 y Fe(histchars)6 b Fd(:)s(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g -(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:) -g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)19 -b Fc(23)0 1861 y Fe(HISTCMD)9 b Fd(:)s(:)e(:)f(:)g(:)g(:)g(:)g(:)g(:)g -(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:) -g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)22 -b Fc(23)0 1919 y Fe(HISTCONTRO)o(L)t Fd(:)s(:)6 b(:)g(:)g(:)g(:)g(:)g -(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:) -g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)17 -b Fc(22)0 1977 y Fe(HISTFILE)8 b Fd(:)s(:)e(:)g(:)g(:)g(:)g(:)g(:)g(:)g -(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:) -h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)21 -b Fc(23)0 2035 y Fe(history)p 142 2035 V 11 w(control)8 -b Fd(:)e(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:) -g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)23 -b Fc(22)0 2093 y Fe(HISTSIZE)8 b Fd(:)s(:)e(:)g(:)g(:)g(:)g(:)g(:)g(:)g -(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:) -h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)21 -b Fc(23)0 2151 y Fe(HOME)5 b Fd(:)g(:)h(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h -(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:) -g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g -(:)g(:)g(:)18 b Fc(4)0 2209 y Fe(horizontal)o(-s)o(cro)o(ll)o(-mo)o(de) -7 b Fd(:)s(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f -(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)20 b Fc(41)0 2268 -y Fe(HOSTFILE)8 b Fd(:)s(:)e(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:) -f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g -(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)21 b Fc(23)0 -2326 y Fe(hostname)p 162 2326 V 11 w(completion)p 372 -2326 V 10 w(file)9 b Fd(:)d(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h -(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)23 b Fc(23)0 -2384 y Fe(HOSTTYPE)8 b Fd(:)s(:)e(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g -(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:) -g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)21 -b Fc(23)0 2496 y Fj(I)0 2562 y Fe(IFS)7 b Fd(:)e(:)h(:)g(:)g(:)g(:)g(:) -g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g -(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:) -g(:)g(:)g(:)h(:)f(:)g(:)g(:)19 b Fc(4)0 2620 y Fe(IGNOREEOF)6 -b Fd(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:) -g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h -(:)f(:)g(:)22 b Fc(10,)13 b(24)0 2678 y Fe(INPUTRC)c -Fd(:)s(:)e(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h -(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:) -g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)22 b Fc(23)1015 438 y -Fj(K)1015 504 y Fe(keymap)9 b Fd(:)d(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:) -g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g -(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)24 -b Fc(42)1015 636 y Fj(M)1015 702 y Fe(MAILCHECK)7 b Fd(:)s(:)f(:)g(:)g -(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:) -g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g -(:)g(:)20 b Fc(23)1015 760 y Fe(MAILPATH)9 b Fd(:)s(:)d(:)g(:)h(:)f(:)g -(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:) -g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g -(:)g(:)22 b Fc(4)1015 818 y Fe(mark-modifi)o(ed)o(-li)o(nes)7 -b Fd(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:) -g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)24 b -Fc(41)1015 876 y Fe(meta-flag)7 b Fd(:)s(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:) -g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g -(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)20 -b Fc(41)1015 1008 y Fj(N)1015 1074 y Fe(no)p 1057 1074 -V 14 w(exit)p 1151 1074 V 12 w(on)p 1203 1074 V 14 w(failed)p -1337 1074 V 12 w(exec)8 b Fd(:)e(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:) -g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)23 -b Fc(24)1015 1132 y Fe(nolinks)9 b Fd(:)t(:)d(:)g(:)g(:)g(:)g(:)g(:)g -(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:) -f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)22 -b Fc(24)1015 1190 y Fe(notify)9 b Fd(:)d(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:) -g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g -(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:) -24 b Fc(31)1015 1322 y Fj(O)1015 1388 y Fe(OLDPWD)9 b -Fd(:)d(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g -(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:) -g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)24 b Fc(12)1015 1446 -y Fe(OPTARG)10 b Fd(:)c(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g -(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:) -g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)25 -b Fc(4)1015 1504 y Fe(OPTIND)10 b Fd(:)c(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:) -g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g -(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:) -g(:)25 b Fc(4)1015 1562 y Fe(OSTYPE)9 b Fd(:)d(:)g(:)g(:)g(:)g(:)g(:)g -(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:) -g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g -(:)g(:)24 b Fc(23)1015 1620 y Fe(output-meta)s Fd(:)s(:)6 -b(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g -(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:) -g(:)g(:)17 b Fc(41)1015 1752 y Fj(P)1015 1818 y Fe(PATH)5 -b Fd(:)g(:)i(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:) -h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g -(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)19 -b Fc(4)1015 1876 y Fe(PROMPT)p 1137 1876 V 12 w(COMMAND)9 -b Fd(:)d(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:) -g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g -(:)25 b Fc(23)1015 1934 y Fe(PS1)7 b Fd(:)e(:)h(:)g(:)g(:)g(:)g(:)h(:)f -(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:) -g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g -(:)g(:)g(:)g(:)g(:)g(:)20 b Fc(4)1015 1992 y Fe(PS2)7 -b Fd(:)e(:)h(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:) -g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g -(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)20 -b Fc(4)1015 2051 y Fe(PS3)6 b Fd(:)f(:)h(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:) -g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g -(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:) -g(:)g(:)g(:)19 b Fc(12)1015 2109 y Fe(PS4)6 b Fd(:)f(:)h(:)g(:)g(:)g(:) -g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h -(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:) -g(:)g(:)g(:)g(:)g(:)g(:)g(:)19 b Fc(12)1015 2167 y Fe(PWD)6 -b Fd(:)f(:)h(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:) -g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g -(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)19 -b Fc(12)1015 2298 y Fj(R)1015 2364 y Fe(RANDOM)9 b Fd(:)d(:)g(:)g(:)g -(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:) -g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g -(:)g(:)g(:)g(:)g(:)24 b Fc(12)1015 2423 y Fe(REPLY)s -Fd(:)5 b(:)h(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:) -g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g -(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)16 b Fc(12)1015 -2554 y Fj(S)1015 2620 y Fe(SECONDS)9 b Fd(:)t(:)d(:)g(:)g(:)g(:)g(:)g -(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:) -h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g -(:)22 b Fc(12)1015 2678 y Fe(show-all-if)o(-a)o(mbi)o(guo)o(us)7 -b Fd(:)t(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:) -g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)22 b Fc(42)p -eop -52 53 bop 0 -58 a Fl(52)1623 b(Bash)15 b(F)l(eatures)0 -183 y Fj(T)0 250 y Fe(TMOUT)s Fd(:)t(:)6 b(:)g(:)g(:)h(:)f(:)g(:)g(:)g -(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:) -g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g -(:)g(:)16 b Fc(13)1015 183 y Fj(U)1015 250 y Fe(UID)6 -b Fd(:)f(:)h(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:) -g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g -(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)19 -b Fc(23)p eop -53 54 bop 0 -58 a Fl(App)q(endix)17 b(B:)e(Concept)h(Index)1347 -b(53)0 183 y Fh(App)r(endix)13 b(B)41 b(Concept)16 b(Index)0 -438 y Fj($)0 504 y Fe($else)s Fd(:)t(:)6 b(:)g(:)g(:)h(:)f(:)g(:)g(:)g -(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:) -g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g -(:)g(:)16 b Fc(44)0 562 y Fe($endif)8 b Fd(:)e(:)g(:)g(:)g(:)g(:)g(:)h -(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:) -g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g -(:)g(:)23 b Fc(44)0 621 y Fe($if)6 b Fd(:)f(:)h(:)g(:)g(:)g(:)g(:)g(:)g -(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:) -g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g -(:)g(:)g(:)h(:)f(:)18 b Fc(43)0 732 y Fj(.)0 799 y Fe(.)9 -b Fd(:)d(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:) -g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g -(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)22 -b Fc(3)0 911 y Fj(:)0 977 y Fe(:)9 b Fd(:)d(:)g(:)g(:)g(:)g(:)g(:)g(:)g -(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:) -f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g -(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)22 b Fc(3)0 1089 y Fj([)0 -1155 y Fe([)9 b Fd(:)d(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g -(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:) -g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g -(:)g(:)g(:)22 b Fc(4)0 1267 y Fj(A)0 1334 y Fe(abort)11 -b(\(C-g\))c Fd(:)t(:)f(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g -(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:) -g(:)h(:)f(:)g(:)g(:)g(:)g(:)20 b Fc(49)0 1392 y Fe(accept-lin)o(e)10 -b(\(Newline)o(,)g(Return\))5 b Fd(:)s(:)h(:)g(:)g(:)g(:)h(:)f(:)g(:)g -(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)18 b Fc(45)0 1450 -y Fe(alias)s Fd(:)t(:)6 b(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g -(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:) -g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)16 -b Fc(14)0 1562 y Fj(B)0 1628 y Fe(backward-c)o(ha)o(r)10 -b(\(C-b\))c Fd(:)t(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h -(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)19 -b Fc(44)0 1686 y Fe(backward-d)o(el)o(ete)o(-c)o(har)9 -b(\(Rubout\))e Fd(:)f(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g -(:)g(:)g(:)g(:)g(:)23 b Fc(46)0 1745 y Fe(backward-k)o(il)o(l-l)o(in)o -(e)10 b(\(C-x)h(Rubout\))d Fd(:)e(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g -(:)g(:)g(:)g(:)g(:)g(:)24 b Fc(47)0 1803 y Fe(backward-k)o(il)o(l-w)o -(or)o(d)10 b(\(M-DEL\))5 b Fd(:)t(:)h(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g -(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)18 b Fc(47)0 -1861 y Fe(backward-w)o(or)o(d)10 b(\(M-b\))c Fd(:)t(:)g(:)g(:)g(:)g(:)g -(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:) -g(:)g(:)g(:)g(:)g(:)g(:)19 b Fc(44)0 1919 y Fe(beginning-)o(of)o(-hi)o -(st)o(ory)9 b(\(M-<\))c Fd(:)g(:)h(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g -(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)18 b Fc(45)0 -1977 y Fe(beginning-)o(of)o(-li)o(ne)9 b(\(C-a\))g Fd(:)c(:)h(:)g(:)g -(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:) -g(:)g(:)g(:)22 b Fc(44)0 2035 y Fe(bg)7 b Fd(:)e(:)h(:)g(:)g(:)g(:)h(:) -f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g -(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:) -g(:)g(:)g(:)g(:)g(:)g(:)g(:)20 b Fc(30)0 2093 y Fe(bind)t -Fd(:)5 b(:)h(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:) -g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g -(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)17 -b Fc(17)0 2151 y Fe(break)t Fd(:)t(:)6 b(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:) -g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g -(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:) -g(:)g(:)17 b Fc(3)0 2209 y Fe(builtin)9 b Fd(:)s(:)e(:)f(:)g(:)g(:)g(:) -g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g -(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:) -g(:)22 b Fc(17)0 2321 y Fj(C)0 2388 y Fe(call-last-)o(kb)o(d-m)o(ac)o -(ro)9 b(\(C-x)j(e\))7 b Fd(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g -(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)20 b Fc(48)0 2446 -y Fe(capitalize)o(-w)o(ord)9 b(\(M-c\))s Fd(:)t(:)d(:)g(:)h(:)f(:)g(:)g -(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:) -g(:)g(:)g(:)16 b Fc(47)0 2504 y Fe(case)5 b Fd(:)g(:)h(:)g(:)g(:)g(:)g -(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:) -g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f -(:)g(:)g(:)g(:)g(:)g(:)g(:)18 b Fc(2)0 2562 y Fe(cd)8 -b Fd(:)d(:)h(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:) -g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g -(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)21 -b Fc(3)0 2620 y Fe(clear-scre)o(en)9 b(\(C-l\))e Fd(:)t(:)f(:)g(:)h(:)f -(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:) -g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)20 b Fc(45)0 2678 y Fe(command)9 -b Fd(:)s(:)e(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:) -h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f -(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)22 b Fc(18)1015 438 -y Fe(complete)10 b(\(TAB\))t Fd(:)t(:)c(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h -(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:) -g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)17 b Fc(48)1015 496 y -Fe(continue)9 b Fd(:)s(:)d(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g -(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:) -g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)22 b -Fc(3)1015 627 y Fj(D)1015 693 y Fe(declare)9 b Fd(:)t(:)d(:)g(:)g(:)g -(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:) -g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h -(:)f(:)g(:)22 b Fc(18)1015 751 y Fe(delete-char)9 b(\(C-d\))f -Fd(:)t(:)f(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h -(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)22 -b Fc(46)1015 809 y Fe(delete-hori)o(zo)o(nta)o(l-s)o(pa)o(ce)9 -b(\(\))c Fd(:)h(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g -(:)g(:)g(:)g(:)g(:)g(:)g(:)19 b Fc(47)1015 867 y Fe(digit-argum)o(en)o -(t)10 b(\(M-0,)h(M-1,)g(...)h(M--\))5 b Fd(:)g(:)h(:)g(:)g(:)g(:)g(:)g -(:)g(:)g(:)g(:)g(:)g(:)g(:)19 b Fc(48)1015 925 y Fe(dirs)5 -b Fd(:)g(:)i(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:) -h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g -(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)19 -b Fc(9)1015 984 y Fe(display-she)o(ll)o(-ve)o(rsi)o(on)9 -b(\(C-x)i(C-v\))f Fd(:)c(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:) -g(:)g(:)g(:)24 b Fc(49)1015 1042 y Fe(do-uppercas)o(e-)o(ver)o(sio)o(n) -10 b(\(M-a,)g(M-b,)i(...\))c Fd(:)t(:)e(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g -(:)21 b Fc(49)1015 1100 y Fe(downcase-wo)o(rd)9 b(\(M-l\))d -Fd(:)t(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g -(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)19 -b Fc(47)1015 1158 y Fe(dump-functi)o(on)o(s)10 b(\(\))e -Fd(:)d(:)i(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h -(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)22 -b Fc(49)1015 1288 y Fj(E)1015 1355 y Fe(echo)5 b Fd(:)g(:)i(:)f(:)g(:)g -(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:) -g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g -(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)19 b Fc(3)1015 1413 y -Fe(emacs-editi)o(ng)o(-mo)o(de)9 b(\(C-e\))f Fd(:)t(:)e(:)h(:)f(:)g(:)g -(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:) -21 b Fc(49)1015 1471 y Fe(enable)9 b Fd(:)d(:)g(:)g(:)g(:)g(:)g(:)g(:)g -(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:) -g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g -(:)24 b Fc(18)1015 1529 y Fe(end-kbd-mac)o(ro)9 b(\(C-x)j(\)\))7 -b Fd(:)t(:)f(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:) -g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)20 b Fc(48)1015 -1587 y Fe(end-of-hist)o(or)o(y)10 b(\(M->\))t Fd(:)t(:)d(:)f(:)g(:)g(:) -g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g -(:)g(:)g(:)g(:)g(:)g(:)18 b Fc(45)1015 1645 y Fe(end-of-line)9 -b(\(C-e\))f Fd(:)t(:)f(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g -(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:) -22 b Fc(44)1015 1703 y Fe(eval)5 b Fd(:)g(:)i(:)f(:)g(:)g(:)g(:)g(:)g -(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:) -g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g -(:)g(:)g(:)g(:)g(:)19 b Fc(3)1015 1762 y(ev)o(en)o(t)14 -b(designators)e Fd(:)6 b(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:) -g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g -(:)g(:)g(:)g(:)23 b Fc(33)1015 1820 y Fe(exec)5 b Fd(:)g(:)i(:)f(:)g(:) -g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g -(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:) -g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)19 b Fc(3)1015 1878 y -Fe(exit)5 b Fd(:)g(:)i(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g -(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:) -h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)19 -b Fc(3)1015 1936 y(expansion)t Fd(:)9 b(:)d(:)g(:)g(:)g(:)g(:)g(:)g(:)g -(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:) -g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)17 -b Fc(33)1015 1994 y Fe(export)10 b Fd(:)c(:)g(:)g(:)g(:)g(:)g(:)g(:)g -(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:) -g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g -(:)g(:)25 b Fc(3)1015 2124 y Fj(F)1015 2191 y Fe(fc)7 -b Fd(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:) -g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g -(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)20 -b Fc(11)1015 2249 y Fe(fg)7 b Fd(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:) -g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g -(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:) -f(:)g(:)g(:)g(:)20 b Fc(30)1015 2307 y Fe(for)7 b Fd(:)e(:)h(:)g(:)g(:) -g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h -(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:) -g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)20 b Fc(1)1015 2365 -y Fe(forward-cha)o(r)10 b(\(C-f\))d Fd(:)t(:)f(:)g(:)g(:)g(:)g(:)g(:)g -(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:) -g(:)h(:)f(:)g(:)g(:)20 b Fc(44)1015 2423 y Fe(forward-sea)o(rc)o(h-h)o -(ist)o(or)o(y)10 b(\(C-s\))f Fd(:)d(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g -(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)25 b Fc(45)1015 2481 -y Fe(forward-wor)o(d)10 b(\(M-f\))d Fd(:)t(:)f(:)g(:)g(:)g(:)g(:)g(:)g -(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:) -g(:)h(:)f(:)g(:)g(:)20 b Fc(44)1015 2612 y Fj(G)1015 -2678 y Fe(getopts)8 b Fd(:)e(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:) -g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g -(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)23 -b Fc(3)p eop -54 55 bop 0 -58 a Fl(54)1623 b(Bash)15 b(F)l(eatures)0 -183 y Fj(H)0 250 y Fe(hash)5 b Fd(:)g(:)h(:)g(:)g(:)g(:)g(:)g(:)g(:)g -(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:) -g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g -(:)g(:)g(:)g(:)18 b Fc(3)0 308 y Fe(help)t Fd(:)5 b(:)h(:)g(:)g(:)g(:)g -(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:) -g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h -(:)f(:)g(:)g(:)g(:)g(:)17 b Fc(19)0 366 y Fe(history)7 -b Fd(:)g(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:) -f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g -(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)23 b Fc(9)0 424 -y(history)14 b(ev)o(en)o(ts)t Fd(:)7 b(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)h -(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:) -g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)17 b Fc(33)0 -482 y(History)m(,)c(ho)o(w)g(to)g(use)c Fd(:)e(:)f(:)g(:)g(:)g(:)g(:)g -(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:) -f(:)g(:)g(:)g(:)g(:)g(:)g(:)22 b Fc(31)0 540 y Fe(history-ex)o(pa)o -(nd-)o(li)o(ne)9 b(\(M-^\))e Fd(:)t(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g -(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)19 -b Fc(49)0 598 y Fe(history-se)o(ar)o(ch-)o(ba)o(ckw)o(ard)9 -b(\(\))c Fd(:)h(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g -(:)h(:)f(:)g(:)g(:)g(:)g(:)18 b Fc(45)0 656 y Fe(history-se)o(ar)o(ch-) -o(fo)o(rwa)o(rd)9 b(\(\))e Fd(:)e(:)h(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g -(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)19 -b Fc(45)0 790 y Fj(I)0 856 y Fe(if)8 b Fd(:)d(:)h(:)g(:)g(:)h(:)f(:)g -(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:) -g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g -(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)21 b Fc(1)0 915 y Fe(insert-com)o(pl)o -(eti)o(on)o(s)10 b(\(\))s Fd(:)5 b(:)h(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g -(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:) -16 b Fc(48)0 973 y Fe(insert-las)o(t-)o(arg)o(um)o(ent)9 -b(\(M-.,)i(M-)p 558 973 12 2 v 13 w(\))5 b Fd(:)h(:)g(:)g(:)g(:)g(:)g -(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)18 b Fc(49)0 -1031 y(in)o(teraction,)d(readline)t Fd(:)8 b(:)e(:)g(:)g(:)g(:)g(:)g(:) -g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g -(:)g(:)g(:)h(:)f(:)g(:)g(:)16 b Fc(37)0 1164 y Fj(J)0 -1231 y Fe(jobs)t Fd(:)5 b(:)h(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f -(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:) -g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)17 -b Fc(31)0 1364 y Fj(K)0 1431 y Fe(kill)5 b Fd(:)g(:)h(:)g(:)g(:)g(:)g -(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:) -g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f -(:)g(:)g(:)g(:)g(:)g(:)g(:)18 b Fc(3)0 1489 y(Kill)d(ring)7 -b Fd(:)g(:)f(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:) -g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g -(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)20 b Fc(39)0 1547 -y Fe(kill-line)9 b(\(C-k\))g Fd(:)d(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g -(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:) -g(:)g(:)g(:)g(:)g(:)g(:)24 b Fc(47)0 1605 y Fe(kill-whole)o(-l)o(ine)9 -b(\(\))e Fd(:)e(:)h(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g -(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)20 -b Fc(47)0 1663 y Fe(kill-word)9 b(\(M-d\))g Fd(:)d(:)g(:)g(:)g(:)h(:)f -(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:) -g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)24 b Fc(47)0 -1721 y(Killing)16 b(text)7 b Fd(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h -(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:) -g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)20 b -Fc(39)0 1855 y Fj(L)0 1921 y Fe(let)9 b Fd(:)c(:)h(:)g(:)g(:)g(:)g(:)g -(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:) -g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g -(:)h(:)21 b Fc(12,)13 b(26)0 1979 y Fe(local)s Fd(:)t(:)6 -b(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g -(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:) -f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)16 b Fc(19)0 2038 -y Fe(logout)9 b Fd(:)d(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g -(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:) -g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)24 -b Fc(9)0 2171 y Fj(N)0 2238 y Fe(next-histo)o(ry)9 b(\(C-n\))e -Fd(:)t(:)f(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g -(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)20 -b Fc(45)0 2296 y Fe(non-increm)o(en)o(tal)o(-f)o(orw)o(ard)o(-s)o(ear)o -(ch)o(-hi)o(st)o(ory)9 b(\(M-n\))82 2354 y Fd(:)d(:)g(:)g(:)g(:)g(:)g -(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:) -f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g -(:)g(:)g(:)g(:)g(:)g(:)18 b Fc(45)0 2412 y Fe(non-increm)o(en)o(tal)o -(-r)o(eve)o(rse)o(-s)o(ear)o(ch)o(-hi)o(st)o(ory)9 b(\(M-p\))82 -2470 y Fd(:)d(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g -(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:) -g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)18 -b Fc(45)0 2604 y Fj(O)0 2670 y Fe(operate-an)o(d-)o(get)o(-n)o(ext)9 -b(\(C-o\))c Fd(:)g(:)h(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g -(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)18 b Fc(49)1015 183 y -Fj(P)1015 250 y Fe(popd)5 b Fd(:)g(:)i(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g -(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:) -g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g -(:)g(:)g(:)19 b Fc(8)1015 308 y Fe(possible-co)o(mp)o(let)o(ion)o(s)10 -b(\(M-?\))5 b Fd(:)t(:)h(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:) -g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)19 b Fc(48)1015 366 y -Fe(prefix-meta)9 b(\(ESC\))f Fd(:)t(:)f(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g -(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:) -g(:)g(:)g(:)g(:)22 b Fc(49)1015 424 y Fe(previous-hi)o(st)o(ory)9 -b(\(C-p\))g Fd(:)d(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h -(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)24 b Fc(45)1015 -482 y Fe(pushd)t Fd(:)5 b(:)h(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h -(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:) -g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)17 -b Fc(8)1015 540 y Fe(pwd)7 b Fd(:)e(:)h(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g -(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:) -g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g -(:)g(:)g(:)g(:)20 b Fc(3)1015 656 y Fj(Q)1015 722 y Fe(quoted-inse)o -(rt)9 b(\(C-q,)i(C-v\))f Fd(:)c(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g -(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)25 -b Fc(46)1015 838 y Fj(R)1015 904 y Fe(re-read-ini)o(t-)o(fil)o(e)10 -b(\(C-x)h(C-r\))c Fd(:)e(:)h(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:) -g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)21 b Fc(49)1015 962 y -Fe(read)5 b Fd(:)g(:)i(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g -(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:) -h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)19 -b Fc(3)1015 1020 y(Readline,)d(ho)o(w)d(to)g(use)5 b -Fd(:)h(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h -(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)19 -b Fc(35)1015 1078 y Fe(readonly)9 b Fd(:)s(:)d(:)g(:)h(:)f(:)g(:)g(:)g -(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:) -g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)22 -b Fc(3)1015 1136 y Fe(redraw-curr)o(en)o(t-l)o(ine)9 -b(\(\))h Fd(:)c(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f -(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)24 b Fc(45)1015 -1195 y Fe(return)10 b Fd(:)c(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:) -g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h -(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)25 -b Fc(4)1015 1253 y Fe(reverse-sea)o(rc)o(h-h)o(ist)o(or)o(y)10 -b(\(C-r\))f Fd(:)d(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g -(:)g(:)g(:)g(:)g(:)25 b Fc(45)1015 1311 y Fe(revert-line)9 -b(\(M-r\))f Fd(:)t(:)f(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g -(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:) -22 b Fc(49)1015 1426 y Fj(S)1015 1493 y Fe(self-insert)9 -b(\(a,)j(b,)g(A,)g(1,)g(!,)g(...\))6 b Fd(:)f(:)h(:)g(:)g(:)g(:)g(:)g -(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)19 b Fc(46)1015 -1551 y Fe(set)6 b Fd(:)f(:)h(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:) -g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g -(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:) -19 b Fc(20)1015 1609 y Fe(shell-expan)o(d-)o(lin)o(e)10 -b(\(M-C-e\))d Fd(:)s(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:) -f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)20 b Fc(49)1015 1667 -y Fe(shift)t Fd(:)5 b(:)h(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f -(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:) -g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)17 -b Fc(4)1015 1725 y Fe(source)10 b Fd(:)c(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:) -g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g -(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:) -g(:)25 b Fc(9)1015 1783 y Fe(start-kbd-m)o(ac)o(ro)10 -b(\(C-x)h(\(\))t Fd(:)5 b(:)h(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g -(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)17 -b Fc(48)1015 1841 y Fe(suspend)9 b Fd(:)t(:)d(:)g(:)g(:)g(:)g(:)g(:)g -(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:) -f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)22 -b Fc(31)1015 1957 y Fj(T)1015 2023 y Fe(tab-insert)9 -b(\(M-TAB\))e Fd(:)t(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:) -g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)20 -b Fc(46)1015 2081 y Fe(test)5 b Fd(:)g(:)i(:)f(:)g(:)g(:)g(:)g(:)g(:)g -(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:) -g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g -(:)g(:)g(:)g(:)19 b Fc(4)1015 2139 y Fe(tilde-expan)o(d)10 -b(\(M-~\))d Fd(:)t(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g -(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)20 -b Fc(49)1015 2198 y Fe(times)t Fd(:)5 b(:)h(:)g(:)g(:)g(:)g(:)g(:)g(:)g -(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:) -h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f -(:)g(:)g(:)17 b Fc(4)1015 2256 y Fe(transpose-c)o(ha)o(rs)10 -b(\(C-t\))s Fd(:)t(:)c(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g -(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)16 -b Fc(46)1015 2314 y Fe(transpose-w)o(or)o(ds)10 b(\(M-t\))s -Fd(:)t(:)c(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g -(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)16 b Fc(46)1015 -2372 y Fe(trap)5 b Fd(:)g(:)i(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g -(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:) -g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g -(:)19 b Fc(4)1015 2430 y Fe(type)t Fd(:)5 b(:)h(:)h(:)f(:)g(:)g(:)g(:)g -(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:) -g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g -(:)g(:)g(:)g(:)18 b Fc(19)1015 2488 y Fe(typeset)9 b -Fd(:)t(:)d(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g -(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:) -g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)22 b Fc(12)1015 2604 -y Fj(U)1015 2670 y Fe(ulimit)9 b Fd(:)d(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g -(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:) -g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)24 -b Fc(19)p eop -55 56 bop 0 -58 a Fl(App)q(endix)17 b(B:)e(Concept)h(Index)1347 -b(55)0 183 y Fe(umask)t Fd(:)t(:)6 b(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:) -g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g -(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:) -g(:)17 b Fc(4)0 241 y Fe(unalias)9 b Fd(:)s(:)e(:)f(:)g(:)g(:)g(:)g(:)g -(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:) -g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)22 -b Fc(14)0 299 y Fe(undo)11 b(\(C-)p 153 299 12 2 v 13 -w(,)i(C-x)e(C-u\))c Fd(:)e(:)h(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g -(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:) -g(:)20 b Fc(49)0 358 y Fe(universal-)o(ar)o(gum)o(en)o(t)10 -b(\(\))s Fd(:)5 b(:)h(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g -(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)16 -b Fc(48)0 416 y Fe(unix-line-)o(di)o(sca)o(rd)9 b(\(C-u\))g -Fd(:)c(:)h(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f -(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)22 b Fc(47)0 474 y Fe(unix-word-)o(ru)o -(bou)o(t)10 b(\(C-w\))e Fd(:)e(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g -(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)23 -b Fc(47)0 532 y Fe(unset)t Fd(:)t(:)6 b(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g -(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:) -g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g -(:)g(:)17 b Fc(4)0 590 y Fe(until)t Fd(:)t(:)6 b(:)g(:)h(:)f(:)g(:)g(:) -g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g -(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:) -g(:)g(:)g(:)g(:)17 b Fc(1)0 648 y Fe(upcase-wor)o(d)10 -b(\(M-u\))e Fd(:)t(:)e(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g -(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:) -21 b Fc(46)1015 183 y Fj(W)1015 250 y Fe(wait)5 b Fd(:)g(:)i(:)f(:)g(:) -g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g -(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:) -g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)19 b Fc(4)1015 308 y -Fe(while)t Fd(:)5 b(:)h(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g -(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:) -g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)17 -b Fc(1)1015 416 y Fj(Y)1015 482 y Fe(yank)12 b(\(C-y\))d -Fd(:)t(:)d(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f -(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:) -g(:)g(:)g(:)g(:)g(:)22 b Fc(47)1015 540 y Fe(yank-last-a)o(rg)9 -b(\(M-.,)i(M-)p 1436 540 V 13 w(\))6 b Fd(:)g(:)g(:)g(:)g(:)g(:)g(:)g -(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:) -19 b Fc(46)1015 598 y Fe(yank-nth-ar)o(g)10 b(\(M-C-y\))t -Fd(:)s(:)d(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h -(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)18 b Fc(46)1015 -656 y Fe(yank-pop)10 b(\(M-y\))t Fd(:)t(:)c(:)g(:)g(:)g(:)g(:)g(:)g(:)g -(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:) -f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)17 b Fc(47)1015 715 -y(Y)m(anking)e(text)s Fd(:)6 b(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g -(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:) -g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)16 b Fc(39)p -eop -56 57 bop 0 -58 a Fl(56)1623 b(Bash)15 b(F)l(eatures)p -eop --1 58 bop 1937 -58 a Fl(i)0 183 y Fh(T)-7 b(able)15 b(of)g(Con)n(ten)n -(ts)0 351 y Fj(1)67 b(Bourne)23 b(Shell)h(St)n(yle)g(F)-6 -b(eatures)14 b Fb(:)c(:)h(:)f(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g -(:)g(:)g(:)h(:)f(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)37 b Fj(1)149 -428 y Fl(1.1)45 b(Lo)q(oping)16 b(Constructs)d Fa(:)7 -b(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g -(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:) -f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)27 b Fl(1)149 -491 y(1.2)45 b(Conditional)16 b(Constructs)8 b Fa(:)f(:)g(:)g(:)g(:)g -(:)h(:)f(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:) -g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h -(:)f(:)g(:)g(:)22 b Fl(1)149 553 y(1.3)45 b(Shell)17 -b(F)l(unctions)6 b Fa(:)i(:)g(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h -(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)h(:)f(:)g(:)g(:) -g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f -(:)g(:)g(:)g(:)h(:)20 b Fl(2)149 615 y(1.4)45 b(Bourne)16 -b(Shell)h(Builtins)6 b Fa(:)j(:)e(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g -(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:) -h(:)f(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)20 -b Fl(3)149 677 y(1.5)45 b(Bourne)16 b(Shell)h(V)l(ariables)d -Fa(:)7 b(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:) -g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g -(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)27 b Fl(4)149 -740 y(1.6)45 b(Other)15 b(Bourne)h(Shell)h(F)l(eatures)5 -b Fa(:)i(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:) -g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f -(:)g(:)g(:)g(:)h(:)19 b Fl(5)299 802 y(1.6.1)44 b(Ma)s(jor)13 -b(Di\013erences)j(from)f(the)g(Bourne)g(Shell)6 b Fa(:)j(:)e(:)h(:)f(:) -g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)20 -b Fl(5)0 927 y Fj(2)67 b(C-Shell)24 b(St)n(yle)g(F)-6 -b(eatures)5 b Fb(:)11 b(:)f(:)g(:)g(:)h(:)f(:)g(:)g(:)h(:)f(:)g(:)g(:)g -(:)h(:)f(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:) -g(:)28 b Fj(7)149 1004 y Fl(2.1)45 b(Tilde)17 b(Expansion)6 -b Fa(:)h(:)g(:)h(:)f(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:) -h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g -(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)20 -b Fl(7)149 1067 y(2.2)45 b(Brace)15 b(Expansion)c Fa(:)d(:)f(:)h(:)f(:) -g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g -(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:) -g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)25 b Fl(7)149 -1129 y(2.3)45 b(C)15 b(Shell)i(Builtins)11 b Fa(:)e(:)e(:)h(:)f(:)g(:)g -(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:) -f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)h(:)f(:)g(:)g(:)g -(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)25 b Fl(8)149 -1191 y(2.4)45 b(C)15 b(Shell)i(V)l(ariables)7 b Fa(:)h(:)f(:)g(:)h(:)f -(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:) -h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g -(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)21 b Fl(10)0 1316 -y Fj(3)67 b(Korn)22 b(Shell)j(St)n(yle)e(F)-6 b(eatures)17 -b Fb(:)10 b(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)h(:)f(:)g(:)g -(:)g(:)h(:)f(:)g(:)g(:)h(:)f(:)g(:)g(:)39 b Fj(11)149 -1394 y Fl(3.1)45 b(Korn)15 b(Shell)i(Constructs)6 b Fa(:)h(:)g(:)h(:)f -(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:) -h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g -(:)g(:)g(:)h(:)f(:)21 b Fl(11)149 1456 y(3.2)45 b(Korn)15 -b(Shell)i(Builtins)6 b Fa(:)j(:)f(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g -(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:) -g(:)g(:)g(:)h(:)f(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h -(:)20 b Fl(11)149 1518 y(3.3)45 b(Korn)15 b(Shell)i(V)l(ariables)d -Fa(:)8 b(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:) -f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g -(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)28 b Fl(12)149 -1580 y(3.4)45 b(Aliases)7 b Fa(:)h(:)g(:)f(:)g(:)g(:)h(:)f(:)g(:)g(:)g -(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:) -g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g -(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)22 -b Fl(13)299 1643 y(3.4.1)44 b(Alias)16 b(Builtins)10 -b Fa(:)f(:)e(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:) -g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f -(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)25 b Fl(14)0 1767 -y Fj(4)67 b(Bash)22 b(Sp)r(eci\014c)h(F)-6 b(eatures)11 -b Fb(:)g(:)f(:)g(:)g(:)h(:)f(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:) -g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)h(:)f(:)g(:)34 -b Fj(15)149 1845 y Fl(4.1)45 b(In)o(v)o(oking)16 b(Bash)5 -b Fa(:)i(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:) -g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h -(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:) -20 b Fl(15)149 1907 y(4.2)45 b(Bash)15 b(Startup)g(Files)c -Fa(:)d(:)f(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g -(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:) -g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)26 b -Fl(16)149 1969 y(4.3)45 b(Is)15 b(This)h(Shell)h(In)o(teractiv)o(e?)9 -b Fa(:)f(:)g(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:) -h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g -(:)g(:)g(:)h(:)f(:)g(:)g(:)24 b Fl(17)149 2032 y(4.4)45 -b(Bash)15 b(Builtin)j(Commands)13 b Fa(:)7 b(:)g(:)g(:)g(:)h(:)f(:)g(:) -g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h -(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)28 -b Fl(17)149 2094 y(4.5)45 b(The)15 b(Set)h(Builtin)e -Fa(:)7 b(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:) -h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g -(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)27 -b Fl(20)149 2156 y(4.6)45 b(Bash)15 b(V)l(ariables)9 -b Fa(:)g(:)e(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:) -g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h -(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)24 -b Fl(22)149 2219 y(4.7)45 b(Shell)17 b(Arithmetic)e Fa(:)7 -b(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g -(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:) -g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)h(:)28 -b Fl(24)299 2281 y(4.7.1)44 b(Arithmetic)16 b(Ev)m(aluation)f -Fa(:)7 b(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:) -g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)29 -b Fl(24)299 2343 y(4.7.2)44 b(Arithmetic)16 b(Expansion)7 -b Fa(:)h(:)f(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:) -g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f -(:)22 b Fl(25)299 2405 y(4.7.3)44 b(Arithmetic)16 b(Builtins)f -Fa(:)7 b(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:) -g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g -(:)h(:)f(:)27 b Fl(26)149 2468 y(4.8)45 b(Con)o(trolling)16 -b(the)f(Prompt)e Fa(:)7 b(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g -(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:) -h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)28 b -Fl(26)0 2592 y Fj(5)67 b(Job)22 b(Con)n(trol)8 b Fb(:)j(:)f(:)g(:)h(:)f -(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:) -f(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h -(:)f(:)31 b Fj(29)149 2670 y Fl(5.1)45 b(Job)15 b(Con)o(trol)g(Basics) -10 b Fa(:)d(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g -(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:) -g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)24 -b Fl(29)p eop --2 59 bop 0 -58 a Fl(ii)1645 b(Bash)15 b(F)l(eatures)149 -42 y(5.2)45 b(Job)15 b(Con)o(trol)g(Builtins)h Fa(:)7 -b(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g -(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:) -g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)28 b Fl(30)149 104 -y(5.3)45 b(Job)15 b(Con)o(trol)g(V)l(ariables)c Fa(:)d(:)f(:)g(:)h(:)f -(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:) -g(:)h(:)f(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g -(:)g(:)g(:)h(:)25 b Fl(31)0 228 y Fj(6)67 b(Using)22 -b(History)h(In)n(teractiv)n(ely)e Fb(:)10 b(:)g(:)h(:)f(:)g(:)g(:)g(:)h -(:)f(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)h(:)f(:)g(:)41 -b Fj(33)149 306 y Fl(6.1)k(History)15 b(In)o(teraction)8 -b Fa(:)f(:)g(:)h(:)f(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:) -h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g -(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)23 -b Fl(33)299 368 y(6.1.1)44 b(Ev)o(en)o(t)14 b(Designators)t -Fa(:)7 b(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:) -h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g -(:)g(:)g(:)h(:)f(:)19 b Fl(33)299 431 y(6.1.2)44 b(W)l(ord)15 -b(Designators)8 b Fa(:)e(:)h(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:) -g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f -(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)23 b Fl(34)299 493 -y(6.1.3)44 b(Mo)q(di\014ers)13 b Fa(:)7 b(:)h(:)f(:)g(:)g(:)g(:)h(:)f -(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:) -g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f -(:)g(:)g(:)g(:)28 b Fl(34)0 617 y Fj(7)67 b(Command)22 -b(Line)i(Editing)10 b Fb(:)h(:)g(:)f(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:) -f(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)33 -b Fj(37)149 695 y Fl(7.1)45 b(In)o(tro)q(duction)16 b(to)f(Line)h -(Editing)t Fa(:)9 b(:)e(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g -(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:) -g(:)g(:)g(:)h(:)f(:)g(:)19 b Fl(37)149 758 y(7.2)45 b(Readline)17 -b(In)o(teraction)5 b Fa(:)j(:)f(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g -(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:) -g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)20 -b Fl(37)299 820 y(7.2.1)44 b(Readline)17 b(Bare)e(Essen)o(tials)d -Fa(:)c(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f -(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)26 -b Fl(38)299 882 y(7.2.2)44 b(Readline)17 b(Mo)o(v)o(emen)o(t)d -(Commands)e Fa(:)7 b(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:) -g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)27 b Fl(38)299 -944 y(7.2.3)44 b(Readline)17 b(Killing)h(Commands)7 b -Fa(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h -(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)22 b Fl(39)299 -1007 y(7.2.4)44 b(Readline)17 b(Argumen)o(ts)c Fa(:)8 -b(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)h(:)f(:)g(:)g -(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:) -28 b Fl(40)149 1069 y(7.3)45 b(Readline)17 b(Init)g(File)c -Fa(:)7 b(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:) -h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g -(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)27 -b Fl(40)299 1131 y(7.3.1)44 b(Readline)17 b(Init)f(Syn)o(tax)10 -b Fa(:)d(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:) -h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g -(:)g(:)25 b Fl(40)299 1193 y(7.3.2)44 b(Conditional)16 -b(Init)g(Constructs)c Fa(:)7 b(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f -(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:) -27 b Fl(43)149 1256 y(7.4)45 b(Bindable)17 b(Readline)h(Commands)8 -b Fa(:)e(:)i(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:) -h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g -(:)g(:)23 b Fl(44)299 1318 y(7.4.1)44 b(Commands)14 b(F)l(or)h(Mo)o -(ving)e Fa(:)7 b(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:) -f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g -(:)28 b Fl(44)299 1380 y(7.4.2)44 b(Commands)14 b(F)l(or)h -(Manipulating)i(The)e(History)8 b Fa(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:) -g(:)h(:)f(:)g(:)g(:)g(:)23 b Fl(45)299 1443 y(7.4.3)44 -b(Commands)14 b(F)l(or)h(Changing)h(T)l(ext)10 b Fa(:)c(:)i(:)f(:)g(:)g -(:)g(:)h(:)f(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:) -g(:)g(:)g(:)25 b Fl(46)299 1505 y(7.4.4)44 b(Killing)18 -b(And)e(Y)l(anking)10 b Fa(:)e(:)f(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g -(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:) -h(:)f(:)g(:)g(:)g(:)h(:)f(:)25 b Fl(47)299 1567 y(7.4.5)44 -b(Sp)q(ecifying)17 b(Numeric)f(Argumen)o(ts)8 b Fa(:)f(:)g(:)g(:)g(:)h -(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:) -g(:)g(:)h(:)22 b Fl(48)299 1629 y(7.4.6)44 b(Letting)15 -b(Readline)j(T)o(yp)q(e)d(F)l(or)g(Y)l(ou)5 b Fa(:)i(:)h(:)f(:)g(:)g(:) -g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f -(:)g(:)g(:)20 b Fl(48)299 1692 y(7.4.7)44 b(Keyb)q(oard)15 -b(Macros)9 b Fa(:)e(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f -(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:) -g(:)h(:)f(:)g(:)g(:)h(:)f(:)24 b Fl(48)299 1754 y(7.4.8)44 -b(Some)15 b(Miscellaneous)i(Commands)11 b Fa(:)d(:)f(:)g(:)g(:)g(:)h(:) -f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g -(:)27 b Fl(49)149 1816 y(7.5)45 b(Readline)17 b(vi)f(Mo)q(de)d -Fa(:)7 b(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:) -g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g -(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)27 -b Fl(50)0 1941 y Fj(App)r(endix)d(A)67 b(V)-6 b(ariable)24 -b(Index)15 b Fb(:)c(:)f(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)h(:)f(:)g -(:)g(:)g(:)h(:)f(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)38 b Fj(51)0 -2081 y(App)r(endix)24 b(B)67 b(Concept)22 b(Index)c Fb(:)10 -b(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)h(:)f(:)g(:)g(:)g -(:)h(:)f(:)g(:)g(:)h(:)f(:)g(:)39 b Fj(53)p eop end -userdict /end-hook known{end-hook}if diff --git a/documentation/features.texi b/documentation/features.texi deleted file mode 100644 index bc1d2b3..0000000 --- a/documentation/features.texi +++ /dev/null @@ -1,1907 +0,0 @@ -\input texinfo.tex @c -*- texinfo -*- -@c %**start of header -@setfilename features.info -@settitle Bash Features -@c %**end of header - -@ignore -last change: Thu Aug 4 15:21:56 EDT 1994 -@end ignore - -@set EDITION 1.14 -@set VERSION 1.14 -@set UPDATED 4 August 1994 -@set UPDATE-MONTH August 1994 - -@setchapternewpage odd -@synindex fn cp -@set BashFeatures -@ifinfo -@format -This text is a brief description of the features that are present in -the Bash shell. - -This is Edition @value{EDITION}, last updated @value{UPDATED}, -of @cite{The GNU Bash Features Guide}, -for @code{Bash}, Version @value{VERSION}. - -Copyright (C) 1991, 1993 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 1, 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, 675 Mass Ave, Cambridge, MA 02139, USA. -@end format -@end ifinfo - -@titlepage -@sp 10 -@title Bash Features -@subtitle Overview Documentation for Bash -@subtitle Edition @value{EDITION}, for @code{bash} Version @value{VERSION}. -@subtitle @value{UPDATE-MONTH} -@author Brian Fox, Free Software Foundation -@author Chet Ramey, Case Western Reserve University -@page -@vskip 0pt plus 1filll -Copyright @copyright{} 1991, 1993 Free Software Foundation, Inc. -@end titlepage - -@ifinfo -@node Top -@top Bash Features - -Bash contains features that appear in other popular shells, and some -features that only appear in Bash. Some of the shells that Bash has -borrowed concepts from are the Bourne Shell (@file{sh}), the Korn Shell -(@file{ksh}), and the C-shell (@file{csh} and its successor, -@file{tcsh}). The following menu breaks the features up into -categories based upon which one of these other shells inspired the -feature. - -This manual is meant as a brief introduction to features found in -Bash. The Bash manual page should be used as the definitive -reference on shell behavior. - -@menu -* Bourne Shell Features:: Features originally found in the - Bourne shell. - -* Csh Features:: Features originally found in the - Berkeley C-Shell. - -* Korn Shell Features:: Features originally found in the Korn - Shell. - -* Bash Specific Features:: Features found only in Bash. - -* Job Control:: A chapter describing what job control is - and how bash allows you to use it. - -* Using History Interactively:: Chapter dealing with history expansion - rules. - -* Command Line Editing:: Chapter describing the command line - editing features. - -* Variable Index:: Quick reference helps you find the - variable you want. - -* Concept Index:: General index for this manual. -@end menu -@end ifinfo - -@node Bourne Shell Features -@chapter Bourne Shell Style Features - -Bash is an acronym for Bourne Again SHell. The Bourne shell is -the traditional Unix shell originally written by Stephen Bourne. -All of the Bourne shell builtin commands are available in Bash, -and the rules for evaluation and quoting are taken from the Posix -1003.2 specification for the `standard' Unix shell. - -This section briefly summarizes things which Bash inherits from -the Bourne shell: shell control structures, builtins, variables, -and other features. It also lists the significant differences -between Bash and the Bourne Shell. - -@menu -* Looping Constructs:: Shell commands for iterative action. -* Conditional Constructs:: Shell commands for conditional execution. -* Shell Functions:: Grouping commands by name. -* Bourne Shell Builtins:: Builtin commands inherited from the Bourne - Shell. -* Bourne Shell Variables:: Variables which Bash uses in the same way - as the Bourne Shell. -* Other Bourne Shell Features:: Addtional aspects of Bash which behave in - the same way as the Bourne Shell. -@end menu - -@node Looping Constructs -@section Looping Constructs - -Note that wherever you see a @samp{;} in the description of a -command's syntax, it may be replaced indiscriminately with -one or more newlines. - -Bash supports the following looping constructs. - -@ftable @code -@item until -The syntax of the @code{until} command is: -@example -until @var{test-commands}; do @var{consequent-commands}; done -@end example -Execute @var{consequent-commands} as long as the final command in -@var{test-commands} has an exit status which is not zero. - -@item while -The syntax of the @code{while} command is: -@example -while @var{test-commands}; do @var{consequent-commands}; done -@end example - -Execute @var{consequent-commands} as long as the final command in -@var{test-commands} has an exit status of zero. - -@item for -The syntax of the for command is: - -@example -for @var{name} [in @var{words} ...]; do @var{commands}; done -@end example -Execute @var{commands} for each member in @var{words}, with @var{name} -bound to the current member. If ``@code{in @var{words}}'' is not -present, ``@code{in "$@@"}'' is assumed. - -@end ftable - -@node Conditional Constructs -@section Conditional Constructs - -@ftable @code -@item if -The syntax of the @code{if} command is: - -@example -if @var{test-commands}; then - @var{consequent-commands}; -[elif @var{more-test-commands}; then - @var{more-consequents};] -[else @var{alternate-consequents};] -fi -@end example - -Execute @var{consequent-commands} only if the final command in -@var{test-commands} has an exit status of zero. -Otherwise, each @code{elif} list is executed in turn, -and if its exit status is zero, -the corresponding @var{more-consequents} is executed and the -command completes. -If ``@code{else @var{alternate-consequents}}'' is present, and -the final command in the final @code{if} or @code{elif} clause -has a non-zero exit status, then execute @var{alternate-consequents}. - -@item case -The syntax of the @code{case} command is: - -@example -@code{case @var{word} in [@var{pattern} [| @var{pattern}]...) @var{commands} ;;]... esac} -@end example - -Selectively execute @var{commands} based upon @var{word} matching -@var{pattern}. The `@code{|}' is used to separate multiple patterns. - -Here is an example using @code{case} in a script that could be used to -describe an interesting feature of an animal: - -@example -echo -n "Enter the name of an animal: " -read ANIMAL -echo -n "The $ANIMAL has " -case $ANIMAL in - horse | dog | cat) echo -n "four";; - man | kangaroo ) echo -n "two";; - *) echo -n "an unknown number of";; -esac -echo "legs." -@end example - -@end ftable - -@node Shell Functions -@section Shell Functions - -Shell functions are a way to group commands for later execution -using a single name for the group. They are executed just like -a "regular" command. Shell functions are executed in the current -shell context; no new process is created to interpret them. - -Functions are declared using this syntax: - -@example -[ @code{function} ] @var{name} () @{ @var{command-list}; @} -@end example - -This defines a function named @var{name}. The @var{body} of the -function is the @var{command-list} between @{ and @}. This list -is executed whenever @var{name} is specified as the -name of a command. The exit status of a function is -the exit status of the last command executed in the body. - -When a function is executed, the arguments to the -function become the positional parameters -during its execution. The special parameter -@code{#} that gives the number of positional parameters -is updated to reflect the change. Positional parameter 0 -is unchanged. - -If the builtin command @code{return} -is executed in a function, the function completes and -execution resumes with the next command after the function -call. When a function completes, the values of the -positional parameters and the special parameter @code{#} -are restored to the values they had prior to function -execution. - -@node Bourne Shell Builtins -@section Bourne Shell Builtins - -The following shell builtin commands are inherited from the Bourne -shell. These commands are implemented as specified by the Posix -1003.2 standard. - -@ftable @code -@item : -Do nothing beyond expanding any arguments and performing redirections. -@item . -Read and execute commands from the @var{filename} argument in the -current shell context. -@item break -Exit from a @code{for}, @code{while}, or @code{until} loop. -@item cd -Change the current working directory. -@item continue -Resume the next iteration of an enclosing @code{for}, @code{while}, -or @code{until} loop. -@item echo -Print the arguments, separated by spaces, to the standard output. -@item eval -The arguments are concatenated together into a single -command, which is then read and executed. -@item exec -If a @var{command} argument -is supplied, it replaces the shell. If no -@var{command} is specified, redirections may be used to affect -the current shell environment. -@item exit -Exit the shell. -@item export -Mark the arguments as variables to be passed to child processes -in the environment. -@item getopts -Parse options to shell scripts or functions. -@item hash -Remember the full pathnames of commands specified as arguments, -so they need not be searched for on subsequent invocations. -@item kill -Send a signal to a process. -@item pwd -Print the current working directory. -@item read -Read a line from the shell input and use it to set the values of -specified variables. -@item readonly -Mark variables as unchangable. -@item return -Cause a shell function to exit with a specified value. -@item shift -Shift positional parameters to the left. -@item test -@itemx [ -Evaluate a conditional expression. -@item times -Print out the user and system times used by the shell and its children. -@item trap -Specify commands to be executed when the shell receives signals. -@item umask -Set the shell process's file creation mask. -@item unset -Cause shell variables to disappear. -@item wait -Wait until child processes exit and report their exit status. -@end ftable - -@node Bourne Shell Variables -@section Bourne Shell Variables - -Bash uses certain shell variables in the same way as the Bourne shell. -In some cases, Bash assigns a default value to the variable. - -@vtable @code - -@item IFS -A list of characters that separate fields; used when the shell splits -words as part of expansion. - -@item PATH -A colon-separated list of directories in which the shell looks for -commands. - -@item HOME -The current user's home directory. - -@item CDPATH -A colon-separated list of directories used as a search path for -the @code{cd} command. - -@item MAILPATH -A colon-separated list of files which the shell periodically checks -for new mail. You can -also specify what message is printed by separating the file name from -the message with a @samp{?}. When used in the text of the message, -@code{$_} stands for the name of the current mailfile. - -@item PS1 -The primary prompt string. - -@item PS2 -The secondary prompt string. - -@item OPTIND -The index of the last option processed by the -@code{getopts} builtin. - -@item OPTARG -The value of the last option argument processed by the -@code{getopts} builtin. - -@end vtable - -@node Other Bourne Shell Features -@section Other Bourne Shell Features - -@menu -* Major Differences from the Bourne Shell:: Major differences between - Bash and the Bourne shell. -@end menu - -Bash implements essentially the same grammar, parameter and variable -expansion, redirection, and quoting as the Bourne Shell. Bash uses the -Posix 1003.2 standard as the specification of how these features are to be -implemented. There are some differences between the traditional Bourne -shell and the Posix standard; this section quickly details the differences -of significance. A number of these differences are explained in greater -depth in subsequent sections. - -@node Major Differences from the Bourne Shell -@subsection Major Differences from the Bourne Shell - -Bash implements the @code{!} keyword to negate the return value of -a pipeline. Very useful when an @code{if} statement needs to act -only if a test fails. - -Bash includes brace expansion (@pxref{Brace Expansion}). - -Bash includes the Posix and @code{ksh}-style pattern removal @code{%%} and -@code{##} constructs to remove leading or trailing substrings from -variables. - -The Posix and @code{ksh}-style @code{$()} form of command substitution is -implemented, and preferred to the Bourne shell's @code{``} (which -is also implemented for backwards compatibility). - -Variables present in the shell's initial environment are automatically -exported to child processes. The Bourne shell does not normally do -this unless the variables are explicitly marked using the @code{export} -command. - -The expansion @code{$@{#xx@}}, which returns the length of @code{$xx}, -is supported. - -The @code{IFS} variable is used to split only the results of expansion, -not all words. This closes a longstanding shell security hole. - -It is possible to have a variable and a function with the same name; -@code{sh} does not separate the two name spaces. - -Bash functions are permitted to have local variables, and thus useful -recursive functions may be written. - -The @code{noclobber} option is available to avoid overwriting existing -files with output redirection. - -Bash allows you to write a function to override a builtin, and provides -access to that builtin's functionality within the function via the -@code{builtin} and @code{command} builtins. - -The @code{command} builtin allows selective disabling of functions -when command lookup is performed. - -Individual builtins may be enabled or disabled using the @code{enable} -builtin. - -Functions may be exported to children via the environment. - -The Bash @code{read} builtin will read a line ending in @key{\} with -the @code{-r} option, and will use the @code{$REPLY} variable as a -default if no arguments are supplied. - -The @code{return} builtin may be used to abort execution of scripts -executed with the @code{.} or @code{source} builtins. - -The @code{umask} builtin allows symbolic mode arguments similar to -those accepted by @code{chmod}. - -The @code{test} builtin is slightly different, as it implements the -Posix 1003.2 algorithm, which specifies the behavior based on the -number of arguments. - -@node Csh Features -@chapter C-Shell Style Features - -The C-Shell (@dfn{@code{csh}}) was created by Bill Joy at UC Berkeley. It -is generally considered to have better features for interactive use than -the original Bourne shell. Some of the @code{csh} features present in -Bash include job control, history expansion, `protected' redirection, and -several variables for controlling the interactive behaviour of the shell -(e.g. @code{IGNOREEOF}). - -@xref{Using History Interactively} for details on history expansion. - -@menu -* Tilde Expansion:: Expansion of the ~ character. -* Brace Expansion:: Expansion of expressions within braces. -* C Shell Builtins:: Builtin commands adopted from the C Shell. -* C Shell Variables:: Variables which Bash uses in essentially - the same way as the C Shell. -@end menu - -@node Tilde Expansion -@section Tilde Expansion - -Bash has tilde (~) expansion, similar, but not identical, to that of -@code{csh}. The following table shows what unquoted words beginning -with a tilde expand to. - -@table @code -@item ~ -The current value of @code{$HOME}. -@item ~/foo -@file{$HOME/foo} - -@item ~fred/foo -The subdirectory @code{foo} of the home directory of the user -@code{fred}. - -@item ~+/foo -@file{$PWD/foo} - -@item ~- -@file{$OLDPWD/foo} -@end table - -Bash will also tilde expand words following redirection operators -and words following @samp{=} in assignment statements. - -@node Brace Expansion -@section Brace Expansion - -Brace expansion -is a mechanism by which arbitrary strings -may be generated. This mechanism is similar to -@var{pathname expansion} (see the Bash manual -page for details), but the file names generated -need not exist. Patterns to be brace expanded take -the form of an optional @var{preamble}, -followed by a series of comma-separated strings -between a pair of braces, followed by an optional @var{postamble}. -The preamble is prepended to each string contained -within the braces, and the postamble is then appended -to each resulting string, expanding left to right. - -Brace expansions may be nested. The results of each expanded -string are not sorted; left to right order is preserved. -For example, -@example -a@{d,c,b@}e -@end example -expands into -@var{ade ace abe}. - -Brace expansion is performed before any other expansions, -and any characters special to other expansions are preserved -in the result. It is strictly textual. Bash -does not apply any syntactic interpretation to the context of the -expansion or the text between the braces. - -A correctly-formed brace expansion must contain unquoted opening -and closing braces, and at least one unquoted comma. -Any incorrectly formed brace expansion is left unchanged. - -This construct is typically used as shorthand when the common -prefix of the strings to be generated is longer than in the -above example: -@example -mkdir /usr/local/src/bash/@{old,new,dist,bugs@} -@end example -or -@example -chown root /usr/@{ucb/@{ex,edit@},lib/@{ex?.?*,how_ex@}@} -@end example - -@node C Shell Builtins -@section C Shell Builtins - -Bash has several builtin commands whose definition is very similar -to @code{csh}. - -@ftable @code -@item pushd -@example -pushd [@var{dir} | @var{+n} | @var{-n}] -@end example - -Save the current directory on a list and then @code{cd} to -@var{dir}. With no -arguments, exchanges the top two directories. - -@table @code -@item +@var{n} -Brings the @var{n}th directory (counting from the left of the -list printed by @code{dirs}) to the top of the list by rotating -the stack. -@item -@var{n} -Brings the @var{n}th directory (counting from the right of the -list printed by @code{dirs}) to the top of the list by rotating -the stack. -@item @var{dir} -Makes the current working directory be the top of the stack, and then -@var{cd}s to @var{dir}. You can see the saved directory list -with the @code{dirs} command. -@end table - -@item popd -@example -popd [+@var{n} | -@var{n}] -@end example - -Pops the directory stack, and @code{cd}s to the new top directory. When -no arguments are given, removes the top directory from the stack and -@code{cd}s to the new top directory. The -elements are numbered from 0 starting at the first directory listed with -@code{dirs}; i.e. @code{popd} is equivalent to @code{popd +0}. -@table @code -@item +@var{n} -Removes the @var{n}th directory (counting from the left of the -list printed by @code{dirs}), starting with zero. -@item -@var{n} -Removes the @var{n}th directory (counting from the right of the -list printed by @code{dirs}), starting with zero. -@end table - -@item dirs -@example -dirs [+@var{n} | -@var{n}] [-@var{l}] -@end example -Display the list of currently remembered directories. Directories -find their way onto the list with the @code{pushd} command; you can get -back up through the list with the @code{popd} command. -@table @code -@item +@var{n} -Displays the @var{n}th directory (counting from the left of the -list printed by @code{dirs} when invoked without options), starting -with zero. -@item -@var{n} -Displays the @var{n}th directory (counting from the right of the -list printed by @code{dirs} when invoked without options), starting -with zero. -@item -@var{l} -Produces a longer listing; the default listing format uses a -tilde to denote the home directory. -@end table - - -@item history -@example -history [@var{n}] [ [-w -r -a -n] [@var{filename}]] -@end example - -Display the history list with line numbers. Lines prefixed with -with a @code{*} have been modified. An argument of @var{n} says -to list only the last @var{n} lines. Option @code{-w} means -write out the current history to the history file; @code{-r} -means to read the current history file and make its contents the -history list. An argument of @code{-a} means to append the new -history lines (history lines entered since the beginning of the -current Bash session) to the history file. Finally, the -@code{-n} argument means to read the history lines not already -read from the history file into the current history list. These -are lines appended to the history file since the beginning of the -current Bash session. If @var{filename} is given, then it is used -as the history file, else if @code{$HISTFILE} has a value, -that is used, otherwise @file{~/.bash_history} is used. - -@item logout -Exit a login shell. - -@item source -A synonym for @code{.} (@pxref{Bourne Shell Builtins}) - -@end ftable - -@node C Shell Variables -@section C Shell Variables - -@vtable @code - -@item IGNOREEOF -If this variable is set, it represents the number of consecutive -@code{EOF}s Bash will read before exiting. By default, Bash will exit -upon reading a single @code{EOF}. - -@item cdable_vars -If this variable is set, Bash treats arguments to the @code{cd} command -which are not directories as names of variables whose values are the -directories to change to. -@end vtable - -@node Korn Shell Features -@chapter Korn Shell Style Features - -This section describes features primarily inspired by the -Korn Shell (@code{ksh}). In some cases, the Posix 1003.2 -standard has adopted these commands and variables from the -Korn Shell; Bash implements those features using the Posix -standard as a guide. - -@menu -* Korn Shell Constructs:: Shell grammar constructs adopted from the - Korn Shell -* Korn Shell Builtins:: Builtin commands adopted from the Korn Shell. -* Korn Shell Variables:: Variables which bash uses in essentially - the same way as the Korn Shell. -* Aliases:: Substituting one command for another. -@end menu - -@node Korn Shell Constructs -@section Korn Shell Constructs - -Bash includes the Korn Shell @code{select} construct. This construct -allows the easy generation of menus. It has almost the same syntax as -the @code{for} command. - -The syntax of the @code{select} command is: -@example -select @var{name} [in @var{words} ...]; do @var{commands}; done -@end example - -The list of words following @code{in} is expanded, generating a list -of items. The set of expanded words is printed on the standard -error, each preceded by a number. If the ``@code{in @var{words}}'' -is omitted, the positional parameters are printed. The -@code{PS3} prompt is then displayed and a line is read from the standard -input. If the line consists of the number corresponding to one of -the displayed words, then the value of @var{name} -is set to that word. If the line is empty, the words and prompt -are displayed again. If @code{EOF} is read, the @code{select} -command completes. Any other value read causes @var{name} -to be set to null. The line read is saved in the variable -@code{REPLY}. - -The @var{commands} are executed after each selection until a -@code{break} or @code{return} command is executed, at which -point the @code{select} command completes. - -@node Korn Shell Builtins -@section Korn Shell Builtins - -This section describes Bash builtin commands taken from @code{ksh}. - -@ftable @code -@item fc - -@example -@code{fc [-e @var{ename}] [-nlr] [@var{first}] [@var{last}]} -@code{fc -s [@var{pat=rep}] [@var{command}]} -@end example - -Fix Command. In the first form, a range of commands from @var{first} to -@var{last} is selected from the history list. Both @var{first} and -@var{last} may be specified as a string (to locate the most recent -command beginning with that string) or as a number (an index into the -history list, where a negative number is used as an offset from the -current command number). If @var{last} is not specified it is set to -@var{first}. If @var{first} is not specified it is set to the previous -command for editing and -16 for listing. If the @code{-l} flag is -given, the commands are listed on standard output. The @code{-n} flag -suppresses the command numbers when listing. The @code{-r} flag -reverses the order of the listing. Otherwise, the editor given by -@var{ename} is invoked on a file containing those commands. If -@var{ename} is not given, the value of the following variable expansion -is used: @code{$@{FCEDIT:-$@{EDITOR:-vi@}@}}. This says to use the -value of the @code{FCEDIT} variable if set, or the value of the -@code{EDITOR} variable if that is set, or @code{vi} if neither is set. -When editing is complete, the edited commands are echoed and executed. - -In the second form, @var{command} is re-executed after each instance -of @var{pat} in the selected command is replaced by @var{rep}. - -A useful alias to use with the @code{fc} command is @code{r='fc -s'}, so -that typing @code{r cc} runs the last command beginning with @code{cc} -and typing @code{r} re-executes the last command (@pxref{Aliases}). - -@item let -The @code{let} builtin allows arithmetic to be performed on shell variables. -For details, refer to @ref{Arithmetic Builtins}. - -@item typeset -The @code{typeset} command is supplied for compatibility with the Korn -shell; however, it has been made obsolete by the -@code{declare} command (@pxref{Bash Builtins}). - -@end ftable - -@node Korn Shell Variables -@section Korn Shell Variables - -@vtable @code - -@item REPLY -The default variable for the @code{read} builtin. - -@item RANDOM -Each time this parameter is referenced, a random integer -is generated. Assigning a value to this variable seeds -the random number generator. - -@item SECONDS -This variable expands to the number of seconds since the -shell was started. Assignment to this variable resets -the count to the value assigned, and the expanded value -becomes the value assigned plus the number of seconds -since the assignment. - -@item PS3 -The value of this variable is used as the prompt for the -@code{select} command. - -@item PS4 -This is the prompt printed before the command line is echoed -when the @code{-x} option is set (@pxref{The Set Builtin}). - -@item PWD -The current working directory as set by the @code{cd} builtin. - -@item OLDPWD -The previous working directory as set by the @code{cd} builtin. - -@item TMOUT -If set to a value greater than zero, the value is interpreted as -the number of seconds to wait for input after issuing the primary -prompt. -Bash terminates after that number of seconds if input does -not arrive. - -@end vtable - -@node Aliases -@section Aliases - -@menu -* Alias Builtins:: Builtins commands to maniuplate aliases. -@end menu - -The shell maintains a list of @var{aliases} -that may be set and unset with the @code{alias} and -@code{unalias} builtin commands. - -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 alias name and the replacement text may contain any valid -shell input, including shell metacharacters, with the exception -that the alias name may not contain @key{=}. -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 -@code{ls} to @code{"ls -F"}, -for instance, and Bash does not try to recursively expand the -replacement text. If the last character of the alias value is a -space or tab character, then the next command word following the -alias is also checked for alias expansion. - -Aliases are created and listed with the @code{alias} -command, and removed with the @code{unalias} command. - -There is no mechanism for using arguments in the replacement text, -as in @code{csh}. -If arguments are needed, a shell function should be used. - -Aliases are not expanded when the shell is not interactive. - -The rules concerning the definition and use of aliases are -somewhat confusing. Bash -always reads at least one complete line -of input before executing any -of the commands on that line. Aliases are expanded when a -command is read, not when it is executed. Therefore, an -alias definition appearing on the same line as another -command does not take effect until the next line of input is read. -This means that the commands following the alias definition -on that line are not affected by the new alias. -This behavior is also an issue when functions are executed. -Aliases are expanded when the function definition is read, -not when the function is executed, because a function definition -is itself a compound command. As a consequence, aliases -defined in a function are not available until after that -function is executed. To be safe, always put -alias definitions on a separate line, and do not use @code{alias} -in compound commands. - -Note that for almost every purpose, aliases are superseded by -shell functions. - -@node Alias Builtins -@subsection Alias Builtins - -@ftable @code -@item alias -@example -alias [@var{name}[=@var{value}] ...] -@end example - -Without arguments, print the list of aliases on the standard output. -If arguments are supplied, an alias is defined for each @var{name} -whose @var{value} is given. If no @var{value} is given, the name -and value of the alias is printed. - -@item unalias -@example -unalias [-a] [@var{name} ... ] -@end example - -Remove each @var{name} from the list of aliases. If @code{-a} is -supplied, all aliases are removed. -@end ftable - -@node Bash Specific Features -@chapter Bash Specific Features - -This section describes the features unique to Bash. - -@menu -* Invoking Bash:: Command line options that you can give - to Bash. -* Bash Startup Files:: When and how Bash executes scripts. -* Is This Shell Interactive?:: Determining the state of a running Bash. -* Bash Builtins:: Table of builtins specific to Bash. -* The Set Builtin:: This builtin is so overloaded it - deserves its own section. -* Bash Variables:: List of variables that exist in Bash. -* Shell Arithmetic:: Arithmetic on shell variables. -* Printing a Prompt:: Controlling the PS1 string. -@end menu - -@node Invoking Bash -@section Invoking Bash - -In addition to the single-character shell command-line options -(@pxref{The Set Builtin}), there are several multi-character -options that you can use. These options must appear on the command -line before the single-character options to be recognized. - -@table @code -@item -norc -Don't read the @file{~/.bashrc} initialization file in an -interactive shell. This is on by default if the shell is -invoked as @code{sh}. - -@item -rcfile @var{filename} -Execute commands from @var{filename} (instead of @file{~/.bashrc}) -in an interactive shell. - -@item -noprofile -Don't load the system-wide startup file @file{/etc/profile} -or any of the personal initialization files -@file{~/.bash_profile}, @file{~/.bash_login}, or @file{~/.profile} -when bash is invoked as a login shell. - -@item -version -Display the version number of this shell. - -@item -login -Make this shell act as if it were directly invoked from login. -This is equivalent to @samp{exec - bash} but can be issued from -another shell, such as @code{csh}. If you wanted to replace your -current login shell with a Bash login shell, you would say -@samp{exec bash -login}. - -@item -nobraceexpansion -Do not perform curly brace expansion (@pxref{Brace Expansion}). - -@item -nolineediting -Do not use the GNU Readline library (@pxref{Command Line Editing}) -to read interactive command lines. - -@item -posix -Change the behavior of Bash where the default operation differs -from the Posix 1003.2 standard to match the standard. This -is intended to make Bash behave as a strict superset of that -standard. - -@end table - -There are several single-character options you can give which are -not available with the @code{set} builtin. - -@table @code -@item -c @var{string} -Read and execute commands from @var{string} after processing the -options, then exit. - -@item -i -Force the shell to run interactively. - -@item -s -If this flag is present, or if no arguments remain after option -processing, then commands are read from the standard input. -This option allows the positional parameters to be set -when invoking an interactive shell. - -@end table - -An @emph{interactive} shell is one whose input and output are both -connected to terminals (as determined by @code{isatty()}), or one -started with the @code{-i} option. - -@node Bash Startup Files -@section Bash Startup Files - -When and how Bash executes startup files. - -@example -For Login shells (subject to the -noprofile option): - - On logging in: - If @file{/etc/profile} exists, then source it. - - If @file{~/.bash_profile} exists, then source it, - else if @file{~/.bash_login} exists, then source it, - else if @file{~/.profile} exists, then source it. - - On logging out: - If @file{~/.bash_logout} exists, source it. - -For non-login interactive shells (subject to the -norc and -rcfile options): - On starting up: - If @file{~/.bashrc} exists, then source it. - -For non-interactive shells: - On starting up: - If the environment variable @code{ENV} is non-null, expand the - variable and source the file named by the value. If Bash is - not started in Posix mode, it looks for @code{BASH_ENV} before - @code{ENV}. -@end example - -So, typically, your @code{~/.bash_profile} contains the line -@example -@code{if [ -f @code{~/.bashrc} ]; then source @code{~/.bashrc}; fi} -@end example -@noindent -after (or before) any login specific initializations. - -If Bash is invoked as @code{sh}, it tries to mimic the behavior of -@code{sh} as closely as possible. For a login shell, it attempts to -source only @file{/etc/profile} and @file{~/.profile}, in that order. -The @code{-noprofile} option may still be used to disable this behavior. -A shell invoked as @code{sh} does not attempt to source any other -startup files. - -When Bash is started in @var{POSIX} mode, as with the -@code{-posix} command line option, it follows the Posix 1003.2 -standard for startup files. In this mode, the @code{ENV} -variable is expanded and that file sourced; no other startup files -are read. - -@node Is This Shell Interactive? -@section Is This Shell Interactive? - -You may wish to determine within a startup script whether Bash is -running interactively or not. To do this, examine the variable -@code{$PS1}; it is unset in non-interactive shells, and set in -interactive shells. Thus: - -@example -if [ -z "$PS1" ]; then - echo This shell is not interactive -else - echo This shell is interactive -fi -@end example - -You can ask an interactive Bash to not run your @file{~/.bashrc} file -with the @code{-norc} flag. You can change the name of the -@file{~/.bashrc} file to any other file name with @code{-rcfile -@var{filename}}. You can ask Bash to not run your -@file{~/.bash_profile} file with the @code{-noprofile} flag. - -@node Bash Builtins -@section Bash Builtin Commands - -This section describes builtin commands which are unique to -or have been extended in Bash. - -@ftable @code -@item builtin -@example -builtin [@var{shell-builtin} [@var{args}]] -@end example -Run a shell builtin. This is useful when you wish to rename a -shell builtin to be a function, but need the functionality of the -builtin within the function itself. - -@item bind -@example -bind [-m @var{keymap}] [-lvd] [-q @var{name}] -bind [-m @var{keymap}] -f @var{filename} -bind [-m @var{keymap}] @var{keyseq:function-name} -@end example - -Display current Readline (@pxref{Command Line Editing}) -key and function bindings, or -bind a key sequence to a Readline function or macro. The -binding syntax accepted is identical to that of -@file{.inputrc} (@pxref{Readline Init File}), -but each binding must be passed as a separate argument: -@samp{"\C-x\C-r":re-read-init-file}. -Options, if supplied, have the following meanings: - -@table @code -@item -m keymap -Use @var{keymap} as the keymap to be affected by -the subsequent bindings. Acceptable @var{keymap} -names are -@code{emacs}, -@code{emacs-standard}, -@code{emacs-meta}, -@code{emacs-ctlx}, -@code{vi}, -@code{vi-move}, -@code{vi-command}, and -@code{vi-insert}. -@code{vi} is equivalent to @code{vi-command}; -@code{emacs} is equivalent to @code{emacs-standard}. - -@item -l -List the names of all readline functions - -@item -v -List current function names and bindings - -@item -d -Dump function names and bindings in such a way that they can be re-read - -@item -f filename -Read key bindings from @var{filename} - -@item -q -Query about which keys invoke the named @var{function} -@end table - -@item command -@example -command [-pVv] @var{command} [@var{args} ...] -@end example -Runs @var{command} with @var{arg} ignoring shell functions. If -you have a shell function called @code{ls}, and you wish to call -the command @code{ls}, you can say @samp{command ls}. The -@code{-p} option means to use a default value for @code{$PATH} -that is guaranteed to find all of the standard utilities. - -If either the @code{-V} or @code{-v} option is supplied, a -description of @var{command} is printed. The @code{-v} option -causes a single word indicating the command or file name used to -invoke @var{command} to be printed; the @code{-V} option produces -a more verbose description. - -@item declare -@example -declare [-frxi] [@var{name}[=@var{value}]] -@end example - -Declare variables and/or give them attributes. If no @var{name}s -are given, then display the values of variables instead. -@code{-f} means to use function names only. @code{-r} says to -make @var{name}s readonly. @code{-x} says to mark @var{name}s -for export. @code{-i} says that the variable is to be treated as -an integer; arithmetic evaluation (@pxref{Shell Arithmetic}) is -performed when the variable is assigned a value. Using @code{+} -instead of @code{-} turns off the attribute instead. When used in -a function, @code{declare} makes @var{name}s local, as with the -@code{local} command. - -@item enable -@example -enable [-n] [-a] [@var{name} ...] -@end example -Enable and disable builtin shell commands. This allows you to -use a disk command which has the same name as a shell builtin. -If @code{-n} is used, the @var{name}s become disabled. Otherwise -@var{name}s are enabled. For example, to use the @code{test} binary -found via @code{$PATH} instead of the shell builtin version, type -@samp{enable -n test}. The @code{-a} option means to list -each builtin with an indication of whether or not it is enabled. - -@item help -@example -help [@var{pattern}] -@end example -Display helpful information about builtin commands. If -@var{pattern} is specified, @code{help} gives detailed help -on all commands matching @var{pattern}, otherwise a list of -the builtins is printed. - -@item local -@example -local @var{name}[=@var{value}] -@end example -For each argument, create a local variable called @var{name}, and -give it @var{value}. -@code{local} can only be used within a function; it makes the variable -@var{name} have a visible scope restricted to that function and its -children. - -@item type -@example -type [-all] [-type | -path] [@var{name} ...] -@end example -For each @var{name}, indicate how it would be interpreted if used as a -command name. - -If the @code{-type} flag is used, @code{type} returns a single word -which is one of ``alias'', ``function'', ``builtin'', ``file'' or -``keyword'', if @var{name} is an alias, shell function, shell builtin, -disk file, or shell reserved word, respectively. - -If the @code{-path} flag is used, @code{type} either returns the name -of the disk file that would be executed, or nothing if @code{-type} -would not return ``file''. - -If the @code{-all} flag is used, returns all of the places that contain -an executable named @var{file}. This includes aliases and functions, -if and only if the @code{-path} flag is not also used. - -@code{Type} accepts @code{-a}, @code{-t}, and @code{-p} as equivalent to -@code{-all}, @code{-type}, and @code{-path}, respectively. - -@item ulimit -@example -ulimit [-acdmstfpnuvSH] [@var{limit}] -@end example -@code{Ulimit} provides control over the resources available to processes -started by the shell, on systems that allow such control. If an -option is given, it is interpreted as follows: -@table @code -@item -S -change and report the soft limit associated with a resource (the -default if the @code{-H} option is not given). -@item -H -change and report the hard limit associated with a resource. -@item -a -all current limits are reported. - -@item -c -the maximum size of core files created. - -@item -d -the maximum size of a process's data segment. - -@item -m -the maximum resident set size. - -@item -s -the maximum stack size. - -@item -t -the maximum amount of cpu time in seconds. - -@item -f -the maximum size of files created by the shell. - -@item -p -the pipe buffer size. - -@item -n -the maximum number of open file descriptors. - -@item -u -the maximum number of processes available to a single user. - -@item -v -the maximum amount of virtual memory available to the process. - -@end table - -If @var{limit} is given, it is the new value of the specified resource. -Otherwise, the current value of the specified resource is printed. If -no option is given, then @samp{-f} is assumed. Values are in 1024-byte -increments, except for @samp{-t}, which is in seconds, @samp{-p}, -which is in units of 512-byte blocks, and @samp{-n} and @samp{-u}, which -are unscaled values. - -@end ftable - -@node The Set Builtin -@section The Set Builtin - -This builtin is so overloaded that it deserves its own section. - -@ftable @code -@item set -@example -set [-abefhkmnptuvxldCHP] [-o @var{option}] [@var{argument} ...] -@end example - -@table @code -@item -a -Mark variables which are modified or created for export. - -@item -b -Cause the status of terminated background jobs to be reported -immediately, rather than before printing the next primary prompt. - -@item -e -Exit immediately if a command exits with a non-zero status. - -@item -f -Disable file name generation (globbing). - -@item -h -Locate and remember (hash) commands as functions are defined, rather -than when the function is executed. - -@item -k -All keyword arguments are placed in the environment for a command, not -just those that precede the command name. - -@item -m -Job control is enabled (@pxref{Job Control}). - -@item -n -Read commands but do not execute them. - -@item -o @var{option-name} - -Set the flag corresponding to @var{option-name}: - -@table @code -@item allexport -same as @code{-a}. - -@item braceexpand -the shell will perform brace expansion (@pxref{Brace Expansion}). - -@item emacs -use an emacs-style line editing interface (@pxref{Command Line Editing}). - -@item errexit -same as @code{-e}. - -@item histexpand -same as @code{-H}. - -@item ignoreeof -the shell will not exit upon reading EOF. - -@item interactive-comments -allow a word beginning with a @samp{#} to cause that word and -all remaining characters on that line to be ignored in an -interactive shell. - -@item monitor -same as @code{-m}. - -@item noclobber -same as @code{-C}. - -@item noexec -same as @code{-n}. - -@item noglob -same as @code{-f}. - -@item nohash -same as @code{-d}. - -@item notify -same as @code{-b}. - -@item nounset -same as @code{-u}. - -@item physical -same as @code{-P}. - -@item posix -change the behavior of Bash where the default operation differs -from the Posix 1003.2 standard to match the standard. This -is intended to make Bash behave as a strict superset of that -standard. - -@item privileged -same as @code{-p}. - -@item verbose -same as @code{-v}. - -@item vi -use a @code{vi}-style line editing interface. - -@item xtrace -same as @code{-x}. -@end table - -@item -p -Turn on privileged mode. -In this mode, the @code{$ENV} -file is not processed, and shell functions -are not inherited from the environment. This is enabled automatically -on startup if the effective user (group) id is not equal to the real -user (group) id. Turning this option off causes the effective user -and group ids to be set to the real user and group ids. - -@item -t -Exit after reading and executing one command. - -@item -u -Treat unset variables as an error when substituting. - -@item -v -Print shell input lines as they are read. - -@item -x -Print commands and their arguments as they are executed. - -@item -l -Save and restore the binding of the @var{name} in a @code{for} command. - -@item -d -Disable the hashing of commands that are looked up for execution. -Normally, commands are remembered in a hash table, and once found, do -not have to be looked up again. - -@item -C -Disallow output redirection to existing files. - -@item -H -Enable ! style history substitution. This flag is on by default. - -@item -P -If set, do not follow symbolic links when performing commands such as -@code{cd} which change the current directory. The physical directory -is used instead. - -@item -- -If no arguments follow this flag, then the positional parameters are -unset. Otherwise, the positional parameters are set to the -@var{arguments}, even if some of them begin with a @code{-}. - -@item - -Signal the end of options, cause all remaining @var{arguments} -to be assigned to the positional parameters. The @code{-x} -and @code{-v} options are turned off. -If there are no arguments, the positional parameters remain unchanged. -@end table - -Using @samp{+} rather than @samp{-} causes these flags to be -turned off. The flags can also be used upon invocation of the -shell. The current set of flags may be found in @code{$-}. The -remaining N @var{arguments} are positional parameters and are -assigned, in order, to @code{$1}, @code{$2}, .. @code{$N}. If -no arguments are given, all shell variables are printed. -@end ftable - -@node Bash Variables -@section Bash Variables - -These variables are set or used by bash, but other shells -do not normally treat them specially. - -@vtable @code - -@item HISTCONTROL -@itemx history_control -Set to a value of @samp{ignorespace}, it means don't enter lines which -begin with a space or tab into the history list. Set to a value -of @samp{ignoredups}, it means don't enter lines which match the last -entered line. A value of @samp{ignoreboth} combines the two options. -Unset, or set to any other value than those above, means to save -all lines on the history list. - -@item HISTFILE -The name of the file to which the command history is saved. - -@item HISTSIZE -If set, this is the maximum number of commands to remember in the -history. - -@item histchars -Up to three characters which control history expansion, quick -substitution, and tokenization (@pxref{History Interaction}). -The first character is the -@dfn{history-expansion-char}, that is, the character which signifies the -start of a history expansion, normally @samp{!}. The second character is the -character which signifies `quick substitution' when seen as the first -character on a line, normally @samp{^}. The optional third character is the -character which signifies the remainder of the line is a comment, when -found as the first character of a word, usually @samp{#}. The history -comment character causes history substitution to be skipped for the -remaining words on the line. It does not necessarily cause the shell -parser to treat the rest of the line as a comment. - -@item HISTCMD -The history number, or index in the history list, of the current -command. If @code{HISTCMD} is unset, it loses its special properties, -even if it is subsequently reset. - -@item hostname_completion_file -@itemx HOSTFILE -Contains the name of a file in the same format as @file{/etc/hosts} that -should be read when the shell needs to complete a hostname. You can -change the file interactively; the next time you attempt to complete a -hostname, Bash will add the contents of the new file to the already -existing database. - -@item MAILCHECK -How often (in seconds) that the shell should check for mail -in the files specified in @code{MAILPATH}. - -@item PROMPT_COMMAND -If present, this contains a string which is a command to execute -before the printing of each primary prompt (@code{$PS1}). - -@item UID -The numeric real user id of the current user. - -@item EUID -The numeric effective user id of the current user. - -@item HOSTTYPE -A string describing the machine Bash is running on. - -@item OSTYPE -A string describing the operating system Bash is running on. - -@item FIGNORE -A colon-separated list of suffixes to ignore when performing -filename completion -A file name whose suffix matches one of the entries in -@code{FIGNORE} -is excluded from the list of matched file names. A sample -value is @samp{.o:~} - -@item INPUTRC -The name of the Readline startup file, overriding the default -of @file{~/.inputrc}. - -@item BASH_VERSION -The version number of the current instance of Bash. - -@item IGNOREEOF -Controls the action of the shell on receipt of an @code{EOF} character -as the sole input. If set, then the value of it is the number -of consecutive @code{EOF} characters that can be read as the -first characters on an input line -before the shell will exit. If the variable exists but does not -have a numeric value (or has no value) then the default is 10. -If the variable does not exist, then @code{EOF} signifies the end of -input to the shell. This is only in effect for interactive shells. - -@item no_exit_on_failed_exec -If this variable exists, the shell will not exit in the case that it -couldn't execute the file specified in the @code{exec} command. - -@item nolinks -If present, says not to follow symbolic links when doing commands -that change the current working directory. By default, bash follows -the logical chain of directories when performing commands such as -@code{cd} which change the current directory. - -For example, if @file{/usr/sys} is a link to @file{/usr/local/sys} then: -@example -$ cd /usr/sys; echo $PWD -/usr/sys -$ cd ..; pwd -/usr -@end example - -@noindent -If @code{nolinks} exists, then: -@example -$ cd /usr/sys; echo $PWD -/usr/local/sys -$ cd ..; pwd -/usr/local -@end example - -See also the description of the @code{-P} option to the @code{set} -builtin, @ref{The Set Builtin}. -@end vtable - -@node Shell Arithmetic -@section Shell Arithmetic - -@menu -* Arithmetic Evaluation:: How shell arithmetic works. -* Arithmetic Expansion:: How to use arithmetic in shell expansions. -* Arithmetic Builtins:: Builtin commands that use shell arithmetic. -@end menu - -@node Arithmetic Evaluation -@subsection Arithmetic Evaluation - -The shell allows arithmetic expressions to be evaluated, as one of -the shell expansions or by the @code{let} builtin. - -Evaluation is done in long integers with no check for overflow, -though division by 0 is trapped and flagged as an error. The -following list of operators is grouped into levels of -equal-precedence operators. The levels are listed in order of -decreasing precedence. - -@table @code -@item - + -unary minus and plus - -@item ! ~ -logical and bitwise negation - -@item * / % -multiplication, division, remainder - -@item + - -addition, subtraction - -@item << >> -left and right bitwise shifts - -@item <= >= < > -comparison - -@item == != -equality and inequality - -@item & -bitwise AND - -@item ^ -bitwise exclusive OR - -@item | -bitwise OR - -@item && -logical AND - -@item || -logical OR - -@item = *= /= %= += -= <<= >>= &= ^= |= -assignment -@end table - -Shell variables are allowed as operands; parameter expansion is -performed before the expression is evaluated. -The value of a parameter is coerced to a long integer within -an expression. A shell variable need not have its integer attribute -turned on to be used in an expression. - -Constants with a leading 0 are interpreted as octal numbers. -A leading @code{0x} or @code{0X} denotes hexadecimal. Otherwise, -numbers take the form [@var{base#}]n, where @var{base} is a -decimal number between 2 and 36 representing the arithmetic -base, and @var{n} is a number in that base. If @var{base} is -omitted, then base 10 is used. - -Operators are evaluated in order of precedence. Sub-expressions in -parentheses are evaluated first and may override the precedence -rules above. - -@node Arithmetic Expansion -@subsection Arithmetic Expansion - -Arithmetic expansion allows the evaluation of an arithmetic expression -and the substitution of the result. There are two formats for -arithmetic expansion: - -@example -$[ expression ] -$(( expression )) -@end example - -The expression is treated as if it were within double quotes, but -a double quote inside the braces or parentheses is not treated -specially. All tokens in the expression undergo parameter -expansion, command substitution, and quote removal. Arithmetic -substitutions may be nested. - -The evaluation is performed according to the rules listed above. -If the expression is invalid, Bash -prints a message indicating failure and no substitution occurs. - -@node Arithmetic Builtins -@subsection Arithmetic Builtins - -@ftable @code -@item let -@example -let @var{expression} [@var{expression}] -@end example -The @code{let} builtin allows arithmetic to be performed on shell -variables. Each @var{expression} is evaluated according to the -rules given previously (@pxref{Arithmetic Evaluation}). If the -last @var{expression} evaluates to 0, @code{let} returns 1; -otherwise 0 is returned. -@end ftable - -@node Printing a Prompt -@section Controlling the Prompt - -The value of the variable @code{$PROMPT_COMMAND} is examined just before -Bash prints each primary prompt. If it is set and non-null, then the -value is executed just as if you had typed it on the command line. - -In addition, the following table describes the special characters which -can appear in the @code{PS1} variable: - -@table @code -@item \t -the time, in HH:MM:SS format. -@item \d -the date, in "Weekday Month Date" format (e.g. "Tue May 26"). -@item \n -newline. -@item \s -the name of the shell, the basename of @code{$0} (the portion -following the final slash). -@item \w -the current working directory. -@item \W -the basename of @code{$PWD}. -@item \u -your username. -@item \h -the hostname. -@item \# -the command number of this command. -@item \! -the history number of this command. -@item \nnn -the character corresponding to the octal number @code{nnn}. -@item \$ -if the effective uid is 0, @code{#}, otherwise @code{$}. -@item \\ -a backslash. -@item \[ -begin a sequence of non-printing characters. This could be used to -embed a terminal control sequence into the prompt. -@item \] -end a sequence of non-printing characters. -@end table - -@node Job Control -@chapter Job Control - -This chapter disusses what job control is, how it works, and how -Bash allows you to access its facilities. - -@menu -* Job Control Basics:: How job control works. -* Job Control Builtins:: Bash builtin commands used to interact - with job control. -* Job Control Variables:: Variables Bash uses to customize job - control. -@end menu - -@node Job Control Basics -@section Job Control Basics - -Job control -refers to the ability to selectively stop (suspend) -the execution of processes and continue (resume) -their execution at a later point. A user typically employs -this facility via an interactive interface supplied jointly -by the system's terminal driver and Bash. - -The shell associates a @var{job} with each pipeline. It keeps a -table of currently executing jobs, which may be listed with the -@code{jobs} command. When Bash starts a job -asynchronously (in the background), it prints a line that looks -like: -@example -[1] 25647 -@end example -indicating that this job is job number 1 and that the process ID -of the last process in the pipeline associated with this job is -25647. All of the processes in a single pipeline are members of -the same job. Bash uses the @var{job} abstraction as the -basis for job control. - -To facilitate the implementation of the user interface to job -control, the system maintains the notion of a current terminal -process group ID. Members of this process group (processes whose -process group ID is equal to the current terminal process group -ID) receive keyboard-generated signals such as @code{SIGINT}. -These processes are said to be in the foreground. Background -processes are those whose process group ID differs from the -terminal's; such processes are immune to keyboard-generated -signals. Only foreground processes are allowed to read from or -write to the terminal. Background processes which attempt to -read from (write to) the terminal are sent a @code{SIGTTIN} -(@code{SIGTTOU}) signal by the terminal driver, which, unless -caught, suspends the process. - -If the operating system on which Bash is running supports -job control, Bash allows you to use it. Typing the -@var{suspend} character (typically @samp{^Z}, Control-Z) while a -process is running causes that process to be stopped and returns -you to Bash. Typing the @var{delayed suspend} character -(typically @samp{^Y}, Control-Y) causes the process to be stopped -when it attempts to read input from the terminal, and control to -be returned to Bash. You may then manipulate the state of -this job, using the @code{bg} command to continue it in the -background, the @code{fg} command to continue it in the -foreground, or the @code{kill} command to kill it. A @samp{^Z} -takes effect immediately, and has the additional side effect of -causing pending output and typeahead to be discarded. - -There are a number of ways to refer to a job in the shell. The -character @samp{%} introduces a job name. Job number @code{n} -may be referred to as @samp{%n}. A job may also be referred to -using a prefix of the name used to start it, or using a substring -that appears in its command line. For example, @samp{%ce} refers -to a stopped @code{ce} job. Using @samp{%?ce}, on the -other hand, refers to any job containing the string @samp{ce} in -its command line. If the prefix or substring matches more than one job, -Bash reports an error. The symbols @samp{%%} and -@samp{%+} refer to the shell's notion of the current job, which -is the last job stopped while it was in the foreground. The -previous job may be referenced using @samp{%-}. In output -pertaining to jobs (e.g., the output of the @code{jobs} command), -the current job is always flagged with a @samp{+}, and the -previous job with a @samp{-}. - -Simply naming a job can be used to bring it into the foreground: -@samp{%1} is a synonym for @samp{fg %1} bringing job 1 from the -background into the foreground. Similarly, @samp{%1 &} resumes -job 1 in the background, equivalent to @samp{bg %1} - -The shell learns immediately whenever a job changes state. -Normally, Bash waits until it is about to print a prompt -before reporting changes in a job's status so as to not interrupt -any other output. If the -the @code{-b} option to the @code{set} builtin is set, -Bash reports such changes immediately (@pxref{The Set Builtin}). -This feature is also controlled by the variable @code{notify}. - -If you attempt to exit bash while jobs are stopped, the -shell prints a message warning you. You may then use the -@code{jobs} command to inspect their status. If you do this, or -try to exit again immediately, you are not warned again, and the -stopped jobs are terminated. - -@node Job Control Builtins -@section Job Control Builtins - -@ftable @code - -@item bg -@example -bg [@var{jobspec}] -@end example -Place @var{jobspec} into the background, as if it had been started -with @samp{&}. If @var{jobspec} is not supplied, the current job -is used. - -@item fg -@example -fg [@var{jobspec}] -@end example -Bring @var{jobspec} into the foreground and make it the current job. -If @var{jobspec} is not supplied, the current job is used. - -@item jobs -@example -jobs [-lpn] [@var{jobspec}] -jobs -x @var{command} [@var{jobspec}] -@end example - -The first form lists the active jobs. The @code{-l} option lists -process IDs in addition to the normal information; the @code{-p} -option lists only the process ID of the job's process group -leader. The @code{-n} option displays only jobs that have -changed status since last notfied. If @var{jobspec} is given, -output is restricted to information about that job. -If @var{jobspec} is not supplied, the status of all jobs is -listed. - -If the @code{-x} option is supplied, @code{jobs} replaces any -@var{jobspec} found in @var{command} or @var{arguments} with the -corresponding process group ID, and executes @var{command}, -passing it @var{argument}s, returning its exit status. - -@item suspend -@example -suspend [-f] -@end example -Suspend the execution of this shell until it receives a -@code{SIGCONT} signal. The @code{-f} option means to suspend -even if the shell is a login shell. - -@end ftable - -When job control is active, the @code{kill} and @code{wait} -builtins also accept @var{jobspec} arguments. - -@node Job Control Variables -@section Job Control Variables - -@vtable @code - -@item auto_resume -This variable controls how the shell interacts with the user and -job control. If this variable exists then single word simple -commands without redirects are treated as candidates for resumption -of an existing job. There is no ambiguity allowed; if you have -more than one job beginning with the string that you have typed, then -the most recently accessed job will be selected. -The name of a stopped job, in this context, is the command line -used to start it. If this variable is set to the value @code{exact}, -the string supplied must match the name of a stopped job exactly; -if set to @code{substring}, -the string supplied needs to match a substring of the name of a -stopped job. The @code{substring} value provides functionality -analogous to the @code{%?} job id (@pxref{Job Control Basics}). -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 @code{%} job id. - -@item notify -Setting this variable to a value is equivalent to -@samp{set -b}; unsetting it is equivalent to @samp{set +b} -(@pxref{The Set Builtin}). - -@end vtable - -@set readline-appendix -@set history-appendix -@cindex History, how to use -@include hsuser.texinfo -@cindex Readline, how to use -@include rluser.texinfo -@clear readline-appendix -@clear history-appendix - -@node Variable Index -@appendix Variable Index -@printindex vr - -@node Concept Index -@appendix Concept Index -@printindex cp - -@contents -@bye diff --git a/documentation/readline.ps b/documentation/readline.ps deleted file mode 100644 index 5e004b1..0000000 --- a/documentation/readline.ps +++ /dev/null @@ -1,1052 +0,0 @@ -%!PS-Adobe-3.0 -%%Creator: groff version 1.08 -%%DocumentNeededResources: font Times-Roman -%%+ font Times-Bold -%%+ font Times-Italic -%%DocumentSuppliedResources: procset grops 1.08 0 -%%Pages: 12 -%%PageOrder: Ascend -%%Orientation: Portrait -%%EndComments -%%BeginProlog -%%BeginResource: procset grops 1.08 0 -/setpacking where{ -pop -currentpacking -true setpacking -}if -/grops 120 dict dup begin -/SC 32 def -/A/show load def -/B{0 SC 3 -1 roll widthshow}bind def -/C{0 exch ashow}bind def -/D{0 exch 0 SC 5 2 roll awidthshow}bind def -/E{0 rmoveto show}bind def -/F{0 rmoveto 0 SC 3 -1 roll widthshow}bind def -/G{0 rmoveto 0 exch ashow}bind def -/H{0 rmoveto 0 exch 0 SC 5 2 roll awidthshow}bind def -/I{0 exch rmoveto show}bind def -/J{0 exch rmoveto 0 SC 3 -1 roll widthshow}bind def -/K{0 exch rmoveto 0 exch ashow}bind def -/L{0 exch rmoveto 0 exch 0 SC 5 2 roll awidthshow}bind def -/M{rmoveto show}bind def -/N{rmoveto 0 SC 3 -1 roll widthshow}bind def -/O{rmoveto 0 exch ashow}bind def -/P{rmoveto 0 exch 0 SC 5 2 roll awidthshow}bind def -/Q{moveto show}bind def -/R{moveto 0 SC 3 -1 roll widthshow}bind def -/S{moveto 0 exch ashow}bind def -/T{moveto 0 exch 0 SC 5 2 roll awidthshow}bind def -/SF{ -findfont exch -[exch dup 0 exch 0 exch neg 0 0]makefont -dup setfont -[exch/setfont cvx]cvx bind def -}bind def -/MF{ -findfont -[5 2 roll -0 3 1 roll -neg 0 0]makefont -dup setfont -[exch/setfont cvx]cvx bind def -}bind def -/level0 0 def -/RES 0 def -/PL 0 def -/LS 0 def -/PLG{ -gsave newpath clippath pathbbox grestore -exch pop add exch pop -}bind def -/BP{ -/level0 save def -1 setlinecap -1 setlinejoin -72 RES div dup scale -LS{ -90 rotate -}{ -0 PL translate -}ifelse -1 -1 scale -}bind def -/EP{ -level0 restore -showpage -}bind def -/DA{ -newpath arcn stroke -}bind def -/SN{ -transform -.25 sub exch .25 sub exch -round .25 add exch round .25 add exch -itransform -}bind def -/DL{ -SN -moveto -SN -lineto stroke -}bind def -/DC{ -newpath 0 360 arc closepath -}bind def -/TM matrix def -/DE{ -TM currentmatrix pop -translate scale newpath 0 0 .5 0 360 arc closepath -TM setmatrix -}bind def -/RC/rcurveto load def -/RL/rlineto load def -/ST/stroke load def -/MT/moveto load def -/CL/closepath load def -/FL{ -currentgray exch setgray fill setgray -}bind def -/BL/fill load def -/LW/setlinewidth load def -/RE{ -findfont -dup maxlength 1 index/FontName known not{1 add}if dict begin -{ -1 index/FID ne{def}{pop pop}ifelse -}forall -/Encoding exch def -dup/FontName exch def -currentdict end definefont pop -}bind def -/DEFS 0 def -/EBEGIN{ -moveto -DEFS begin -}bind def -/EEND/end load def -/CNT 0 def -/level1 0 def -/PBEGIN{ -/level1 save def -translate -div 3 1 roll div exch scale -neg exch neg exch translate -0 setgray -0 setlinecap -1 setlinewidth -0 setlinejoin -10 setmiterlimit -[]0 setdash -/setstrokeadjust where{ -pop -false setstrokeadjust -}if -/setoverprint where{ -pop -false setoverprint -}if -newpath -/CNT countdictstack def -userdict begin -/showpage{}def -}bind def -/PEND{ -clear -countdictstack CNT sub{end}repeat -level1 restore -}bind def -end def -/setpacking where{ -pop -setpacking -}if -%%EndResource -%%IncludeResource: font Times-Roman -%%IncludeResource: font Times-Bold -%%IncludeResource: font Times-Italic -grops begin/DEFS 1 dict def DEFS begin/u{.001 mul}bind def end/RES 72 def/PL -792 def/LS false def/ENC0[/asciicircum/asciitilde/Scaron/Zcaron/scaron/zcaron -/Ydieresis/trademark/quotesingle/.notdef/.notdef/.notdef/.notdef/.notdef -/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef -/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/space -/exclam/quotedbl/numbersign/dollar/percent/ampersand/quoteright/parenleft -/parenright/asterisk/plus/comma/hyphen/period/slash/zero/one/two/three/four -/five/six/seven/eight/nine/colon/semicolon/less/equal/greater/question/at/A/B/C -/D/E/F/G/H/I/J/K/L/M/N/O/P/Q/R/S/T/U/V/W/X/Y/Z/bracketleft/backslash -/bracketright/circumflex/underscore/quoteleft/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q -/r/s/t/u/v/w/x/y/z/braceleft/bar/braceright/tilde/.notdef/quotesinglbase -/guillemotleft/guillemotright/bullet/florin/fraction/perthousand/dagger -/daggerdbl/endash/emdash/ff/fi/fl/ffi/ffl/dotlessi/dotlessj/grave/hungarumlaut -/dotaccent/breve/caron/ring/ogonek/quotedblleft/quotedblright/oe/lslash -/quotedblbase/OE/Lslash/.notdef/exclamdown/cent/sterling/currency/yen/brokenbar -/section/dieresis/copyright/ordfeminine/guilsinglleft/logicalnot/minus -/registered/macron/degree/plusminus/twosuperior/threesuperior/acute/mu -/paragraph/periodcentered/cedilla/onesuperior/ordmasculine/guilsinglright -/onequarter/onehalf/threequarters/questiondown/Agrave/Aacute/Acircumflex/Atilde -/Adieresis/Aring/AE/Ccedilla/Egrave/Eacute/Ecircumflex/Edieresis/Igrave/Iacute -/Icircumflex/Idieresis/Eth/Ntilde/Ograve/Oacute/Ocircumflex/Otilde/Odieresis -/multiply/Oslash/Ugrave/Uacute/Ucircumflex/Udieresis/Yacute/Thorn/germandbls -/agrave/aacute/acircumflex/atilde/adieresis/aring/ae/ccedilla/egrave/eacute -/ecircumflex/edieresis/igrave/iacute/icircumflex/idieresis/eth/ntilde/ograve -/oacute/ocircumflex/otilde/odieresis/divide/oslash/ugrave/uacute/ucircumflex -/udieresis/yacute/thorn/ydieresis]def/Times-Italic@0 ENC0/Times-Italic RE -/Times-Bold@0 ENC0/Times-Bold RE/Times-Roman@0 ENC0/Times-Roman RE -%%EndProlog -%%Page: 1 1 -%%BeginPageSetup -BP -%%EndPageSetup -/F0 10/Times-Roman@0 SF 342.2(READLINE\(3\) READLINE\(3\))72 48 R/F1 9 -/Times-Bold@0 SF -.18(NA)72 84 S(ME).18 E F0 -(readline \255 get a line from a user with editing)108 96 Q F1(SYNOPSIS)72 -112.8 Q/F2 10/Times-Bold@0 SF(#include )-.18 E -(#include )-.7 E(typedef int Function \(\);)108 153.6 Q -(char *r)108 170.4 Q(eadline \(pr)-.18 E(ompt\))-.18 E(char *pr)108 182.4 Q -(ompt;)-.18 E(int rl_add_defun \(name, function, k)108 199.2 Q(ey\))-.1 E -(char *name;)108 211.2 Q(Function *function;)108 223.2 Q(int k)108 235.2 Q(ey;) --.1 E(int rl_bind_k)108 252 Q(ey \(k)-.1 E(ey)-.1 E 2.5(,f)-.55 G(unction\)) -202.26 252 Q(int k)108 264 Q(ey;)-.1 E(Function *function;)108 276 Q -(int rl_unbind_k)108 292.8 Q(ey \(k)-.1 E(ey\))-.1 E(int k)108 304.8 Q(ey;)-.1 -E(int rl_bind_k)108 321.6 Q(ey_in_map \(k)-.1 E(ey)-.1 E 2.5(,f)-.55 G -(unction, k)239.49 321.6 Q(eymap\))-.1 E(int k)108 333.6 Q(ey;)-.1 E -(Function *function;)108 345.6 Q -.25(Ke)108 357.6 S(ymap k).25 E(eymap;)-.1 E -(int rl_unbind_k)108 374.4 Q(ey_in_map \(k)-.1 E(ey)-.1 E 2.5(,k)-.55 G -(eymap\))252.74 374.4 Q(int k)108 386.4 Q(ey;)-.1 E -.25(Ke)108 398.4 S(ymap k) -.25 E(eymap;)-.1 E(int rl_macr)108 415.2 Q(o_bind \(k)-.18 E(eyseq, macr)-.1 E -(o, k)-.18 E(eymap\))-.1 E(char *k)108 427.2 Q(eyseq, *macr)-.1 E(o;)-.18 E --.25(Ke)108 439.2 S(ymap k).25 E(eymap;)-.1 E(int rl_v)108 456 Q -(ariable_bind \(v)-.1 E(ariable, v)-.1 E(alue\))-.1 E(char *v)108 468 Q -(ariable, *v)-.1 E(alue;)-.1 E(int rl_parse_and_bind \(line\))108 484.8 Q -(char *line;)108 496.8 Q(int rl_translate_k)108 513.6 Q(eyseq \(k)-.1 E -(eyseq, array)-.1 E 2.5(,l)-.55 G(en\))276.68 513.6 Q(char *k)108 525.6 Q -(eyseq, *array;)-.1 E(int *len;)108 537.6 Q -(Function *rl_named_function \(command\))108 554.4 Q(char *command;)108 566.4 Q -(Function *rl_function_of_k)108 583.2 Q(eyseq \(k)-.1 E(eyseq, k)-.1 E -(eymap, type\))-.1 E(char *k)108 595.2 Q(eyseq;)-.1 E -.25(Ke)108 607.2 S -(ymap k).25 E(eymap;)-.1 E(int *type;)108 619.2 Q(char **rl_in)108 636 Q -.1 -(vo)-.4 G(king_k).1 E(eyseqs \(function\))-.1 E(Function *function;)108 648 Q -(char **rl_in)108 664.8 Q -.1(vo)-.4 G(king_k).1 E(eyseqs_in_map \(function, k) --.1 E(eymap\))-.1 E(Function *function;)108 676.8 Q -.25(Ke)108 688.8 S(ymap k) -.25 E(eymap;)-.1 E -.1(vo)108 705.6 S(id rl_function_dumper \(r).1 E(eadable\)) --.18 E(int r)108 717.6 Q(eadable;)-.18 E F0 184.005(GNU 1994)72 768 R(July 26) -2.5 E(1)535 768 Q EP -%%Page: 2 2 -%%BeginPageSetup -BP -%%EndPageSetup -/F0 10/Times-Roman@0 SF 342.2(READLINE\(3\) READLINE\(3\))72 48 R/F1 10 -/Times-Bold@0 SF(char **rl_funmap_names \(\))108 84 Q/F2 9/Times-Bold@0 SF -(COPYRIGHT)72 100.8 Q F0(Readline is Cop)108 112.8 Q -(yright \251 1989, 1991 by the Free Softw)-.1 E(are F)-.1 E(oundation, Inc.) --.15 E F2(DESCRIPTION)72 129.6 Q F1 -.18(re)108 141.6 S(adline).18 E F0 .49 -(will read a line from the terminal and return it, using)2.99 F F1(pr)2.99 E -(ompt)-.18 E F0 .49(as a prompt.)2.99 F(If)5.49 E F1(pr)2.99 E(ompt)-.18 E F0 -.49(is null, no)2.99 F 1.066(prompt is issued.)108 153.6 R 1.066 -(The line returned is allocated with)6.066 F/F3 10/Times-Italic@0 SF(malloc) -3.566 E F0 1.067(\(3\), so the caller must free it when \214nished.).31 F -(The line returned has the \214nal ne)108 165.6 Q(wline remo)-.25 E -.15(ve) --.15 G(d, so only the te).15 E(xt of the line remains.)-.15 E F1 -.18(re)108 -182.4 S(adline).18 E F0(of)3.79 E 1.29 -(fers editing capabilities while the user is entering the line.)-.25 F 1.289 -(By def)6.289 F 1.289(ault, the line editing com-)-.1 F -(mands are similar to those of emacs.)108 194.4 Q 2.5(Av)5 G -(i\255style line editing interf)273.53 194.4 Q(ace is also a)-.1 E -.25(va)-.2 -G(ilable.).25 E 6.74(In the follo)108 211.2 R 6.74(wing descriptions,)-.25 F F1 --.1(ke)9.24 G(ymap).1 E F0 6.74(can be one of)9.24 F F3(emacs_k)9.24 E -.3(ey) --.1 G 6.74(map, emacs_meta_k).3 F -.3(ey)-.1 G(map,).3 E(emacs_ctlx_k)108 223.2 -Q -.3(ey)-.1 G(map, vi_insertion_k).3 E -.3(ey)-.1 G(map, or vi_mo).3 E -(vement_k)-.1 E -.3(ey)-.1 G(map).3 E F0(.)A F1(rl_add_defun)108 240 Q F0(mak) -3.356 E(es)-.1 E F1(name)3.356 E F0 .856 -(appear as a bindable readline command, and mak)3.356 F(es)-.1 E F1(function) -3.355 E F0 .855(be the function)3.355 F(called when that command is in)108 252 -Q -.2(vo)-.4 G -.1(ke).2 G 2.5(d. If).1 F F1 -.1(ke)2.5 G(y).1 E F0 -(is not \2551, it is bound to)2.5 E F1(function)2.5 E F0(in the current k)2.5 E --.15(ey)-.1 G(map.).15 E F1(rl_bind_k)108 268.8 Q(ey)-.1 E F0(causes)2.5 E F1 --.1(ke)2.5 G(y).1 E F0(to in)2.5 E -.2(vo)-.4 G -.1(ke).2 G F1(function)2.6 E -F0 5(.T)C(he binding is made in the current k)296.55 268.8 Q -.15(ey)-.1 G -(map.).15 E F1(rl_unbind_k)108 285.6 Q(ey)-.1 E F0(remo)2.5 E -.15(ve)-.15 G -2.5(st).15 G(he binding for)212.06 285.6 Q F1 -.1(ke)2.5 G(y).1 E F0 -(in the current k)2.5 E -.15(ey)-.1 G(map.).15 E F1(rl_bind_k)108 302.4 Q -(ey_in_map)-.1 E F0(mak)2.5 E(es the)-.1 E F1 -.1(ke)2.5 G(y).1 E F0(entry in) -2.5 E F1 -.1(ke)2.5 G(ymap).1 E F0(in)2.5 E -.2(vo)-.4 G -.1(ke).2 G F1 -(function)2.6 E F0(.)A F1(rl_unbind_k)108 319.2 Q(ey_in_map)-.1 E F0(remo)2.5 E --.15(ve)-.15 G 2.5(st).15 G(he binding for)249.29 319.2 Q F1 -.1(ke)2.5 G(y).1 -E F0(in k)2.5 E -.15(ey)-.1 G(map).15 E F1 -.1(ke)2.5 G(ymap).1 E F0(.)A F1 -(rl_macr)108 336 Q(o_bind)-.18 E F0(mak)2.5 E(es)-.1 E F1 -.1(ke)2.5 G(yseq).1 -E F0(insert the string)2.5 E F1(macr)2.5 E(o)-.18 E F0 5(.T)C -(he binding is performed in)338.81 336 Q F1 -.1(ke)2.5 G(ymap).1 E F0(.)A F1 -(rl_v)108 352.8 Q(ariable_bind)-.1 E F0(sets the v)2.5 E -(alue of the readline v)-.25 E(ariable)-.25 E F1 -.1(va)2.5 G(riable).1 E F0 -(to)2.5 E F1 -.1(va)2.5 G(lue).1 E F0(.)A F1(rl_parse_and_bind)108 369.6 Q F0 -(tak)2.806 E .307(es as an ar)-.1 F .307 -(gument a line of the same form as the readline startup \214le \(see)-.18 F F2 -(INITIAL-)2.807 E(IZA)108 381.6 Q(TION FILE)-.855 E F0(belo)2.25 E(w\) and e) --.25 E -.15(xe)-.15 G(cutes the commands therein.).15 E F1(rl_translate_k)108 -398.4 Q(eyseq)-.1 E F0(con)2.975 E -.15(ve)-.4 G(rts).15 E F1 -.1(ke)2.975 G -(yseq).1 E F0 .475(into a ne)2.975 F 2.975(ws)-.25 G .475 -(tring, storing the result in)312.05 398.4 R F1(array)2.975 E F0 5.475(.T)C -.475(his translates control)456.28 398.4 R .337(and meta pre\214x)108 410.4 R -.337(es and the readline character escape sequences \(see)-.15 F F2 -.225(Ke) -2.837 G 2.587(yB).225 G(indings)404.423 410.4 Q F0(belo)2.588 E 2.838(w\). The) --.25 F .338(length of the)2.838 F(translated sequence is returned in)108 422.4 -Q F1(*len)2.5 E F0(.)A F1(rl_named_function)108 439.2 Q F0 2.974 -(returns the function that is e)5.474 F -.15(xe)-.15 G 2.973 -(cuted when the readline command).15 F F1(command)5.473 E F0(is)5.473 E(in)108 -451.2 Q -.2(vo)-.4 G -.1(ke).2 G(d.).1 E F1(rl_function_of_k)108 468 Q(eyseq) --.1 E F0 .801(returns the function that is e)3.301 F -.15(xe)-.15 G .801 -(cuted when).15 F F1 -.1(ke)3.301 G(yseq).1 E F0 .801(is read and)3.301 F F1 --.1(ke)3.302 G(ymap).1 E F0 .802(is the cur)3.302 F(-)-.2 E .267(rent k)108 480 -R -.15(ey)-.1 G(map.).15 E F1(type)5.267 E F0 .267 -(is set to indicate whether the return v)2.767 F .266 -(alue corresponds to a function, macro, or auxiliary)-.25 F -.1(ke)108 492 S -(ymap.)-.05 E F1(rl_in)108 508.8 Q -.1(vo)-.4 G(king_k).1 E(eyseqs)-.1 E F0 -(returns all of the k)2.5 E .3 -.15(ey s)-.1 H(equences in the current k).15 E --.15(ey)-.1 G(map that in).15 E -.2(vo)-.4 G -.1(ke).2 G F1(function)2.6 E F0 -(.)A F1(rl_in)108 525.6 Q -.1(vo)-.4 G(king_k).1 E(eyseqs_in_map)-.1 E F0 -(returns all of the k)2.5 E .3 -.15(ey s)-.1 H(equences in).15 E F1 -.1(ke)2.5 -G(ymap).1 E F0(that in)2.5 E -.2(vo)-.4 G -.1(ke).2 G F1(function)2.6 E F0(.)A -F1(rl_function_dumper)108 542.4 Q F0 .117(prints all of the readline functions\ - and their bindings to the readline output stream.)2.617 F(If)5.118 E F1 -.18 -(re)108 554.4 S(adable).18 E F0(is non\255zero, the output is formattted so th\ -at it can be read back in to restore the bindings.)2.5 E F1(rl_funmap_names)108 -571.2 Q F0(returns an array of all kno)2.5 E -(wn readline bindable function names.)-.25 E(The array is sorted.)5 E F2 -(RETURN V)72 588 Q(ALUE)-1.215 E F1 -.18(re)108 600 S(adline).18 E F0 1.09 -(returns the te)3.59 F 1.09(xt of the line read.)-.15 F 3.589(Ab)6.09 G 1.089 -(lank line returns the empty string.)299.949 600 R(If)6.089 E F1(EOF)3.589 E F0 -1.089(is encountered)3.589 F .283(while reading a line, and the line is empty) -108 612 R(,)-.65 E F1(NULL)2.783 E F0 .283(is returned.)2.783 F .283(If an) -5.283 F F1(EOF)2.783 E F0 .283(is read with a non\255empty line, it)2.783 F -(is treated as a ne)108 624 Q(wline.)-.25 E(Unless otherwise stated, the other\ - functions return 0 on success and non\255zero on f)108 640.8 Q(ailure.)-.1 E -F2(NO)72 657.6 Q -.81(TA)-.36 G(TION)-.045 E F0 .037 -(An emacs\255style notation is used to denote k)108 669.6 R -.15(ey)-.1 G -(strok).15 E 2.536(es. Control)-.1 F -.1(ke)2.536 G .036 -(ys are denoted by C\255)-.05 F F3 -.1(ke)C(y)-.2 E F0 2.536(,e)C .036 -(.g., C\255n means)479.568 669.6 R 2.625(Control\255N. Similarly)108 681.6 R(,) --.65 E F3(meta)2.625 E F0 -.1(ke)2.625 G .125(ys are denoted by M\255)-.05 F F3 --.1(ke)C(y)-.2 E F0 2.625(,s)C 2.625(oM)341.73 681.6 S .125 -(\255x means Meta\255X.)358.245 681.6 R .126(\(On k)5.126 F -.15(ey)-.1 G .126 -(boards without a).15 F F3(meta)108 693.6 Q F0 -.1(ke)3.309 G 2.109 -.65(y, M) --.05 H.65 E F3(x)A F0 .809(means ESC)3.309 F F3(x)3.309 E F0 3.309(,i)C -.809(.e., press the Escape k)235.914 693.6 R 1.108 -.15(ey t)-.1 H .808 -(hen the).15 F F3(x)3.308 E F0 -.1(ke)3.308 G 4.608 -.65(y. T)-.05 H .808 -(his mak).65 F .808(es ESC the)-.1 F F3 .808(meta pr)3.308 F(e\214x)-.37 E F0 -(.)A .48(The combination M\255C\255)108 705.6 R F3(x)A F0 .48 -(means ESC\255Control\255)2.98 F F3(x)A F0 2.98(,o)C 2.98(rp)317.4 705.6 S .48 -(ress the Escape k)328.71 705.6 R .78 -.15(ey t)-.1 H .48 -(hen hold the Control k).15 F .78 -.15(ey w)-.1 H(hile).15 E(pressing the)108 -717.6 Q F3(x)2.5 E F0 -.1(ke)2.5 G -.65(y.)-.05 G(\)).65 E 184.005(GNU 1994)72 -768 R(July 26)2.5 E(2)535 768 Q EP -%%Page: 3 3 -%%BeginPageSetup -BP -%%EndPageSetup -/F0 10/Times-Roman@0 SF 342.2(READLINE\(3\) READLINE\(3\))72 48 R .62 -(Readline commands may be gi)108 84 R -.15(ve)-.25 G 3.119(nn).15 G(umeric) -255.959 84 Q/F1 10/Times-Italic@0 SF(ar)3.119 E(guments)-.37 E F0 3.119(,w).27 -G .619(hich normally act as a repeat count.)341.807 84 R(Sometimes,)5.619 E(ho) -108 96 Q(we)-.25 E -.15(ve)-.25 G 1.418 -.4(r, i).15 H 3.118(ti).4 G 3.119(st) -158.456 96 S .619(he sign of the ar)168.245 96 R .619 -(gument that is signi\214cant.)-.18 F -.15(Pa)5.619 G .619(ssing a ne).15 F --.05(ga)-.15 G(ti).05 E .919 -.15(ve a)-.25 H -.18(rg).15 G .619 -(ument to a command that).18 F 1.019(acts in the forw)108 108 R 1.018 -(ard direction \(e.g.,)-.1 F/F2 10/Times-Bold@0 SF(kill\255line)3.518 E F0 -3.518(\)c)C 1.018(auses that command to act in a backw)298.478 108 R 1.018 -(ard direction.)-.1 F(Com-)6.018 E(mands whose beha)108 120 Q(vior with ar)-.2 -E(guments de)-.18 E(viates from this are noted.)-.25 E .811 -(When a command is described as)108 136.8 R F1(killing)3.311 E F0(te)3.311 E -.811(xt, the te)-.15 F .811(xt deleted is sa)-.15 F -.15(ve)-.2 G 3.311(df).15 -G .812(or possible future retrie)403.403 136.8 R -.25(va)-.25 G 3.312(l\().25 G -F1(yank-)517.79 136.8 Q(ing)108 148.8 Q F0 3.439(\). The)B .939(killed te)3.439 -F .939(xt is sa)-.15 F -.15(ve)-.2 G 3.439(di).15 G 3.438(na)234.794 148.8 S F1 -(kill\255ring)A F0 5.938(.C)C(onsecuti)302.418 148.8 Q 1.238 -.15(ve k)-.25 H -.938(ills cause the te).15 F .938(xt to be accumulated into one)-.15 F .331 -(unit, which can be yank)108 160.8 R .331(ed all at once.)-.1 F .331 -(Commands which do not kill te)5.331 F .331(xt separate the chunks of te)-.15 F -.331(xt on the)-.15 F(kill\255ring.)108 172.8 Q/F3 9/Times-Bold@0 SF -(INITIALIZA)72 189.6 Q(TION FILE)-.855 E F0 .827 -(Readline is customized by putting commands in an initialization \214le.)108 -201.6 R .827(The name of this \214le is tak)5.827 F .827(en from)-.1 F 1.041 -(the v)108 213.6 R 1.041(alue of the)-.25 F F2(INPUTRC)3.541 E F0 -.25(va)3.542 -G 3.542(riable. If).25 F 1.042(that v)3.542 F 1.042(ariable is unset, the def) --.25 F 1.042(ault is)-.1 F F1(~/.inputr)3.542 E(c)-.37 E F0 6.042(.W).31 G -1.042(hen a program)480.156 213.6 R 1.159 -(which uses the readline library starts up, the init \214le is read, and the k) -108 225.6 R 1.458 -.15(ey b)-.1 H 1.158(indings and v).15 F 1.158 -(ariables are set.)-.25 F .028(There are only a fe)108 237.6 R 2.528(wb)-.25 G -.028(asic constructs allo)198.13 237.6 R .028(wed in the readline init \214le.) --.25 F .029(Blank lines are ignored.)5.029 F .029(Lines be)5.029 F(gin-)-.15 E -.554(ning with a)108 249.6 R F2(#)3.054 E F0 .554(are comments.)3.054 F .554 -(Lines be)5.554 F .554(ginning with a)-.15 F F2($)3.054 E F0 .554 -(indicate conditional constructs.)3.054 F .553(Other lines denote)5.553 F -.1 -(ke)108 261.6 S 2.986(yb)-.05 G .486(indings and v)130.176 261.6 R .487 -(ariable settings.)-.25 F .487(Each program using this library may add its o) -5.487 F .487(wn commands and bind-)-.25 F(ings.)108 273.6 Q -.15(Fo)108 290.4 S -2.5(re).15 G(xample, placing)128.53 290.4 Q(M\255Control\255u: uni)144 307.2 Q --.15(ve)-.25 G(rsal\255ar).15 E(gument)-.18 E(or)108 319.2 Q -(C\255Meta\255u: uni)144 331.2 Q -.15(ve)-.25 G(rsal\255ar).15 E(gument)-.18 E -(into the)108 343.2 Q F1(~/.inputr)4.166 E(c)-.37 E F0 -.1(wo)4.166 G(uld mak) -.1 E 2.5(eM)-.1 G(\255C\255u e)244.092 343.2 Q -.15(xe)-.15 G -(cute the readline command).15 E F1(univer)2.5 E(sal\255ar)-.1 E(gument)-.37 E -F0(.).68 E .978(The follo)108 360 R .978 -(wing symbolic character names are recognized while processing k)-.25 F 1.277 --.15(ey b)-.1 H(indings:).15 E F1 -.4(RU)3.477 G(BOUT).4 E F0(,)1.27 E F1(DEL) -3.477 E F0(,).53 E F1(ESC)108 372 Q F0(,).72 E F1(LFD)2.984 E F0(,).28 E F1 -(NEWLINE)2.984 E F0(,).73 E F1(RET)2.984 E F0(,)1.27 E F1(RETURN)2.984 E F0(,) -1.1 E F1(SPC)2.984 E F0(,).72 E F1(SP)2.984 E -.3(AC)-.9 G(E).3 E F0 2.984(,a) -.73 G(nd)337.968 372 Q F1 -.5(TA)2.984 G(B).5 E F0 5.484(.I).27 G 2.984(na) -379.816 372 S .485(ddition to command names, readline)392.24 372 R(allo)108 384 -Q(ws k)-.25 E -.15(ey)-.1 G 2.5(st).15 G 2.5(ob)159.72 384 S 2.5(eb)172.22 384 -S(ound to a string that is inserted when the k)184.16 384 Q .3 -.15(ey i)-.1 H -2.5(sp).15 G(ressed \(a)379.73 384 Q F1(macr)2.5 E(o)-.45 E F0(\).)A F2 -.25 -(Ke)87 405.6 S 2.5(yB).25 G(indings)113.14 405.6 Q F0 .724 -(The syntax for controlling k)108 417.6 R 1.024 -.15(ey b)-.1 H .724 -(indings in the).15 F F1(~/.inputr)3.224 E(c)-.37 E F0 .724(\214le is simple.) -3.224 F .723(All that is required is the name of)5.724 F .938 -(the command or the te)108 429.6 R .938(xt of a macro and a k)-.15 F 1.238 -.15 -(ey s)-.1 H .938(equence to which it should be bound. The name may be).15 F -.695(speci\214ed in one of tw)108 441.6 R 3.195(ow)-.1 G .695 -(ays: as a symbolic k)212.095 441.6 R .995 -.15(ey n)-.1 H .695 -(ame, possibly with).15 F F1(Meta\255)3.195 E F0(or)3.195 E F1(Contr)3.194 E -(ol\255)-.45 E F0(pre\214x)3.194 E .694(es, or as a)-.15 F -.1(ke)108 453.6 S -4.143(ys)-.05 G 4.143(equence. When)130.223 453.6 R 1.643(using the form)4.143 -F F2 -.1(ke)4.143 G(yname).1 E F0(:)A F1(function-name)A F0(or)4.143 E F1(macr) -4.143 E(o)-.45 E F0(,)A F1 -.1(ke)4.143 G(yname)-.2 E F0 1.644 -(is the name of a k)4.143 F -.15(ey)-.1 G(spelled out in English.)108 465.6 Q --.15(Fo)5 G 2.5(re).15 G(xample:)222.98 465.6 Q(Control\255u: uni)144 489.6 Q --.15(ve)-.25 G(rsal\255ar).15 E(gument)-.18 E(Meta\255Rubout: backw)144 501.6 Q -(ard\255kill\255w)-.1 E(ord)-.1 E(Control\255o: ">&output")144 513.6 Q .229 -(In the abo)108 530.4 R .529 -.15(ve ex)-.15 H(ample,).15 E F1(C\255u)2.729 E -F0 .229(is bound to the function)2.729 F F2(uni)2.729 E -.1(ve)-.1 G -(rsal\255ar).1 E(gument)-.1 E F0(,)A F1(M-DEL)2.729 E F0 .228 -(is bound to the function)2.729 F F2(backward\255kill\255w)108 542.4 Q(ord)-.1 -E F0 3.837(,a)C(nd)208.977 542.4 Q F1(C\255o)3.837 E F0 1.337 -(is bound to run the macro e)3.837 F 1.337 -(xpressed on the right hand side \(that is, to)-.15 F(insert the te)108 554.4 Q -(xt)-.15 E F1(>&output)2.5 E F0(into the line\).)2.5 E .115 -(In the second form,)108 571.2 R F2("k)2.615 E(eyseq")-.1 E F0(:)A F1 -(function\255name)A F0(or)2.615 E F1(macr)2.615 E(o)-.45 E F0(,)A F2 -.1(ke) -2.615 G(yseq).1 E F0(dif)2.615 E .115(fers from)-.25 F F2 -.1(ke)2.615 G(yname) -.1 E F0(abo)2.615 E .415 -.15(ve i)-.15 H 2.615(nt).15 G .115(hat strings) -498.495 571.2 R 1.284(denoting an entire k)108 583.2 R 1.584 -.15(ey s)-.1 H -1.284(equence may be speci\214ed by placing the sequence within double quotes.) -.15 F(Some)6.284 E(GNU Emacs style k)108 595.2 Q .3 -.15(ey e)-.1 H -(scapes can be used, as in the follo).15 E(wing e)-.25 E(xample.)-.15 E -("\\C\255u": uni)144 619.2 Q -.15(ve)-.25 G(rsal\255ar).15 E(gument)-.18 E -("\\C\255x\\C\255r": re\255read\255init\255\214le)144 631.2 Q -("\\e[11~": "Function K)144 643.2 Q .3 -.15(ey 1)-.25 H(").15 E .238(In this e) -108 660 R(xample,)-.15 E F1(C-u)2.738 E F0 .238(is ag)2.738 F .238 -(ain bound to the function)-.05 F F2(uni)2.738 E -.1(ve)-.1 G(rsal\255ar).1 E -(gument)-.1 E F0(.)A F1 .237(C-x C-r)5.238 F F0 .237(is bound to the function) -2.737 F F2 -.18(re)108 672 S.18 E(ead\255init\255\214le)-.18 E F0 3.909 -(,a)C(nd)191.139 672 Q F1 1.409(ESC [ 1 1 ~)3.909 F F0 1.409 -(is bound to insert the te)3.909 F(xt)-.15 E F2 1.41(Function K)3.91 F 1.41 -(ey 1)-.25 F F0 6.41(.T)C 1.41(he full set of escape)454.94 672 R(sequences is) -108 684 Q F2(\\C-)144 700.8 Q F0(control pre\214x)180 700.8 Q F2(\\M-)144 717.6 -Q F0(meta pre\214x)180 717.6 Q 184.005(GNU 1994)72 768 R(July 26)2.5 E(3)535 -768 Q EP -%%Page: 4 4 -%%BeginPageSetup -BP -%%EndPageSetup -/F0 10/Times-Roman@0 SF 342.2(READLINE\(3\) READLINE\(3\))72 48 R/F1 10 -/Times-Bold@0 SF(\\e)144 84 Q F0(an escape character)180 84 Q F1(\\\\)144 100.8 -Q F0(backslash)180 100.8 Q F1(\\")144 117.6 Q F0(literal ")180 117.6 Q F1(\\') -144 134.4 Q F0(literal ')180 134.4 Q .74(When entering the te)108 151.2 R .74(\ -xt of a macro, single or double quotes should be used to indicate a macro de\ -\214nition.)-.15 F 1.226(Unquoted te)108 163.2 R 1.226 -(xt is assumed to be a function name.)-.15 F 1.227(Backslash will quote an) -6.226 F 3.727(yc)-.15 G 1.227(haracter in the macro te)430.552 163.2 R(xt,)-.15 -E(including " and '.)108 175.2 Q F1(Bash)108 192 Q F0(allo)2.93 E .43 -(ws the current readline k)-.25 F .73 -.15(ey b)-.1 H .429 -(indings to be displayed or modi\214ed with the).15 F F1(bind)2.929 E F0 -.2 -(bu)2.929 G .429(iltin command.).2 F 1.095 -(The editing mode may be switched during interacti)108 204 R 1.395 -.15(ve u) --.25 H 1.095(se by using the).15 F F13.595 E F0 1.095(option to the)3.595 -F F1(set)3.595 E F0 -.2(bu)3.595 G 1.095(iltin com-).2 F 3.097(mand. Other)108 -216 R .597(programs using this library pro)3.097 F .597 -(vide similar mechanisms.)-.15 F(The)5.597 E/F2 10/Times-Italic@0 SF(inputr) -3.097 E(c)-.37 E F0 .596(\214le may be edited and)3.096 F -(re\255read if a program does not pro)108 228 Q(vide an)-.15 E 2.5(yo)-.15 G -(ther means to incorporate ne)283.85 228 Q 2.5(wb)-.25 G(indings.)412.18 228 Q -F1 -.92(Va)87 244.8 S(riables).92 E F0 .043(Readline has v)108 256.8 R .044 -(ariables that can be used to further customize its beha)-.25 F(vior)-.2 E -5.044(.A)-.55 G -.25(va)413.896 256.8 S .044(riable may be set in the).25 F F2 -(inpu-)2.544 E(tr)108 268.8 Q(c)-.37 E F0(\214le with a statement of the form) -2.5 E F1(set)144 285.6 Q F2(variable\255name value)2.5 E F0 .489 -(Except where noted, readline v)108 302.4 R .489(ariables can tak)-.25 F 2.989 -(et)-.1 G .489(he v)307.123 302.4 R(alues)-.25 E F1(On)2.989 E F0(or)2.989 E F1 -(Off)2.989 E F0 5.489(.T)C .489(he v)404.028 302.4 R .488 -(ariables and their def)-.25 F .488(ault v)-.1 F(al-)-.25 E(ues are:)108 314.4 -Q F1(horizontal\255scr)108 331.2 Q(oll\255mode \(Off\))-.18 E F0 .448 -(When set to)144 343.2 R F1(On)2.948 E F0 2.948(,m)C(ak)222.182 343.2 Q .448 -(es readline use a single line for display)-.1 F 2.948(,s)-.65 G .449 -(crolling the input horizontally on a)398.596 343.2 R 1.194(single screen line\ - when it becomes longer than the screen width rather than wrapping to a ne)144 -355.2 R(w)-.25 E(line.)144 367.2 Q F1(editing\255mode \(emacs\))108 379.2 Q F0 -.252(Controls whether readline be)144 391.2 R .253(gins with a set of k)-.15 F -.553 -.15(ey b)-.1 H .253(indings similar to).15 F F2(emacs)2.753 E F0(or)2.753 -E F2(vi)2.753 E F0(.)A F1(editing\255mode)5.253 E F0(can be set to either)144 -403.2 Q F1(emacs)2.5 E F0(or)2.5 E F1(vi)2.5 E F0(.)A F1 -(mark\255modi\214ed\255lines \(Off\))108 415.2 Q F0(If set to)144 427.2 Q F1 -(On)2.5 E F0 2.5(,h)C(istory lines that ha)200.39 427.2 Q .3 -.15(ve b)-.2 H -(een modi\214ed are displayed with a preceding asterisk \().15 E F1(*)A F0(\).) -A F1(bell\255style \(audible\))108 439.2 Q F0 .011 -(Controls what happens when readline w)144 451.2 R .011 -(ants to ring the terminal bell.)-.1 F .01(If set to)5.01 F F1(none)2.51 E F0 -2.51(,r)C .01(eadline ne)486.8 451.2 R -.15(ve)-.25 G(r).15 E .94 -(rings the bell.)144 463.2 R .94(If set to)5.94 F F1(visible)3.44 E F0 3.44(,r) -C .94(eadline uses a visible bell if one is a)278.91 463.2 R -.25(va)-.2 G 3.44 -(ilable. If).25 F .94(set to)3.44 F F1(audible)3.44 E F0(,)A -(readline attempts to ring the terminal')144 475.2 Q 2.5(sb)-.55 G(ell.)306.21 -475.2 Q F1(comment\255begin \(`)108 487.2 Q(`#')-.63 E('\))-.63 E F0 -(The string that is inserted in)144 499.2 Q F1(vi)2.5 E F0(mode when the)2.5 E -F1(vi\255comment)2.5 E F0(command is e)2.5 E -.15(xe)-.15 G(cuted.).15 E F1 -(meta\255\215ag \(Off\))108 511.2 Q F0 .228(If set to)144 523.2 R F1(On)2.728 E -F0 2.728(,r)C .227(eadline will enable eight-bit input \(that is, it will not \ -strip the high bit from the char)199.632 523.2 R(-)-.2 E(acters it reads\), re) -144 535.2 Q -.05(ga)-.15 G(rdless of what the terminal claims it can support.) -.05 E F1(con)108 547.2 Q -.1(ve)-.4 G(rt\255meta \(On\)).1 E F0 .612(If set to) -144 559.2 R F1(On)3.112 E F0 3.112(,r)C .613(eadline will con)201.168 559.2 R --.15(ve)-.4 G .613(rt characters with the eighth bit set to an ASCII k).15 F -.913 -.15(ey s)-.1 H .613(equence by).15 F 1.238 -(stripping the eighth bit and prepending an escape character \(in ef)144 571.2 -R 1.238(fect, using escape as the)-.25 F F2(meta)3.738 E(pr)144 583.2 Q(e\214x) --.37 E F0(\).)A F1(output\255meta \(Off\))108 595.2 Q F0 .506(If set to)144 -607.2 R F1(On)3.006 E F0 3.006(,r)C .507(eadline will display characters with \ -the eighth bit set directly rather than as a meta-)200.744 607.2 R(pre\214x)144 -619.2 Q(ed escape sequence.)-.15 E F1(completion\255query\255items \(100\))108 -631.2 Q F0 .53(This determines when the user is queried about vie)144 643.2 R -.529(wing the number of possible completions gen-)-.25 F .56(erated by the)144 -655.2 R F1(possible\255completions)3.06 E F0 3.06(command. It)3.06 F .561 -(may be set to an)3.061 F 3.061(yi)-.15 G(nte)428.196 655.2 Q .561(ger v)-.15 F -.561(alue greater than or)-.25 F .783(equal to zero.)144 667.2 R .783 -(If the number of possible completions is greater than or equal to the v)5.783 -F .782(alue of this)-.25 F -.25(va)144 679.2 S .237(riable, the user is ask).25 -F .237(ed whether or not he wishes to vie)-.1 F 2.737(wt)-.25 G .237 -(hem; otherwise the)389.254 679.2 R 2.737(ya)-.15 G .237(re simply listed) -477.855 679.2 R(on the terminal.)144 691.2 Q F1 -.1(ke)108 703.2 S -(ymap \(emacs\)).1 E F0 2.323(Set the current readline k)144 715.2 R -.15(ey) --.1 G 4.823(map. The).15 F 2.323(set of le)4.823 F -.05(ga)-.15 G 4.823(lk).05 -G -.15(ey)368.478 715.2 S 2.323(map names is).15 F F2 2.323 -(emacs, emacs-standar)4.823 F(d,)-.37 E .808(emacs-meta, emacs-ctlx, vi, vi-mo) -144 727.2 R(ve)-.1 E 3.308(,v)-.1 G(i-command)300.862 727.2 Q F0 3.308(,a)C(nd) -356.1 727.2 Q F2(vi-insert)3.308 E F0(.).68 E F2(vi)5.808 E F0 .808(is equi) -3.308 F -.25(va)-.25 G .809(lent to).25 F F2(vi-command)3.309 E F0(;)A 184.005 -(GNU 1994)72 768 R(July 26)2.5 E(4)535 768 Q EP -%%Page: 5 5 -%%BeginPageSetup -BP -%%EndPageSetup -/F0 10/Times-Roman@0 SF 342.2(READLINE\(3\) READLINE\(3\))72 48 R/F1 10 -/Times-Italic@0 SF(emacs)144 84 Q F0 1.124(is equi)3.624 F -.25(va)-.25 G 1.124 -(lent to).25 F F1(emacs-standar)3.624 E(d)-.37 E F0 6.124(.T)C 1.124(he def) -317.34 84 R 1.124(ault v)-.1 F 1.124(alue is)-.25 F F1(emacs)3.624 E F0 3.624 -(;t).27 G 1.124(he v)431.47 84 R 1.123(alue of)-.25 F/F2 10/Times-Bold@0 SF -(editing\255mode)3.623 E F0(also af)144 96 Q(fects the def)-.25 E(ault k)-.1 E --.15(ey)-.1 G(map.).15 E F2(sho)108 108 Q(w\255all\255if\255ambiguous \(Off\)) --.1 E F0 .477(This alters the def)144 120 R .477(ault beha)-.1 F .477 -(vior of the completion functions.)-.2 F .478(If set to)5.478 F F2(on)2.978 E -F0 2.978(,w)C .478(ords which ha)450.326 120 R .778 -.15(ve m)-.2 H(ore).15 E -1.264(than one possible completion cause the matches to be listed immediately \ -instead of ringing the)144 132 R(bell.)144 144 Q F2(expand\255tilde \(Off\))108 -156 Q F0(If set to)144 168 Q F2(on)2.5 E F0 2.5(,t)C(ilde e)195.39 168 Q -(xpansion is performed when readline attempts w)-.15 E(ord completion.)-.1 E F2 -(Conditional Constructs)87 184.8 Q F0 .05(Readline implements a f)108 196.8 R -.05(acility similar in spirit to the conditional compilation features of the C\ - preprocessor)-.1 F 1.49(which allo)108 208.8 R 1.49(ws k)-.25 F 1.79 -.15 -(ey b)-.1 H 1.49(indings and v).15 F 1.49 -(ariable settings to be performed as the result of tests.)-.25 F 1.49 -(There are three)6.49 F(parser directi)108 220.8 Q -.15(ve)-.25 G 2.5(su).15 G -(sed.)180.91 220.8 Q F2($if)108 237.6 Q F0(The)144 237.6 Q F2($if)2.962 E F0 -.462(construct allo)2.962 F .463 -(ws bindings to be made based on the editing mode, the terminal being used,) --.25 F .478(or the application using readline.)144 249.6 R .477(The te)5.477 F -.477(xt of the test e)-.15 F .477(xtends to the end of the line; no characters) --.15 F(are required to isolate it.)144 261.6 Q F2(mode)144 278.4 Q F0(The)180 -278.4 Q F2(mode=)3.711 E F0 1.211(form of the)3.711 F F2($if)3.711 E F0 -(directi)3.711 E 1.511 -.15(ve i)-.25 H 3.711(su).15 G 1.211 -(sed to test whether readline is in emacs or vi)351.628 278.4 R 3.065 -(mode. This)180 290.4 R .565(may be used in conjunction with the)3.065 F F2 -.565(set k)3.065 F(eymap)-.1 E F0 .565(command, for instance, to)3.065 F .029 -(set bindings in the)180 302.4 R F1(emacs-standar)2.529 E(d)-.37 E F0(and)2.529 -E F1(emacs-ctlx)2.529 E F0 -.1(ke)2.529 G .029 -(ymaps only if readline is starting out)-.05 F(in emacs mode.)180 314.4 Q F2 -(term)144 331.2 Q F0(The)180 331.2 Q F2(term=)3.197 E F0 .696 -(form may be used to include terminal-speci\214c k)3.197 F .996 -.15(ey b)-.1 H -.696(indings, perhaps to bind).15 F .654(the k)180 343.2 R .954 -.15(ey s)-.1 H -.654(equences output by the terminal').15 F 3.154(sf)-.55 G .654(unction k) -360.138 343.2 R -.15(ey)-.1 G 3.154(s. The).15 F -.1(wo)3.154 G .654 -(rd on the right side of).1 F(the)180 355.2 Q F2(=)3.004 E F0 .504 -(is tested ag)3.004 F .503 -(ainst the full name of the terminal and the portion of the terminal name)-.05 -F(before the \214rst)180 367.2 Q F22.5 E F0 5(.T)C(his allo)260.13 367.2 Q -(ws)-.25 E F1(sun)2.5 E F0(to match both)2.5 E F1(sun)2.5 E F0(and)2.5 E F1 -(sun\255cmd)2.5 E F0 2.5(,f).77 G(or instance.)456.28 367.2 Q F2(application) -144 384 Q F0(The)180 396 Q F2(application)2.772 E F0 .272 -(construct is used to include application\255speci\214c settings.)2.772 F .272 -(Each program)5.272 F .114(using the readline library sets the)180 408 R F1 -.114(application name)2.614 F F0 2.614(,a)C .114 -(nd an initialization \214le can test for a)395.052 408 R .5(particular v)180 -420 R 3(alue. This)-.25 F .501(could be used to bind k)3 F .801 -.15(ey s)-.1 H -.501(equences to functions useful for a spe-).15 F .397(ci\214c program.)180 -432 R -.15(Fo)5.397 G 2.896(ri).15 G .396(nstance, the follo)261.31 432 R .396 -(wing command adds a k)-.25 F .696 -.15(ey s)-.1 H .396 -(equence that quotes the).15 F(current or pre)180 444 Q(vious w)-.25 E -(ord in Bash:)-.1 E F2($if)180 456 Q F0(bash)2.5 E 2.5(#Q)180 468 S -(uote the current or pre)194.72 468 Q(vious w)-.25 E(ord)-.1 E -("\\C-xq": "\\eb\\"\\ef\\"")180 480 Q F2($endif)180 492 Q($endif)108 508.8 Q F0 -(This command, as you sa)9.33 E 2.5(wi)-.15 G 2.5(nt)257.73 508.8 S(he pre) -268.01 508.8 Q(vious e)-.25 E(xample, terminates an)-.15 E F2($if)2.5 E F0 -(command.)2.5 E F2($else)108 525.6 Q F0(Commands in this branch of the)144 -525.6 Q F2($if)2.5 E F0(directi)2.5 E .3 -.15(ve a)-.25 H(re e).15 E -.15(xe) --.15 G(cuted if the test f).15 E(ails.)-.1 E/F3 9/Times-Bold@0 SF -(EDITING COMMANDS)72 542.4 Q F0 1.391(The follo)108 554.4 R 1.391 -(wing is a list of the names of the commands and the def)-.25 F 1.391(ault k) --.1 F 1.691 -.15(ey s)-.1 H 1.391(equences to which the).15 F 3.892(ya)-.15 G -(re)532.23 554.4 Q(bound.)108 566.4 Q F2(Commands f)87 583.2 Q(or Mo)-.25 E -(ving)-.1 E(beginning\255of\255line \(C\255a\))108 595.2 Q F0(Mo)144 607.2 Q .3 --.15(ve t)-.15 H 2.5(ot).15 G(he start of the current line.)182.59 607.2 Q F2 -(end\255of\255line \(C\255e\))108 619.2 Q F0(Mo)144 631.2 Q .3 -.15(ve t)-.15 H -2.5(ot).15 G(he end of the line.)182.59 631.2 Q F2 -.25(fo)108 643.2 S -(rward\255char \(C\255f\)).25 E F0(Mo)144 655.2 Q .3 -.15(ve f)-.15 H(orw).15 E -(ard a character)-.1 E(.)-.55 E F2(backward\255char \(C\255b\))108 667.2 Q F0 -(Mo)144 679.2 Q .3 -.15(ve b)-.15 H(ack a character).15 E(.)-.55 E F2 -.25(fo) -108 691.2 S(rward\255w).25 E(ord \(M\255f\))-.1 E F0(Mo)144 703.2 Q .823 -.15 -(ve f)-.15 H(orw).15 E .523(ard to the end of the ne)-.1 F .523(xt w)-.15 F -3.023(ord. W)-.1 F .522(ords are composed of alphanumeric characters \(let-)-.8 -F(ters and digits\).)144 715.2 Q 184.005(GNU 1994)72 768 R(July 26)2.5 E(5)535 -768 Q EP -%%Page: 6 6 -%%BeginPageSetup -BP -%%EndPageSetup -/F0 10/Times-Roman@0 SF 342.2(READLINE\(3\) READLINE\(3\))72 48 R/F1 10 -/Times-Bold@0 SF(backward\255w)108 84 Q(ord \(M\255b\))-.1 E F0(Mo)144 96 Q -.748 -.15(ve b)-.15 H .449(ack to the start of this, or the pre).15 F .449 -(vious, w)-.25 F 2.949(ord. W)-.1 F .449 -(ords are composed of alphanumeric char)-.8 F(-)-.2 E -(acters \(letters and digits\).)144 108 Q F1(clear\255scr)108 120 Q -(een \(C\255l\))-.18 E F0 .993(Clear the screen lea)144 132 R .993 -(ving the current line at the top of the screen.)-.2 F -.4(Wi)5.993 G .993 -(th an ar).4 F .993(gument, refresh the)-.18 F -(current line without clearing the screen.)144 144 Q F1 -.18(re)108 156 S -(draw\255curr).18 E(ent\255line)-.18 E F0(Refresh the current line.)144 168 Q -(By def)5 E(ault, this is unbound.)-.1 E F1(Commands f)87 184.8 Q -(or Manipulating the History)-.25 E(accept\255line \(Newline, Retur)108 196.8 Q -(n\))-.15 E F0 .857(Accept the line re)144 208.8 R -.05(ga)-.15 G .857 -(rdless of where the cursor is.).05 F .857(If this line is non\255empty)5.857 F -3.357(,a)-.65 G .858(dd it to the history)463.228 208.8 R(list. If the line is\ - a modi\214ed history line, then restore the history line to its original stat\ -e.)144 220.8 Q F1(pr)108 232.8 Q -.15(ev)-.18 G(ious\255history \(C\255p\)).15 -E F0(Fetch the pre)144 244.8 Q(vious command from the history list, mo)-.25 E -(ving back in the list.)-.15 E F1(next\255history \(C\255n\))108 256.8 Q F0 -(Fetch the ne)144 268.8 Q(xt command from the history list, mo)-.15 E -(ving forw)-.15 E(ard in the list.)-.1 E F1 -(beginning\255of\255history \(M\255<\))108 280.8 Q F0(Mo)144 292.8 Q .3 -.15 -(ve t)-.15 H 2.5(ot).15 G(he \214rst line in the history)182.59 292.8 Q(.)-.65 -E F1(end\255of\255history \(M\255>\))108 304.8 Q F0(Mo)144 316.8 Q .3 -.15 -(ve t)-.15 H 2.5(ot).15 G(he end of the input history)182.59 316.8 Q 2.5(,i) --.65 G(.e., the line currently being entered.)294.99 316.8 Q F1 -2.29 -.18 -(re v)108 328.8 T(erse\255sear).08 E(ch\255history \(C\255r\))-.18 E F0 1.471 -(Search backw)144 340.8 R 1.471(ard starting at the current line and mo)-.1 F -1.47(ving `up' through the history as necessary)-.15 F(.)-.65 E -(This is an incremental search.)144 352.8 Q F1 -.25(fo)108 364.8 S -(rward\255sear).25 E(ch\255history \(C\255s\))-.18 E F0 1.131(Search forw)144 -376.8 R 1.131(ard starting at the current line and mo)-.1 F 1.132(ving `do)-.15 -F 1.132(wn' through the history as necessary)-.25 F(.)-.65 E -(This is an incremental search.)144 388.8 Q F1(non\255incr)108 400.8 Q -(emental\255r)-.18 E -2.3 -.15(ev e)-.18 H(rse\255sear).15 E -(ch\255history \(M\255p\))-.18 E F0 1.089(Search backw)144 412.8 R 1.088(ard t\ -hrough the history starting at the current line using a non\255incremental sea\ -rch)-.1 F(for a string supplied by the user)144 424.8 Q(.)-.55 E F1 -(non\255incr)108 436.8 Q(emental\255f)-.18 E(orward\255sear)-.25 E -(ch\255history \(M\255n\))-.18 E F0 1.188(Search forw)144 448.8 R 1.189(ard th\ -rough the history using a non\255incremental search for a string supplied by t\ -he)-.1 F(user)144 460.8 Q(.)-.55 E F1(history\255sear)108 472.8 Q(ch\255f)-.18 -E(orward)-.25 E F0 .249(Search forw)144 484.8 R .249(ard through the history f\ -or the string of characters between the start of the current line)-.1 F -(and the current point.)144 496.8 Q(This is a non-incremental search.)5 E -(By def)5 E(ault, this command is unbound.)-.1 E F1(history\255sear)108 508.8 Q -(ch\255backward)-.18 E F0 .95(Search backw)144 520.8 R .951(ard through the hi\ -story for the string of characters between the start of the current)-.1 F 2.721 -(line and the current point.)144 532.8 R 2.721 -(This is a non-incremental search.)7.721 F 2.72(By def)7.721 F 2.72 -(ault, this command is)-.1 F(unbound.)144 544.8 Q F1(yank\255nth\255ar)108 -556.8 Q 2.5(g\()-.1 G<4dad43ad7929>175.14 556.8 Q F0 .622 -(Insert the \214rst ar)144 568.8 R .622(gument to the pre)-.18 F .622 -(vious command \(usually the second w)-.25 F .622(ord on the pre)-.1 F .622 -(vious line\))-.25 F .682(at point \(the current cursor position\).)144 580.8 R --.4(Wi)5.682 G .682(th an ar).4 F(gument)-.18 E/F2 10/Times-Italic@0 SF(n)3.182 -E F0 3.182(,i).24 G .682(nsert the)390.17 580.8 R F2(n)3.182 E F0 .682(th w)B -.681(ord from the pre)-.1 F(vious)-.25 E .729(command \(the w)144 592.8 R .729 -(ords in the pre)-.1 F .729(vious command be)-.25 F .729(gin with w)-.15 F .729 -(ord 0\).)-.1 F 3.23(An)5.73 G -2.25 -.15(eg a)441.56 592.8 T(ti).15 E 1.03 --.15(ve a)-.25 H -.18(rg).15 G .73(ument inserts).18 F(the)144 604.8 Q F2(n)2.5 -E F0(th w)A(ord from the end of the pre)-.1 E(vious command.)-.25 E F1 -(yank\255last\255ar)108 616.8 Q 2.5(g\()-.1 G -1.667(M\255. ,)175.69 616.8 R --1.667(M\255_ \))2.5 F F0 1.077(Insert the last ar)144 628.8 R 1.077 -(gument to the pre)-.18 F 1.077(vious command \(the last w)-.25 F 1.077 -(ord on the pre)-.1 F 1.077(vious line\).)-.25 F -.4(Wi)6.076 G 1.076(th an).4 -F(ar)144 640.8 Q(gument, beha)-.18 E .3 -.15(ve ex)-.2 H(actly lik).15 E(e)-.1 -E F1(yank-nth-ar)2.5 E(g)-.1 E F0(.)A F1(Commands f)87 657.6 Q(or Changing T) --.25 E(ext)-.92 E(delete\255char \(C\255d\))108 669.6 Q F0 .486 -(Delete the character under the cursor)144 681.6 R 5.486(.I)-.55 G 2.987(fp) -304.636 681.6 S .487(oint is at the be)315.953 681.6 R .487 -(ginning of the line, there are no charac-)-.15 F -(ters in the line, and the last character typed w)144 693.6 Q(as not)-.1 E F1 -(C\255d)2.5 E F0 2.5(,t)C(hen return)377.34 693.6 Q/F3 9/Times-Bold@0 SF(EOF) -2.5 E/F4 9/Times-Roman@0 SF(.)A F1(backward\255delete\255char \(Rubout\))108 -705.6 Q F0 .553(Delete the character behind the cursor)144 717.6 R 5.553(.W) --.55 G .553(hen gi)315.598 717.6 R -.15(ve)-.25 G 3.053(nan).15 G .553 -(umeric ar)370.457 717.6 R .552(gument, sa)-.18 F .852 -.15(ve t)-.2 H .552 -(he deleted te).15 F .552(xt on)-.15 F(the kill\255ring.)144 729.6 Q 184.005 -(GNU 1994)72 768 R(July 26)2.5 E(6)535 768 Q EP -%%Page: 7 7 -%%BeginPageSetup -BP -%%EndPageSetup -/F0 10/Times-Roman@0 SF 342.2(READLINE\(3\) READLINE\(3\))72 48 R/F1 10 -/Times-Bold@0 SF(quoted\255insert \(C\255q, C\255v\))108 84 Q F0 1.228 -(Add the ne)144 96 R 1.228(xt character that you type to the line v)-.15 F -3.728(erbatim. This)-.15 F 1.228(is ho)3.728 F 3.729(wt)-.25 G 3.729(oi)446.163 -96 S 1.229(nsert characters lik)457.672 96 R(e)-.1 E F1(C\255q)144 108 Q F0 2.5 -(,f)C(or e)170.81 108 Q(xample.)-.15 E F1(tab\255insert \(M-T)108 120 Q(AB\)) --.9 E F0(Insert a tab character)144 132 Q(.)-.55 E F1 -(self\255insert \(a, b, A, 1, !, ...\))108 144 Q F0 -(Insert the character typed.)144 156 Q F1(transpose\255chars \(C\255t\))108 168 -Q F0 .424(Drag the character before point forw)144 180 R .424(ard o)-.1 F -.15 -(ve)-.15 G 2.924(rt).15 G .424(he character at point.)331.218 180 R .424 -(Point mo)5.424 F -.15(ve)-.15 G 2.924(sf).15 G(orw)477.882 180 Q .424 -(ard as well.)-.1 F 1.03 -(If point is at the end of the line, then transpose the tw)144 192 R 3.531(oc) --.1 G 1.031(haracters before point.)382.266 192 R(Ne)6.031 E -.05(ga)-.15 G(ti) -.05 E 1.331 -.15(ve a)-.25 H -.18(rg).15 G(u-).18 E(ments don')144 204 Q 2.5 -(tw)-.18 G(ork.)200.94 204 Q F1(transpose\255w)108 216 Q(ords \(M\255t\))-.1 E -F0 .683(Drag the w)144 228 R .682(ord behind the cursor past the w)-.1 F .682 -(ord in front of the cursor mo)-.1 F .682(ving the cursor o)-.15 F -.15(ve)-.15 -G 3.182(rt).15 G(hat)527.78 228 Q -.1(wo)144 240 S(rd as well.).1 E F1 -(upcase\255w)108 252 Q(ord \(M\255u\))-.1 E F0 .702 -(Uppercase the current \(or follo)144 264 R .702(wing\) w)-.25 F 3.202(ord. W) --.1 F .702(ith a ne)-.4 F -.05(ga)-.15 G(ti).05 E 1.002 -.15(ve a)-.25 H -.18 -(rg).15 G .702(ument, do the pre).18 F .703(vious w)-.25 F .703(ord, b)-.1 F -(ut)-.2 E(do not mo)144 276 Q .3 -.15(ve p)-.15 H(oint.).15 E F1(do)108 288 Q -(wncase\255w)-.1 E(ord \(M\255l\))-.1 E F0(Lo)144 300 Q .641 -(wercase the current \(or follo)-.25 F .641(wing\) w)-.25 F 3.141(ord. W)-.1 F -.641(ith a ne)-.4 F -.05(ga)-.15 G(ti).05 E .941 -.15(ve a)-.25 H -.18(rg).15 G -.64(ument, do the pre).18 F .64(vious w)-.25 F .64(ord, b)-.1 F(ut)-.2 E -(do not mo)144 312 Q .3 -.15(ve p)-.15 H(oint.).15 E F1(capitalize\255w)108 324 -Q(ord \(M\255c\))-.1 E F0 .82(Capitalize the current \(or follo)144 336 R .82 -(wing\) w)-.25 F 3.32(ord. W)-.1 F .82(ith a ne)-.4 F -.05(ga)-.15 G(ti).05 E -1.12 -.15(ve a)-.25 H -.18(rg).15 G .82(ument, do the pre).18 F .82(vious w) --.25 F .82(ord, b)-.1 F(ut)-.2 E(do not mo)144 348 Q .3 -.15(ve p)-.15 H(oint.) -.15 E F1(Killing and Y)87 364.8 Q(anking)-.85 E(kill\255line \(C\255k\))108 -376.8 Q F0(Kill the te)144 388.8 Q -(xt from the current cursor position to the end of the line.)-.15 E F1 -(backward\255kill\255line \(C\255x Rubout\))108 400.8 Q F0(Kill backw)144 412.8 -Q(ard to the be)-.1 E(ginning of the line.)-.15 E F1 -(unix\255line\255discard \(C\255u\))108 424.8 Q F0(Kill backw)144 436.8 Q -(ard from point to the be)-.1 E(ginning of the line.)-.15 E F1 -(kill\255whole\255line)108 448.8 Q F0 -(Kill all characters on the current line, no matter where the cursor is.)144 -460.8 Q(By def)5 E(ault, this is unbound.)-.1 E F1(kill\255w)108 472.8 Q -(ord \(M\255d\))-.1 E F0 1.044 -(Kill from the cursor to the end of the current w)144 484.8 R 1.043 -(ord, or if between w)-.1 F 1.043(ords, to the end of the ne)-.1 F(xt)-.15 E --.1(wo)144 496.8 S 2.5(rd. W).1 F(ord boundaries are the same as those used by) --.8 E F1 -.25(fo)2.5 G(rward\255w).25 E(ord)-.1 E F0(.)A F1 -(backward\255kill\255w)108 508.8 Q(ord \(M\255Rubout\))-.1 E F0 3.26 -(Kill the w)144 520.8 R 3.26(ord behind the cursor)-.1 F 8.26(.W)-.55 G 3.26 -(ord boundaries are the same as those used by)304.31 520.8 R F1(back-)5.76 E -(ward\255w)144 532.8 Q(ord)-.1 E F0(.)A F1(unix\255w)108 544.8 Q -(ord\255rubout \(C\255w\))-.1 E F0 .482(Kill the w)144 556.8 R .482 -(ord behind the cursor)-.1 F 2.982(,u)-.4 G .482(sing white space as a w) -281.652 556.8 R .482(ord boundary)-.1 F 5.482(.T)-.65 G .482(he w)445.076 556.8 -R .481(ord boundaries are)-.1 F(dif)144 568.8 Q(ferent from)-.25 E F1 -(backward\255kill\255w)2.5 E(ord)-.1 E F0(.)A F1(delete\255horizontal\255space) -108 580.8 Q F0(Delete all spaces and tabs around point.)144 592.8 Q(By def)5 E -(ault, this is unbound.)-.1 E F1(yank \(C\255y\))108 604.8 Q F0 -1(Ya)144 616.8 -S(nk the top of the kill ring into the b)1 E(uf)-.2 E(fer at the cursor)-.25 E -(.)-.55 E F1(yank\255pop \(M\255y\))108 628.8 Q F0 -(Rotate the kill\255ring, and yank the ne)144 640.8 Q 2.5(wt)-.25 G 2.5 -(op. Only)302.71 640.8 R -.1(wo)2.5 G(rks follo).1 E(wing)-.25 E F1(yank)2.5 E -F0(or)2.5 E F1(yank\255pop)2.5 E F0(.)A F1(Numeric Ar)87 657.6 Q(guments)-.1 E -(digit\255ar)108 669.6 Q(gument \(M\2550, M\2551, ..., M\255\255\))-.1 E F0 -.641(Add this digit to the ar)144 681.6 R .641 -(gument already accumulating, or start a ne)-.18 F 3.141(wa)-.25 G -.18(rg) -425.942 681.6 S 3.142(ument. M\255\255).18 F .642(starts a ne)3.142 F(g-)-.15 E -(ati)144 693.6 Q .3 -.15(ve a)-.25 H -.18(rg).15 G(ument.).18 E F1(uni)108 -705.6 Q -.1(ve)-.1 G(rsal\255ar).1 E(gument)-.1 E F0 .783(Each time this is e) -144 717.6 R -.15(xe)-.15 G .783(cuted, the ar).15 F .782 -(gument count is multiplied by four)-.18 F 5.782(.T)-.55 G .782(he ar)437.062 -717.6 R .782(gument count is ini-)-.18 F .175(tially one, so e)144 729.6 R -.15 -(xe)-.15 G .175(cuting this function the \214rst time mak).15 F .176(es the ar) --.1 F .176(gument count four)-.18 F 5.176(.B)-.55 G 2.676(yd)485.028 729.6 S -(ef)497.704 729.6 Q .176(ault, this)-.1 F 184.005(GNU 1994)72 768 R(July 26)2.5 -E(7)535 768 Q EP -%%Page: 8 8 -%%BeginPageSetup -BP -%%EndPageSetup -/F0 10/Times-Roman@0 SF 342.2(READLINE\(3\) READLINE\(3\))72 48 R -(is not bound to a k)144 84 Q -.15(ey)-.1 G(.)-.5 E/F1 10/Times-Bold@0 SF -(Completing)87 100.8 Q(complete \(T)108 112.8 Q(AB\))-.9 E F0 1.909 -(Attempt to perform completion on the te)144 124.8 R 1.908(xt before point.) --.15 F 1.908(The actual completion performed is)6.908 F -(application-speci\214c.)144 136.8 Q F1(Bash)5.517 E F0 3.017(,f)C .518 -(or instance, attempts completion treating the te)260.304 136.8 R .518 -(xt as a v)-.15 F .518(ariable \(if the)-.25 F(te)144 148.8 Q .657(xt be)-.15 F -.657(gins with)-.15 F F1($)3.156 E F0 .656(\), username \(if the te)B .656 -(xt be)-.15 F .656(gins with)-.15 F F1(~)3.156 E F0 .656 -(\), hostname \(if the te)B .656(xt be)-.15 F .656(gins with)-.15 F F1(@)3.156 -E F0 .656(\), or)B .929(command \(including aliases and functions\) in turn.) -144 160.8 R .93(If none of these produces a match, \214lename)5.929 F 1.274 -(completion is attempted.)144 172.8 R F1(Gdb)6.273 E F0 3.773(,o)C 3.773(nt) -281.603 172.8 S 1.273(he other hand, allo)293.156 172.8 R 1.273 -(ws completion of program functions and)-.25 F -.25(va)144 184.8 S -(riables, and only attempts \214lename completion under certain circumstances.) -.25 E F1(possible\255completions \(M-?\))108 196.8 Q F0 -(List the possible completions of the te)144 208.8 Q(xt before point.)-.15 E F1 -(insert\255completions)108 220.8 Q F0 3.372(Insert all completions of the te) -144 232.8 R 3.372(xt before point that w)-.15 F 3.372(ould ha)-.1 F 3.672 -.15 -(ve b)-.2 H 3.372(een generated by).15 F F1(possi-)5.873 E(ble\255completions) -144 244.8 Q F0 5(.B)C 2.5(yd)227.76 244.8 S(ef)240.26 244.8 Q -(ault, this is not bound to a k)-.1 E -.15(ey)-.1 G(.)-.5 E F1 -.25(Ke)87 261.6 -S(yboard Macr).25 E(os)-.18 E(start\255kbd\255macr)108 273.6 Q 2.5(o\()-.18 G -(C-x \()188.93 273.6 Q(\)).833 E F0(Be)144 285.6 Q(gin sa)-.15 E -(ving the characters typed into the current k)-.2 E -.15(ey)-.1 G(board macro.) -.15 E F1(end\255kbd\255macr)108 297.6 Q 2.5(o\()-.18 G(C-x \))184.5 297.6 Q(\)) -.833 E F0(Stop sa)144 309.6 Q(ving the characters typed into the current k)-.2 -E -.15(ey)-.1 G(board macro and sa).15 E .3 -.15(ve t)-.2 H(he de\214nition.) -.15 E F1(call\255last\255kbd\255macr)108 321.6 Q 2.5(o\()-.18 G(C-x e\))204.64 -321.6 Q F0(Re-e)144 333.6 Q -.15(xe)-.15 G 1(cute the last k).15 F -.15(ey)-.1 -G .999 -(board macro de\214ned, by making the characters in the macro appear as if).15 -F(typed at the k)144 345.6 Q -.15(ey)-.1 G(board.).15 E F1(Miscellaneous)87 -362.4 Q -.18(re)108 374.4 S(-r).18 E(ead-init-\214le \(C\255x C\255r\))-.18 E -F0 .54(Read in the contents of your init \214le, and incorporate an)144 386.4 R -3.041(yb)-.15 G .541(indings or v)385.876 386.4 R .541 -(ariable assignments found)-.25 F(there.)144 398.4 Q F1(abort \(C\255g\))108 -410.4 Q F0 3.249(Abort the current editing command and ring the terminal')144 -422.4 R 5.748(sb)-.55 G 3.248(ell \(subject to the setting of)414.6 422.4 R F1 -(bell\255style)144 434.4 Q F0(\).)A F1(do\255upper)108 446.4 Q(case\255v)-.18 E -(ersion \(M\255a, M\255b, ...\))-.1 E F0 -(Run the command that is bound to the corresponding uppercase character)144 -458.4 Q(.)-.55 E F1(pr)108 470.4 Q(e\214x\255meta \(ESC\))-.18 E F0 -(Metafy the ne)144 482.4 Q(xt character typed.)-.15 E/F2 9/Times-Bold@0 SF(ESC) -5 E F1(f)2.25 E F0(is equi)2.5 E -.25(va)-.25 G(lent to).25 E F1(Meta\255f)2.5 -E F0(.)A F1(undo \(C\255_, C\255x C\255u\))108 494.4 Q F0 -(Incremental undo, separately remembered for each line.)144 506.4 Q F1 -2.29 --.18(re v)108 518.4 T(ert\255line \(M\255r\)).08 E F0 .244 -(Undo all changes made to this line.)144 530.4 R .245(This is lik)5.245 F 2.745 -(et)-.1 G .245(yping the)341.895 530.4 R F1(undo)2.745 E F0 .245 -(command enough times to return)2.745 F(the line to its initial state.)144 -542.4 Q F1(tilde\255expand \(M\255~\))108 554.4 Q F0(Perform tilde e)144 566.4 -Q(xpansion on the current w)-.15 E(ord.)-.1 E F1(dump\255functions)108 578.4 Q -F0 .627(Print all of the functions and their k)144 590.4 R .927 -.15(ey b)-.1 H -.626(indings to the readline output stream.).15 F .626(If a numeric ar)5.626 F -(gu-)-.18 E(ment is supplied, the output is formatted in such a w)144 602.4 Q -(ay that it can be made part of an)-.1 E/F3 10/Times-Italic@0 SF(inputr)2.5 E -(c)-.37 E F0(\214le.)2.5 E F1(emacs\255editing\255mode \(C\255e\))108 614.4 Q -F0(When in)144 626.4 Q F1(vi)2.5 E F0(editing mode, this causes a switch to)2.5 -E F1(emacs)2.5 E F0(editing mode.)2.5 E F1 -(vi\255editing\255mode \(M\255C\255j\))108 638.4 Q F0(When in)144 650.4 Q F1 -(emacs)2.5 E F0(editing mode, this causes a switch to)2.5 E F1(vi)2.5 E F0 -(editing mode.)2.5 E F2(DEF)72 667.2 Q -.45(AU)-.81 G 1.656 -.828(LT K).45 H -(EY BINDINGS).828 E F0 .675(The follo)108 679.2 R .675 -(wing is a list of the def)-.25 F .675(ault emacs and vi bindings.)-.1 F .676 -(Characters with the 8th bit set are written as)5.676 F .002 -(M-, and are referred to as)108 691.2 R F3(meta\214ed)2.502 E F0 -2.502(characters. The)2.502 F .002(printable ASCII characters not mentioned in) -2.502 F .444(the list of emacs standard bindings are bound to the)108 703.2 R -F3(self\255insert)2.945 E F0 .445(function, which just inserts the gi)2.945 F --.15(ve)-.25 G 2.945(nc).15 G(har)524.1 703.2 Q(-)-.2 E 2.021 -(acter into the input line.)108 715.2 R 2.02(In vi insertion mode, all charact\ -ers not speci\214cally mentioned are bound to)7.021 F F3(self\255insert)108 -727.2 Q F0 5.388(.C).68 G .388(haracters assigned to signal generation by) -166.658 727.2 R F3(stty)2.889 E F0 .389(\(1\) or the terminal dri).32 F -.15 -(ve)-.25 G 1.189 -.4(r, s).15 H .389(uch as C-Z or C-C,).4 F 184.005(GNU 1994) -72 768 R(July 26)2.5 E(8)535 768 Q EP -%%Page: 9 9 -%%BeginPageSetup -BP -%%EndPageSetup -/F0 10/Times-Roman@0 SF 342.2(READLINE\(3\) READLINE\(3\))72 48 R .221 -(retain that function.)108 84 R .221(Upper and lo)5.221 F .221(wer case)-.25 F -/F1 10/Times-Italic@0 SF(meta\214ed)2.721 E F0 .22 -(characters are bound to the same function in the emacs)2.721 F .304 -(mode meta k)108 96 R -.15(ey)-.1 G 2.804(map. The).15 F .305(remaining charac\ -ters are unbound, which causes readline to ring the bell \(subject)2.804 F -(to the setting of the)108 108 Q/F2 10/Times-Bold@0 SF(bell\255style)2.5 E F0 --.25(va)2.5 G(riable\).).25 E F2(Emacs Mode)87 124.8 Q F0 -(Emacs Standard bindings)151.2 136.8 Q 152.12("C-A" ->)151.2 160.8 R(be)5 E -(ginning-of-line)-.15 E 152.67("C-B" ->)151.2 172.8 R(backw)5 E(ard-char)-.1 E -152.12("C-D" ->)151.2 184.8 R(delete-char)5 E 153.23("C-E" ->)151.2 196.8 R -(end-of-line)5 E 153.78("C-F" ->)151.2 208.8 R(forw)5 E(ard-char)-.1 E 152.12 -("C-G" ->)151.2 220.8 R(abort)5 E 152.12("C-H" ->)151.2 232.8 R(backw)5 E -(ard-delete-char)-.1 E 156.01("C-I" ->)151.2 244.8 R(complete)5 E 155.45 -("C-J" ->)151.2 256.8 R(accept-line)5 E 152.12("C-K" ->)151.2 268.8 R -(kill-line)5 E 153.23("C-L" ->)151.2 280.8 R(clear)5 E(-screen)-.2 E 150.45 -("C-M" ->)151.2 292.8 R(accept-line)5 E 152.12("C-N" ->)151.2 304.8 R(ne)5 E -(xt-history)-.15 E 153.78("C-P" ->)151.2 316.8 R(pre)5 E(vious-history)-.25 E -152.12("C-Q" ->)151.2 328.8 R(quoted-insert)5 E 152.67("C-R" ->)151.2 340.8 R -(re)5 E -.15(ve)-.25 G(rse-search-history).15 E 153.78("C-S" ->)151.2 352.8 R -(forw)5 E(ard-search-history)-.1 E 153.23("C-T" ->)151.2 364.8 R -(transpose-chars)5 E 152.12("C-U" ->)151.2 376.8 R(unix-line-discard)5 E 152.12 -("C-V" ->)151.2 388.8 R(quoted-insert)5 E 149.9("C-W" ->)151.2 400.8 R(unix-w)5 -E(ord-rubout)-.1 E 152.12("C-Y" ->)151.2 412.8 R(yank)5 E 154.34("C-_" ->)151.2 -424.8 R(undo)5 E 3.333("")151.2 436.8 S(to "/")-.833 E 2.5(-> self-insert)331.2 -436.8 R 2.5("0" to)151.2 448.8 R 135.9("9" ->)2.5 F(self-insert)5 E 2.5(":" to) -151.2 460.8 R 139.79("~" ->)2.5 F(self-insert)5 E 154.9("C-?" ->)151.2 472.8 R -(backw)5 E(ard-delete-char)-.1 E(Emacs Meta bindings)151.2 489.6 Q 139.9 -("M-C-H" ->)151.2 513.6 R(backw)5 E(ard-kill-w)-.1 E(ord)-.1 E 143.79 -("M-C-I" ->)151.2 525.6 R(tab-insert)5 E 143.23("M-C-J" ->)151.2 537.6 R -(vi-editing-mode)5 E 138.23("M-C-M" ->)151.2 549.6 R(vi-editing-mode)5 E 140.45 -("M-C-R" ->)151.2 561.6 R(re)5 E -.15(ve)-.25 G(rt-line).15 E 139.9("M-C-Y" ->) -151.2 573.6 R(yank-nth-ar)5 E(g)-.18 E 143.79("M-C-[" ->)151.2 585.6 R -(complete)5 E 149.34("M-&" ->)151.2 597.6 R(tilde-e)5 E(xpand)-.15 E 153.79 -("M--" ->)151.2 609.6 R(digit-ar)5 E(gument)-.18 E 152.12("M-0" ->)151.2 621.6 -R(digit-ar)5 E(gument)-.18 E 152.12("M-1" ->)151.2 633.6 R(digit-ar)5 E(gument) --.18 E 152.12("M-2" ->)151.2 645.6 R(digit-ar)5 E(gument)-.18 E 152.12 -("M-3" ->)151.2 657.6 R(digit-ar)5 E(gument)-.18 E 152.12("M-4" ->)151.2 669.6 -R(digit-ar)5 E(gument)-.18 E 152.12("M-5" ->)151.2 681.6 R(digit-ar)5 E(gument) --.18 E 152.12("M-6" ->)151.2 693.6 R(digit-ar)5 E(gument)-.18 E 152.12 -("M-7" ->)151.2 705.6 R(digit-ar)5 E(gument)-.18 E 152.12("M-8" ->)151.2 717.6 -R(digit-ar)5 E(gument)-.18 E 152.12("M-9" ->)151.2 729.6 R(digit-ar)5 E(gument) --.18 E 184.005(GNU 1994)72 768 R(July 26)2.5 E(9)535 768 Q EP -%%Page: 10 10 -%%BeginPageSetup -BP -%%EndPageSetup -/F0 10/Times-Roman@0 SF 342.2(READLINE\(3\) READLINE\(3\))72 48 R 151.48 -("M-<" ->)151.2 84 R(be)5 E(ginning-of-history)-.15 E 151.48("M->" ->)151.2 96 -R(end-of-history)5 E 152.68("M-?" ->)151.2 108 R(possible-completions)5 E -150.45("M-B" ->)151.2 120 R(backw)5 E(ard-w)-.1 E(ord)-.1 E 150.45("M-C" ->) -151.2 132 R(capitalize-w)5 E(ord)-.1 E 149.9("M-D" ->)151.2 144 R(kill-w)5 E -(ord)-.1 E 151.56("M-F" ->)151.2 156 R(forw)5 E(ard-w)-.1 E(ord)-.1 E 151.01 -("M-L" ->)151.2 168 R(do)5 E(wncase-w)-.25 E(ord)-.1 E 149.9("M-N" ->)151.2 180 -R(non-incremental-forw)5 E(ard-search-history)-.1 E 149.9("M-O" ->)151.2 192 R -(arro)5 E(w-k)-.25 E -.15(ey)-.1 G(-pre\214x).15 E 151.56("M-P" ->)151.2 204 R -(non-incremental-re)5 E -.15(ve)-.25 G(rse-search-history).15 E 150.45 -("M-R" ->)151.2 216 R(re)5 E -.15(ve)-.25 G(rt-line).15 E 151.01("M-T" ->)151.2 -228 R(transpose-w)5 E(ords)-.1 E 149.9("M-U" ->)151.2 240 R(upcase-w)5 E(ord) --.1 E 149.9("M-Y" ->)151.2 252 R(yank-pop)5 E 139.9("M-C-Y" ->)151.2 264 R -(yank-nth-ar)5 E(g)-.18 E 142.68("M-C-?" ->)151.2 276 R(backw)5 E(ard-delete-w) --.1 E(ord)-.1 E(Emacs Control-X bindings)151.2 292.8 Q 134.9("C-XC-G" ->)151.2 -316.8 R(abort)5 E 135.45("C-XC-R" ->)151.2 328.8 R(re-read-init-\214le)5 E -134.9("C-XC-U" ->)151.2 340.8 R(undo)5 E 148.79("C-X\(" ->)151.2 352.8 R -(start-kbd-macro)5 E 148.79("C-X\)" ->)151.2 364.8 R(end-kbd-macro)5 E 147.68 -("C-Xe" ->)151.2 376.8 R(call-last-kbd-macro)5 E 137.68("C-XC-?" ->)151.2 388.8 -R(backw)5 E(ard-kill-line)-.1 E/F1 10/Times-Bold@0 SF(VI Mode bindings)87 417.6 -Q F0(VI Insert Mode functions)151.2 429.6 Q 152.12("C-D" ->)151.2 453.6 R -(vi-eof-maybe)5 E 152.12("C-H" ->)151.2 465.6 R(backw)5 E(ard-delete-char)-.1 E -156.01("C-I" ->)151.2 477.6 R(complete)5 E 155.45("C-J" ->)151.2 489.6 R -(accept-line)5 E 152.12("C-K" ->)151.2 501.6 R(kill-line)5 E 153.23("C-L" ->) -151.2 513.6 R(clear)5 E(-screen)-.2 E 150.45("C-M" ->)151.2 525.6 R -(accept-line)5 E 152.12("C-N" ->)151.2 537.6 R(ne)5 E(xt-history)-.15 E 153.78 -("C-P" ->)151.2 549.6 R(pre)5 E(vious-history)-.25 E 152.12("C-Q" ->)151.2 -561.6 R(quoted-insert)5 E 152.67("C-R" ->)151.2 573.6 R(re)5 E -.15(ve)-.25 G -(rse-search-history).15 E 153.78("C-S" ->)151.2 585.6 R(forw)5 E -(ard-search-history)-.1 E 153.23("C-T" ->)151.2 597.6 R(transpose-chars)5 E -152.12("C-U" ->)151.2 609.6 R(unix-line-discard)5 E 152.12("C-V" ->)151.2 621.6 -R(quoted-insert)5 E 149.9("C-W" ->)151.2 633.6 R(unix-w)5 E(ord-rubout)-.1 E -152.12("C-Y" ->)151.2 645.6 R(yank)5 E 156.01("C-[" ->)151.2 657.6 R(vi-mo)5 E --.15(ve)-.15 G(ment-mode).15 E 3.333("")151.2 669.6 S(to "~")-.833 E 2.5 -(-> self-insert)331.2 669.6 R 154.9("C-?" ->)151.2 681.6 R(backw)5 E -(ard-delete-char)-.1 E(VI Command Mode functions)151.2 698.4 Q 152.12("C-D" ->) -151.2 722.4 R(vi-eof-maybe)5 E 184.005(GNU 1994)72 768 R(July 26)2.5 E(10)530 -768 Q EP -%%Page: 11 11 -%%BeginPageSetup -BP -%%EndPageSetup -/F0 10/Times-Roman@0 SF 342.2(READLINE\(3\) READLINE\(3\))72 48 R 153.23 -("C-E" ->)151.2 84 R(emacs-editing-mode)5 E 152.12("C-G" ->)151.2 96 R(abort)5 -E 152.12("C-H" ->)151.2 108 R(backw)5 E(ard-char)-.1 E 155.45("C-J" ->)151.2 -120 R(accept-line)5 E 152.12("C-K" ->)151.2 132 R(kill-line)5 E 153.23 -("C-L" ->)151.2 144 R(clear)5 E(-screen)-.2 E 150.45("C-M" ->)151.2 156 R -(accept-line)5 E 152.12("C-N" ->)151.2 168 R(ne)5 E(xt-history)-.15 E 153.78 -("C-P" ->)151.2 180 R(pre)5 E(vious-history)-.25 E 152.12("C-Q" ->)151.2 192 R -(quoted-insert)5 E 152.67("C-R" ->)151.2 204 R(re)5 E -.15(ve)-.25 G -(rse-search-history).15 E 153.78("C-S" ->)151.2 216 R(forw)5 E -(ard-search-history)-.1 E 153.23("C-T" ->)151.2 228 R(transpose-chars)5 E -152.12("C-U" ->)151.2 240 R(unix-line-discard)5 E 152.12("C-V" ->)151.2 252 R -(quoted-insert)5 E 149.9("C-W" ->)151.2 264 R(unix-w)5 E(ord-rubout)-.1 E -152.12("C-Y" ->)151.2 276 R(yank)5 E 156.01("C-[" ->)151.2 288 R(abort)5 E -159.341 3.333("" -)151.2 300 T 5(>f)334.53 300 S(orw)348.5 300 Q(ard-char)-.1 E -164.34("#" ->)151.2 312 R(vi-comment)5 E 164.34("$" ->)151.2 324 R(end-of-line) -5 E 161.01("%" ->)151.2 336 R(vi-match)5 E 161.56("&" ->)151.2 348 R -(vi-tilde-e)5 E(xpand)-.15 E 164.34("*" ->)151.2 360 R(vi-complete)5 E 163.7 -("+" ->)151.2 372 R(do)5 E(wn-history)-.25 E 166.84("," ->)151.2 384 R(vi-char) -5 E(-search)-.2 E 166.01("-" ->)151.2 396 R(pre)5 E(vious-history)-.25 E 166.84 -("." ->)151.2 408 R(vi-redo)5 E 166.56("/" ->)151.2 420 R(vi-search)5 E 164.34 -("0" ->)151.2 432 R(be)5 E(ginning-of-line)-.15 E("1" to "9")151.2 444 Q 2.5 -(-> vi-ar)331.2 444 R(g-digit)-.18 E 166.56(";" ->)151.2 456 R(vi-char)5 E -(-search)-.2 E 163.7("=" ->)151.2 468 R(vi-complete)5 E 164.9("?" ->)151.2 480 -R(vi-search)5 E 160.13("@" ->)151.2 492 R(is unde\214ned)5 E 162.12("A" ->) -151.2 504 R(vi-append-eol)5 E 162.67("B" ->)151.2 516 R(vi-pre)5 E(v-w)-.25 E -(ord)-.1 E 162.67("C" ->)151.2 528 R(vi-change-to)5 E 162.12("D" ->)151.2 540 R -(vi-delete-to)5 E 163.23("E" ->)151.2 552 R(vi-end-w)5 E(ord)-.1 E 163.78 -("F" ->)151.2 564 R(vi-char)5 E(-search)-.2 E 166.01("I" ->)151.2 576 R -(vi-insert-be)5 E(g)-.15 E 162.12("N" ->)151.2 588 R(vi-search-ag)5 E(ain)-.05 -E 163.78("P" ->)151.2 600 R(vi-put)5 E 162.67("R" ->)151.2 612 R(vi-replace)5 E -163.78("S" ->)151.2 624 R(vi-subst)5 E 163.23("T" ->)151.2 636 R(vi-char)5 E -(-search)-.2 E 162.12("U" ->)151.2 648 R(re)5 E -.15(ve)-.25 G(rt-line).15 E -159.9("W" ->)151.2 660 R(vi-ne)5 E(xt-w)-.15 E(ord)-.1 E 162.12("X" ->)151.2 -672 R(backw)5 E(ard-delete-char)-.1 E 162.12("Y" ->)151.2 684 R(vi-yank-to)5 E -166.56("\\" ->)151.2 696 R(vi-complete)5 E 166.01("^" ->)151.2 708 R -(vi-\214rst-print)5 E 164.34("_" ->)151.2 720 R(vi-yank-ar)5 E(g)-.18 E 184.005 -(GNU 1994)72 768 R(July 26)2.5 E(11)530 768 Q EP -%%Page: 12 12 -%%BeginPageSetup -BP -%%EndPageSetup -/F0 10/Times-Roman@0 SF 342.2(READLINE\(3\) READLINE\(3\))72 48 R 164.9("a" ->) -151.2 84 R(vi-append-mode)5 E 164.34("b" ->)151.2 96 R(vi-pre)5 E(v-w)-.25 E -(ord)-.1 E 164.9("c" ->)151.2 108 R(vi-change-to)5 E 164.34("d" ->)151.2 120 R -(vi-delete-to)5 E 164.9("e" ->)151.2 132 R(vi-end-w)5 E(ord)-.1 E 166.01 -("f" ->)151.2 144 R(vi-char)5 E(-search)-.2 E 164.34("h" ->)151.2 156 R(backw)5 -E(ard-char)-.1 E 166.56("i" ->)151.2 168 R(vi-insertion-mode)5 E 166.56("j" ->) -151.2 180 R(ne)5 E(xt-history)-.15 E 164.34("k" ->)151.2 192 R(pre)5 E -(v-history)-.25 E 166.56("l" ->)151.2 204 R(forw)5 E(ard-char)-.1 E 164.34 -("n" ->)151.2 216 R(vi-search-ag)5 E(ain)-.05 E 166.01("r" ->)151.2 228 R -(vi-change-char)5 E 165.45("s" ->)151.2 240 R(vi-subst)5 E 166.56("t" ->)151.2 -252 R(vi-char)5 E(-search)-.2 E 164.34("u" ->)151.2 264 R(undo)5 E 162.12 -("w" ->)151.2 276 R(vi-ne)5 E(xt-w)-.15 E(ord)-.1 E 164.34("x" ->)151.2 288 R -(vi-delete)5 E 164.34("y" ->)151.2 300 R(vi-yank-to)5 E 167.34("|" ->)151.2 312 -R(vi-column)5 E 166.01("~" ->)151.2 324 R(vi-change-case)5 E/F1 9/Times-Bold@0 -SF(SEE ALSO)72 340.8 Q/F2 10/Times-Italic@0 SF(The Gnu Readline Libr)108 352.8 -Q(ary)-.15 E F0 2.5(,B)C(rian F)225.35 352.8 Q(ox and Chet Rame)-.15 E(y)-.15 E -F2(The Gnu History Libr)108 364.8 Q(ary)-.15 E F0 2.5(,B)C(rian F)219.8 364.8 Q -(ox and Chet Rame)-.15 E(y)-.15 E F2(bash)108 376.8 Q F0(\(1\))A F1(FILES)72 -393.6 Q F2(~/.inputr)109.666 405.6 Q(c)-.37 E F0(Indi)144 417.6 Q(vidual)-.25 E -/F3 10/Times-Bold@0 SF -.18(re)2.5 G(adline).18 E F0(initialization \214le)2.5 -E F1 -.45(AU)72 434.4 S(THORS).45 E F0(Brian F)144 446.4 Q(ox, Free Softw)-.15 -E(are F)-.1 E(oundation \(primary author\))-.15 E(bfox@ai.MIT)144 458.4 Q(.Edu) --.74 E(Chet Rame)144 475.2 Q 1.3 -.65(y, C)-.15 H(ase W).65 E(estern Reserv)-.8 -E 2.5(eU)-.15 G(ni)296.66 475.2 Q -.15(ve)-.25 G(rsity).15 E(chet@ins.CWR)144 -487.2 Q(U.Edu)-.4 E F1 -.09(BU)72 504 S 2.25(GR).09 G(EPOR)100.161 504 Q(TS) --.36 E F0 .691(If you \214nd a b)108 516 R .691(ug in)-.2 F F3 -.18(re)3.191 G -(adline,).18 E F0 .691(you should report it.)3.191 F .69 -(But \214rst, you should mak)5.69 F 3.19(es)-.1 G .69 -(ure that it really is a b)436.35 516 R(ug,)-.2 E -(and that it appears in the latest v)108 528 Q(ersion of the)-.15 E F3 -.18(re) -2.5 G(adline).18 E F0(library that you ha)2.5 E -.15(ve)-.2 G(.).15 E 10.782 -(Once you ha)108 544.8 R 11.082 -.15(ve d)-.2 H 10.782(etermined that a b).15 F -10.782(ug actually e)-.2 F 10.783(xists, mail a b)-.15 F 10.783(ug report to) --.2 F F2(bash\255maintainer)108 556.8 Q(s)-.1 E F0(@)A F2(pr)A(ep.ai.MIT)-.37 E -(.Edu)-.74 E F0 5.169(.I)C 2.669(fy)267.359 556.8 S .169(ou ha)278.358 556.8 R -.469 -.15(ve a \214)-.2 H .168(x, you are welcome to mail that as well!).15 F -(Suggestions)5.168 E 2(and `philosophical' b)108 568.8 R 2.001 -(ug reports may be mailed to)-.2 F F2 -.2(bu)4.501 G(g-bash).2 E F0(@)A F2(pr)A -(ep.ai.MIT)-.37 E(.Edu)-.74 E F0 2.001(or posted to the Usenet)4.501 F(ne)108 -580.8 Q(wsgroup)-.25 E F3(gnu.bash.b)2.5 E(ug)-.2 E F0(.)A(Comments and b)108 -597.6 Q(ug reports concerning this manual page should be directed to)-.2 E F2 --.15(ch)2.5 G(et@ins.CWR).15 E -.25(U.)-.4 G(Edu).25 E F0(.).25 E F1 -.09(BU)72 -614.4 S(GS).09 E F0(It')108 626.4 Q 2.5(st)-.55 G(oo big and too slo)126.06 -626.4 Q -.65(w.)-.25 G 184.005(GNU 1994)72 768 R(July 26)2.5 E(12)530 768 Q EP -%%Trailer -end -%%EOF diff --git a/documentation/readline.txt b/documentation/readline.txt deleted file mode 100644 index 653a984..0000000 --- a/documentation/readline.txt +++ /dev/null @@ -1,1122 +0,0 @@ - - - -READLINE(3) C LIBRARY FUNCTIONS READLINE(3) - - - -NAME - readline - get a line from a user with editing - -SYNOPSIS - #include - #include - - typedef int Function (); - - char *readline (prompt) - char *prompt; - - int rl_add_defun (name, function, key) - char *name; - Function *function; - int key; - - int rl_bind_key (key, function) - int key; - Function *function; - - int rl_unbind_key (key) - int key; - - int rl_bind_key_in_map (key, function, keymap) - int key; - Function *function; - Keymap keymap; - - int rl_unbind_key_in_map (key, keymap) - int key; - Keymap keymap; - - int rl_macro_bind (keyseq, macro, keymap) - char *keyseq, *macro; - Keymap keymap; - - int rl_variable_bind (variable, value) - char *variable, *value; - - int rl_parse_and_bind (line) - char *line; - - int rl_translate_keyseq (keyseq, array, len) - char *keyseq, *array; - int *len; - - Function *rl_named_function (command) - char *command; - - Function *rl_function_of_keyseq (keyseq, keymap, type) - char *keyseq; - - - -GNU Last change: 1994 July 26 1 - - - - - - -READLINE(3) C LIBRARY FUNCTIONS READLINE(3) - - - - Keymap keymap; - int *type; - - char **rl_invoking_keyseqs (function) - Function *function; - - char **rl_invoking_keyseqs_in_map (function, keymap) - Function *function; - Keymap keymap; - - void rl_function_dumper (readable) - int readable; - - char **rl_funmap_names () - -COPYRIGHT - Readline is Copyright (C) 1989, 1991 by the Free Software - Foundation, Inc. - -DESCRIPTION - readline will read a line from the terminal and return it, - using prompt as a prompt. If prompt is null, no prompt is - issued. The line returned is allocated with _m_a_l_l_o_c(3), so - the caller must free it when finished. The line returned - has the final newline removed, so only the text of the line - remains. - - readline offers editing capabilities while the user is - entering the line. By default, the line editing commands - are similar to those of emacs. A vi-style line editing - interface is also available. - - In the following descriptions, keymap can be one of - _e_m_a_c_s__k_e_y_m_a_p, _e_m_a_c_s__m_e_t_a__k_e_y_m_a_p, _e_m_a_c_s__c_t_l_x__k_e_y_m_a_p, - _v_i__i_n_s_e_r_t_i_o_n__k_e_y_m_a_p, _o_r _v_i__m_o_v_e_m_e_n_t__k_e_y_m_a_p. - - rl_add_defun makes name appear as a bindable readline com- - mand, and makes function be the function called when that - command is invoked. If key is not -1, it is bound to func- - tion in the current keymap. - - rl_bind_key causes key to invoke function. The binding is - made in the current keymap. - - rl_unbind_key removes the binding for key in the current - keymap. - - rl_bind_key_in_map makes the key entry in keymap invoke - function. - - rl_unbind_key_in_map removes the binding for key in keymap - keymap. - - - -GNU Last change: 1994 July 26 2 - - - - - - -READLINE(3) C LIBRARY FUNCTIONS READLINE(3) - - - - rl_macro_bind makes keyseq insert the string macro. The - binding is performed in keymap. - - rl_variable_bind sets the value of the readline variable - variable to value. - - rl_parse_and_bind takes as an argument a line of the same - form as the readline startup file (see INITIALIZATION FILE - below) and executes the commands therein. - - rl_translate_keyseq converts keyseq into a new string, stor- - ing the result in array. This translates control and meta - prefixes and the readline character escape sequences (see - Key Bindings below). The length of the translated sequence - is returned in *len. - - rl_named_function returns the function that is executed when - the readline command command is invoked. - - rl_function_of_keyseq returns the function that is executed - when keyseq is read and keymap is the current keymap. type - is set to indicate whether the return value corresponds to a - function, macro, or auxiliary keymap. - - rl_invoking_keyseqs returns all of the key sequences in the - current keymap that invoke function. - - rl_invoking_keyseqs_in_map returns all of the key sequences - in keymap that invoke function. - - rl_function_dumper prints all of the readline functions and - their bindings to the readline output stream. If readable - is non-zero, the output is formattted so that it can be read - back in to restore the bindings. - - rl_funmap_names returns an array of all known readline bind- - able function names. The array is sorted. - -RETURN VALUE - readline returns the text of the line read. A blank line - returns the empty string. If EOF is encountered while read- - ing a line, and the line is empty, NULL is returned. If an - EOF is read with a non-empty line, it is treated as a new- - line. - - Unless otherwise stated, the other functions return 0 on - success and non-zero on failure. - -NOTATION - An emacs-style notation is used to denote keystrokes. Con- - trol keys are denoted by C-_k_e_y, e.g., C-n means Control-N. - Similarly, _m_e_t_a keys are denoted by M-_k_e_y, so M-x means - - - -GNU Last change: 1994 July 26 3 - - - - - - -READLINE(3) C LIBRARY FUNCTIONS READLINE(3) - - - - Meta-X. (On keyboards without a _m_e_t_a key, M-_x means ESC _x, - i.e., press the Escape key then the _x key. This makes ESC - the _m_e_t_a _p_r_e_f_i_x. The combination M-C-_x means ESC-Control-_x, - or press the Escape key then hold the Control key while - pressing the _x key.) - - Readline commands may be given numeric _a_r_g_u_m_e_n_t_s, which nor- - mally act as a repeat count. Sometimes, however, it is the - sign of the argument that is significant. Passing a nega- - tive argument to a command that acts in the forward direc- - tion (e.g., kill-line) causes that command to act in a back- - ward direction. Commands whose behavior with arguments - deviates from this are noted. - - When a command is described as _k_i_l_l_i_n_g text, the text - deleted is saved for possible future retrieval (_y_a_n_k_i_n_g). - The killed text is saved in a _k_i_l_l-_r_i_n_g. Consecutive kills - cause the text to be accumulated into one unit, which can be - yanked all at once. Commands which do not kill text separate - the chunks of text on the kill-ring. - -INITIALIZATION FILE - Readline is customized by putting commands in an initializa- - tion file. The name of this file is taken from the value of - the INPUTRC variable. If that variable is unset, the - default is ~/._i_n_p_u_t_r_c. When a program which uses the read- - line library starts up, the init file is read, and the key - bindings and variables are set. There are only a few basic - constructs allowed in the readline init file. Blank lines - are ignored. Lines beginning with a # are comments. Lines - beginning with a $ indicate conditional constructs. Other - lines denote key bindings and variable settings. Each pro- - gram using this library may add its own commands and bind- - ings. - - For example, placing - - M-Control-u: universal-argument - or - C-Meta-u: universal-argument - into the ~/._i_n_p_u_t_r_c would make M-C-u execute the readline - command _u_n_i_v_e_r_s_a_l-_a_r_g_u_m_e_n_t. - - The following symbolic character names are recognized while - processing key bindings: _R_U_B_O_U_T, _D_E_L, _E_S_C, _L_F_D, _N_E_W_L_I_N_E, - _R_E_T, _R_E_T_U_R_N, _S_P_C, _S_P_A_C_E, and _T_A_B. In addition to command - names, readline allows keys to be bound to a string that is - inserted when the key is pressed (a _m_a_c_r_o). - - Key Bindings - The syntax for controlling key bindings in the ~/._i_n_p_u_t_r_c - file is simple. All that is required is the name of the - - - -GNU Last change: 1994 July 26 4 - - - - - - -READLINE(3) C LIBRARY FUNCTIONS READLINE(3) - - - - command or the text of a macro and a key sequence to which - it should be bound. The name may be specified in one of two - ways: as a symbolic key name, possibly with _M_e_t_a- or _C_o_n_- - _t_r_o_l- prefixes, or as a key sequence. When using the form - keyname:_f_u_n_c_t_i_o_n-_n_a_m_e or _m_a_c_r_o, _k_e_y_n_a_m_e is the name of a key - spelled out in English. For example: - - Control-u: universal-argument - Meta-Rubout: backward-kill-word - Control-o: ">&output" - - In the above example, _C-_u is bound to the function - universal-argument, _M-_D_E_L is bound to the function - backward-kill-word, and _C-_o is bound to run the macro - expressed on the right hand side (that is, to insert the - text >&_o_u_t_p_u_t into the line). - - In the second form, "keyseq":_f_u_n_c_t_i_o_n-_n_a_m_e or _m_a_c_r_o, keyseq - differs from keyname above in that strings denoting an - entire key sequence may be specified by placing the sequence - within double quotes. Some GNU Emacs style key escapes can - be used, as in the following example. - - "\C-u": universal-argument - "\C-x\C-r": re-read-init-file - "\e[11~": "Function Key 1" - - In this example, _C-_u is again bound to the function - universal-argument. _C-_x _C-_r is bound to the function - re-read-init-file, and _E_S_C [ _1 _1 ~ is bound to insert the - text Function Key 1. The full set of escape sequences is - - \C- control prefix - - \M- meta prefix - - \e an escape character - - \\ backslash - - " \" literal " - - \' literal ' - - When entering the text of a macro, single or double quotes - should be used to indicate a macro definition. Unquoted - text is assumed to be a function name. Backslash will quote - any character in the macro text, including " and '. - - Bash allows the current readline key bindings to be - displayed or modified with the bind builtin command. The - editing mode may be switched during interactive use by using - - - -GNU Last change: 1994 July 26 5 - - - - - - -READLINE(3) C LIBRARY FUNCTIONS READLINE(3) - - - - the -o option to the set builtin command. Other programs - using this library provide similar mechanisms. The _i_n_p_u_t_r_c - file may be edited and re-read if a program does not provide - any other means to incorporate new bindings. - - Variables - Readline has variables that can be used to further customize - its behavior. A variable may be set in the _i_n_p_u_t_r_c file - with a statement of the form - - set _v_a_r_i_a_b_l_e-_n_a_m_e _v_a_l_u_e - - Except where noted, readline variables can take the values - On or Off. The variables and their default values are: - - horizontal-scroll-mode (Off) - When set to On, makes readline use a single line for - display, scrolling the input horizontally on a single - screen line when it becomes longer than the screen - width rather than wrapping to a new line. - editing-mode (emacs) - Controls whether readline begins with a set of key - bindings similar to _e_m_a_c_s or _v_i. editing-mode can be - set to either emacs or vi. - mark-modified-lines (Off) - If set to On, history lines that have been modified are - displayed with a preceding asterisk (*). - bell-style (audible) - Controls what happens when readline wants to ring the - terminal bell. If set to none, readline never rings - the bell. If set to visible, readline uses a visible - bell if one is available. If set to audible, readline - attempts to ring the terminal's bell. - comment-begin (``#'') - The string that is inserted in vi mode when the - vi-comment command is executed. - meta-flag (Off) - If set to On, readline will enable eight-bit input - (that is, it will not strip the high bit from the char- - acters it reads), regardless of what the terminal - claims it can support. - convert-meta (On) - If set to On, readline will convert characters with the - eighth bit set to an ASCII key sequence by stripping - the eighth bit and prepending an escape character (in - effect, using escape as the _m_e_t_a _p_r_e_f_i_x). - output-meta (Off) - If set to On, readline will display characters with the - eighth bit set directly rather than as a meta-prefixed - escape sequence. - completion-query-items (100) - This determines when the user is queried about viewing - - - -GNU Last change: 1994 July 26 6 - - - - - - -READLINE(3) C LIBRARY FUNCTIONS READLINE(3) - - - - the number of possible completions generated by the - possible-completions command. It may be set to any - integer value greater than or equal to zero. If the - number of possible completions is greater than or equal - to the value of this variable, the user is asked - whether or not he wishes to view them; otherwise they - are simply listed on the terminal. - keymap (emacs) - Set the current readline keymap. The set of legal key- - map names is _e_m_a_c_s, _e_m_a_c_s-_s_t_a_n_d_a_r_d, _e_m_a_c_s-_m_e_t_a, _e_m_a_c_s- - _c_t_l_x, _v_i, _v_i-_m_o_v_e, _v_i-_c_o_m_m_a_n_d, and _v_i-_i_n_s_e_r_t. _v_i is - equivalent to _v_i-_c_o_m_m_a_n_d; _e_m_a_c_s is equivalent to - _e_m_a_c_s-_s_t_a_n_d_a_r_d. The default value is _e_m_a_c_s; the value - of editing-mode also affects the default keymap. - show-all-if-ambiguous (Off) - This alters the default behavior of the completion - functions. If set to on, words which have more than - one possible completion cause the matches to be listed - immediately instead of ringing the bell. - expand-tilde (Off) - If set to on, tilde expansion is performed when read- - line attempts word completion. - - Conditional Constructs - Readline implements a facility similar in spirit to the con- - ditional compilation features of the C preprocessor which - allows key bindings and variable settings to be performed as - the result of tests. There are three parser directives - used. - - $if The $if construct allows bindings to be made based on - the editing mode, the terminal being used, or the - application using readline. The text of the test - extends to the end of the line; no characters are - required to isolate it. - - mode The mode= form of the $if directive is used to - test whether readline is in emacs or vi mode. - This may be used in conjunction with the set key- - map command, for instance, to set bindings in the - _e_m_a_c_s-_s_t_a_n_d_a_r_d and _e_m_a_c_s-_c_t_l_x keymaps only if - readline is starting out in emacs mode. - - term The term= form may be used to include terminal- - specific key bindings, perhaps to bind the key - sequences output by the terminal's function keys. - The word on the right side of the = is tested - against the full name of the terminal and the por- - tion of the terminal name before the first -. - This allows _s_u_n to match both _s_u_n and _s_u_n-_c_m_d, for - instance. - - - - -GNU Last change: 1994 July 26 7 - - - - - - -READLINE(3) C LIBRARY FUNCTIONS READLINE(3) - - - - application - The application construct is used to include - application-specific settings. Each program using - the readline library sets the _a_p_p_l_i_c_a_t_i_o_n _n_a_m_e, - and an initialization file can test for a particu- - lar value. This could be used to bind key - sequences to functions useful for a specific pro- - gram. For instance, the following command adds a - key sequence that quotes the current or previous - word in Bash: - $if bash - # Quote the current or previous word - "\C-xq": "\eb\"\ef\"" - $endif - - $endif - This command, as you saw in the previous example, ter- - minates an $if command. - - $else - Commands in this branch of the $if directive are exe- - cuted if the test fails. - -EDITING COMMANDS - The following is a list of the names of the commands and the - default key sequences to which they are bound. - - Commands for Moving - beginning-of-line (C-a) - Move to the start of the current line. - end-of-line (C-e) - Move to the end of the line. - forward-char (C-f) - Move forward a character. - backward-char (C-b) - Move back a character. - forward-word (M-f) - Move forward to the end of the next word. Words are - composed of alphanumeric characters (letters and - digits). - backward-word (M-b) - Move back to the start of this, or the previous, word. - Words are composed of alphanumeric characters (letters - and digits). - clear-screen (C-l) - Clear the screen leaving the current line at the top of - the screen. With an argument, refresh the current line - without clearing the screen. - redraw-current-line - Refresh the current line. By default, this is unbound. - - - - - -GNU Last change: 1994 July 26 8 - - - - - - -READLINE(3) C LIBRARY FUNCTIONS READLINE(3) - - - - Commands for Manipulating the History - accept-line (Newline, Return) - Accept the line regardless of where the cursor is. If - this line is non-empty, add it to the history list. If - the line is a modified history line, then restore the - history line to its original state. - previous-history (C-p) - Fetch the previous command from the history list, mov- - ing back in the list. - next-history (C-n) - Fetch the next command from the history list, moving - forward in the list. - beginning-of-history (M-<) - Move to the first line in the history. - end-of-history (M->) - Move to the end of the input history, i.e., the line - currently being entered. - reverse-search-history (C-r) - Search backward starting at the current line and moving - `up' through the history as necessary. This is an - incremental search. - forward-search-history (C-s) - Search forward starting at the current line and moving - `down' through the history as necessary. This is an - incremental search. - non-incremental-reverse-search-history (M-p) - Search backward through the history starting at the - current line using a non-incremental search for a - string supplied by the user. - non-incremental-forward-search-history (M-n) - Search forward through the history using a - non-incremental search for a string supplied by the - user. - history-search-forward - Search forward through the history for the string of - characters between the start of the current line and - the current point. This is a non-incremental search. - By default, this command is unbound. - history-search-backward - Search backward through the history for the string of - characters between the start of the current line and - the current point. This is a non-incremental search. - By default, this command is unbound. - yank-nth-arg (M-C-y) - Insert the first argument to the previous command (usu- - ally the second word on the previous line) at point - (the current cursor position). With an argument _n, - insert the _nth word from the previous command (the - words in the previous command begin with word 0). A - negative argument inserts the _nth word from the end of - the previous command. - yank-last-arg (M-., M-_) - - - -GNU Last change: 1994 July 26 9 - - - - - - -READLINE(3) C LIBRARY FUNCTIONS READLINE(3) - - - - Insert the last argument to the previous command (the - last word on the previous line). With an argument, - behave exactly like yank-nth-arg. - - Commands for Changing Text - delete-char (C-d) - Delete the character under the cursor. If point is at - the beginning of the line, there are no characters in - the line, and the last character typed was not C-d, - then return EOF. - backward-delete-char (Rubout) - Delete the character behind the cursor. When given a - numeric argument, save the deleted text on the - kill-ring. - quoted-insert (C-q, C-v) - Add the next character that you type to the line verba- - tim. This is how to insert characters like C-q, for - example. - tab-insert (M-TAB) - Insert a tab character. - self-insert (a, b, A, 1, !, ...) - Insert the character typed. - transpose-chars (C-t) - Drag the character before point forward over the char- - acter at point. Point moves forward as well. If point - is at the end of the line, then transpose the two char- - acters before point. Negative arguments don't work. - transpose-words (M-t) - Drag the word behind the cursor past the word in front - of the cursor moving the cursor over that word as well. - upcase-word (M-u) - Uppercase the current (or following) word. With a - negative argument, do the previous word, but do not - move point. - downcase-word (M-l) - Lowercase the current (or following) word. With a - negative argument, do the previous word, but do not - move point. - capitalize-word (M-c) - Capitalize the current (or following) word. With a - negative argument, do the previous word, but do not - move point. - - Killing and Yanking - kill-line (C-k) - Kill the text from the current cursor position to the - end of the line. - backward-kill-line (C-x Rubout) - Kill backward to the beginning of the line. - unix-line-discard (C-u) - Kill backward from point to the beginning of the line. - kill-whole-line - - - -GNU Last change: 1994 July 26 10 - - - - - - -READLINE(3) C LIBRARY FUNCTIONS READLINE(3) - - - - Kill all characters on the current line, no matter - where the cursor is. By default, this is unbound. - kill-word (M-d) - Kill from the cursor to the end of the current word, or - if between words, to the end of the next word. Word - boundaries are the same as those used by forward-word. - backward-kill-word (M-Rubout) - Kill the word behind the cursor. Word boundaries are - the same as those used by backward-word. - unix-word-rubout (C-w) - Kill the word behind the cursor, using white space as a - word boundary. The word boundaries are different from - backward-kill-word. - delete-horizontal-space - Delete all spaces and tabs around point. By default, - this is unbound. - yank (C-y) - Yank the top of the kill ring into the buffer at the - cursor. - yank-pop (M-y) - Rotate the kill-ring, and yank the new top. Only works - following yank or yank-pop. - - Numeric Arguments - digit-argument (M-0, M-1, ..., M--) - Add this digit to the argument already accumulating, or - start a new argument. M-- starts a negative argument. - universal-argument - Each time this is executed, the argument count is mul- - tiplied by four. The argument count is initially one, - so executing this function the first time makes the - argument count four. By default, this is not bound to - a key. - - Completing - complete (TAB) - Attempt to perform completion on the text before point. - The actual completion performed is application- - specific. Bash, for instance, attempts completion - treating the text as a variable (if the text begins - with $), username (if the text begins with ~), hostname - (if the text begins with @), or command (including - aliases and functions) in turn. If none of these pro- - duces a match, filename completion is attempted. Gdb, - on the other hand, allows completion of program func- - tions and variables, and only attempts filename comple- - tion under certain circumstances. - possible-completions (M-?) - List the possible completions of the text before point. - insert-completions - Insert all completions of the text before point that - would have been generated by possible-completions. By - - - -GNU Last change: 1994 July 26 11 - - - - - - -READLINE(3) C LIBRARY FUNCTIONS READLINE(3) - - - - default, this is not bound to a key. - - Keyboard Macros - start-kbd-macro (C-x () - Begin saving the characters typed into the current key- - board macro. - end-kbd-macro (C-x )) - Stop saving the characters typed into the current key- - board macro and save the definition. - call-last-kbd-macro (C-x e) - Re-execute the last keyboard macro defined, by making - the characters in the macro appear as if typed at the - keyboard. - - Miscellaneous - re-read-init-file (C-x C-r) - Read in the contents of your init file, and incorporate - any bindings or variable assignments found there. - abort (C-g) - Abort the current editing command and ring the - terminal's bell (subject to the setting of bell-style). - do-uppercase-version (M-a, M-b, ...) - Run the command that is bound to the corresponding - uppercase character. - prefix-meta (ESC) - Metafy the next character typed. ESC f is equivalent - to Meta-f. - undo (C-_, C-x C-u) - Incremental undo, separately remembered for each line. - revert-line (M-r) - Undo all changes made to this line. This is like typ- - ing the undo command enough times to return the line to - its initial state. - tilde-expand (M-~) - Perform tilde expansion on the current word. - dump-functions - Print all of the functions and their key bindings to - the readline output stream. If a numeric argument is - supplied, the output is formatted in such a way that it - can be made part of an _i_n_p_u_t_r_c file. - emacs-editing-mode (C-e) - When in vi editing mode, this causes a switch to emacs - editing mode. - vi-editing-mode (M-C-j) - When in emacs editing mode, this causes a switch to vi - editing mode. - -DEFAULT KEY BINDINGS - The following is a list of the default emacs and vi bind- - ings. Characters with the 8th bit set are written as M- - , and are referred to as _m_e_t_a_f_i_e_d characters. - The printable ASCII characters not mentioned in the list of - - - -GNU Last change: 1994 July 26 12 - - - - - - -READLINE(3) C LIBRARY FUNCTIONS READLINE(3) - - - - emacs standard bindings are bound to the _s_e_l_f-_i_n_s_e_r_t func- - tion, which just inserts the given character into the input - line. In vi insertion mode, all characters not specifically - mentioned are bound to _s_e_l_f-_i_n_s_e_r_t. Characters assigned to - signal generation by _s_t_t_y(1) or the terminal driver, such as - C-Z or C-C, retain that function. Upper and lower case - _m_e_t_a_f_i_e_d characters are bound to the same function in the - emacs mode meta keymap. The remaining characters are - unbound, which causes readline to ring the bell (subject to - the setting of the bell-style variable). - - Emacs Mode - Emacs Standard bindings - - "C-A" -> beginning-of-line - "C-B" -> backward-char - "C-D" -> delete-char - "C-E" -> end-of-line - "C-F" -> forward-char - "C-G" -> abort - "C-H" -> backward-delete-char - "C-I" -> complete - "C-J" -> accept-line - "C-K" -> kill-line - "C-L" -> clear-screen - "C-M" -> accept-line - "C-N" -> next-history - "C-P" -> previous-history - "C-Q" -> quoted-insert - "C-R" -> reverse-search-history - "C-S" -> forward-search-history - "C-T" -> transpose-chars - "C-U" -> unix-line-discard - "C-V" -> quoted-insert - "C-W" -> unix-word-rubout - "C-Y" -> yank - "C-_" -> undo - " " to "/" -> self-insert - "0" to "9" -> self-insert - ":" to "~" -> self-insert - "C-?" -> backward-delete-char - - Emacs Meta bindings - - "M-C-H" -> backward-kill-word - "M-C-I" -> tab-insert - "M-C-J" -> vi-editing-mode - "M-C-M" -> vi-editing-mode - "M-C-R" -> revert-line - "M-C-Y" -> yank-nth-arg - "M-C-[" -> complete - "M-&" -> tilde-expand - - - -GNU Last change: 1994 July 26 13 - - - - - - -READLINE(3) C LIBRARY FUNCTIONS READLINE(3) - - - - "M--" -> digit-argument - "M-0" -> digit-argument - "M-1" -> digit-argument - "M-2" -> digit-argument - "M-3" -> digit-argument - "M-4" -> digit-argument - "M-5" -> digit-argument - "M-6" -> digit-argument - "M-7" -> digit-argument - "M-8" -> digit-argument - "M-9" -> digit-argument - "M-<" -> beginning-of-history - "M->" -> end-of-history - "M-?" -> possible-completions - "M-B" -> backward-word - "M-C" -> capitalize-word - "M-D" -> kill-word - "M-F" -> forward-word - "M-L" -> downcase-word - "M-N" -> non-incremental-forward-search-history - "M-O" -> arrow-key-prefix - "M-P" -> non-incremental-reverse-search-history - "M-R" -> revert-line - "M-T" -> transpose-words - "M-U" -> upcase-word - "M-Y" -> yank-pop - "M-C-Y" -> yank-nth-arg - "M-C-?" -> backward-delete-word - - Emacs Control-X bindings - - "C-XC-G" -> abort - "C-XC-R" -> re-read-init-file - "C-XC-U" -> undo - "C-X(" -> start-kbd-macro - "C-X)" -> end-kbd-macro - "C-Xe" -> call-last-kbd-macro - "C-XC-?" -> backward-kill-line - - - VI Mode bindings - VI Insert Mode functions - - "C-D" -> vi-eof-maybe - "C-H" -> backward-delete-char - "C-I" -> complete - "C-J" -> accept-line - "C-K" -> kill-line - "C-L" -> clear-screen - "C-M" -> accept-line - "C-N" -> next-history - "C-P" -> previous-history - - - -GNU Last change: 1994 July 26 14 - - - - - - -READLINE(3) C LIBRARY FUNCTIONS READLINE(3) - - - - "C-Q" -> quoted-insert - "C-R" -> reverse-search-history - "C-S" -> forward-search-history - "C-T" -> transpose-chars - "C-U" -> unix-line-discard - "C-V" -> quoted-insert - "C-W" -> unix-word-rubout - "C-Y" -> yank - "C-[" -> vi-movement-mode - " " to "~" -> self-insert - "C-?" -> backward-delete-char - - VI Command Mode functions - - "C-D" -> vi-eof-maybe - "C-E" -> emacs-editing-mode - "C-G" -> abort - "C-H" -> backward-char - "C-J" -> accept-line - "C-K" -> kill-line - "C-L" -> clear-screen - "C-M" -> accept-line - "C-N" -> next-history - "C-P" -> previous-history - "C-Q" -> quoted-insert - "C-R" -> reverse-search-history - "C-S" -> forward-search-history - "C-T" -> transpose-chars - "C-U" -> unix-line-discard - "C-V" -> quoted-insert - "C-W" -> unix-word-rubout - "C-Y" -> yank - "C-[" -> abort - " " -> forward-char - "#" -> vi-comment - "$" -> end-of-line - "%" -> vi-match - "&" -> vi-tilde-expand - "*" -> vi-complete - "+" -> down-history - "," -> vi-char-search - "-" -> previous-history - "." -> vi-redo - "/" -> vi-search - "0" -> beginning-of-line - "1" to "9" -> vi-arg-digit - ";" -> vi-char-search - "=" -> vi-complete - "?" -> vi-search - "@" -> is undefined - "A" -> vi-append-eol - "B" -> vi-prev-word - - - -GNU Last change: 1994 July 26 15 - - - - - - -READLINE(3) C LIBRARY FUNCTIONS READLINE(3) - - - - "C" -> vi-change-to - "D" -> vi-delete-to - "E" -> vi-end-word - "F" -> vi-char-search - "I" -> vi-insert-beg - "N" -> vi-search-again - "P" -> vi-put - "R" -> vi-replace - "S" -> vi-subst - "T" -> vi-char-search - "U" -> revert-line - "W" -> vi-next-word - "X" -> backward-delete-char - "Y" -> vi-yank-to - "\" -> vi-complete - "^" -> vi-first-print - "_" -> vi-yank-arg - "a" -> vi-append-mode - "b" -> vi-prev-word - "c" -> vi-change-to - "d" -> vi-delete-to - "e" -> vi-end-word - "f" -> vi-char-search - "h" -> backward-char - "i" -> vi-insertion-mode - "j" -> next-history - "k" -> prev-history - "l" -> forward-char - "n" -> vi-search-again - "r" -> vi-change-char - "s" -> vi-subst - "t" -> vi-char-search - "u" -> undo - "w" -> vi-next-word - "x" -> vi-delete - "y" -> vi-yank-to - "|" -> vi-column - "~" -> vi-change-case - -SEE ALSO - _T_h_e _G_n_u _R_e_a_d_l_i_n_e _L_i_b_r_a_r_y, Brian Fox and Chet Ramey - _T_h_e _G_n_u _H_i_s_t_o_r_y _L_i_b_r_a_r_y, Brian Fox and Chet Ramey - _b_a_s_h(1) - -FILES - ~/._i_n_p_u_t_r_c - Individual readline initialization file - -AUTHORS - Brian Fox, Free Software Foundation (primary author) - bfox@ai.MIT.Edu - - - - -GNU Last change: 1994 July 26 16 - - - - - - -READLINE(3) C LIBRARY FUNCTIONS READLINE(3) - - - - Chet Ramey, Case Western Reserve University - chet@ins.CWRU.Edu - -BUG REPORTS - If you find a bug in readline, you should report it. But - first, you should make sure that it really is a bug, and - that it appears in the latest version of the readline - library that you have. - - Once you have determined that a bug actually exists, mail a - bug report to _b_a_s_h-_m_a_i_n_t_a_i_n_e_r_s@_p_r_e_p._a_i._M_I_T._E_d_u. If you have - a fix, you are welcome to mail that as well! Suggestions - and `philosophical' bug reports may be mailed to _b_u_g- - _b_a_s_h@_p_r_e_p._a_i._M_I_T._E_d_u or posted to the Usenet newsgroup - gnu.bash.bug. - - Comments and bug reports concerning this manual page should - be directed to _c_h_e_t@_i_n_s._C_W_R_U._E_d_u. - -BUGS - It's too big and too slow. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -GNU Last change: 1994 July 26 17 - - - diff --git a/endian.c b/endian.c deleted file mode 100644 index 7de8706..0000000 --- a/endian.c +++ /dev/null @@ -1,148 +0,0 @@ -/* endian.c -- A trick for determining the byte order of a machine. */ - -/* Copyright (C) 1993 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, 675 Mass Ave, Cambridge, MA 02139, USA. */ - -#include -#include -#include "bashansi.h" - -/* The name of this program, as taken from argv[0]. */ -char *progname; - -/* The name of the source file that this code is made from. */ -char source_name[256]; - -/* The name of the define. Either "BIG_ENDIAN" or "LITTLE_ENDIAN". */ -char *endian_define; - -char string[9]; -char nstring[9]; - -/* Stuff "1234" into a long, and compare it against a character string - "1234". If the results are EQ, the machine is big endian like a 68000 - or Sparc, otherwise it is little endian, like a Vax, or 386. */ -main (argc, argv) - int argc; - char **argv; -{ -#if defined (__STDC__) - register size_t i; -#else - register int i; -#endif /* !__STDC__ */ - FILE *stream = (FILE *)NULL; - char *stream_name = "stdout"; - union { - unsigned long l; - char s[sizeof (long)]; - } u; - - progname = argv[0]; - - for (i = strlen (progname); i > 0; i--) - if (progname[i] == '/') - { - progname = progname + i + 1; - break; - } - - strcpy (source_name, progname); - for (i = strlen (source_name); i > 0; i--) - if (source_name[i] == '.') - { - source_name[i] = '\0'; - break; - } - - strcat (source_name, ".c"); - - if (argc == 1) - { - stream_name = "stdout"; - stream = stdout; - } - else if (argc == 2) - { - stream_name = argv[1]; - stream = fopen (stream_name, "w"); - } - else - { - fprintf (stderr, "Usage: %s [output-file]\n", progname); - exit (1); - } - - if (!stream) - { - fprintf (stderr, "%s: %s Cannot be opened or written to.\n", - progname, stream_name); - exit (2); - } - - if (sizeof (long int) == 4) - { - u.l = 0x04030201L; - (void) strcpy (string, "4321"); - } - else if (sizeof (long int) == 8) - { -#if defined (__GNUC__) - unsigned long fake_out_gcc; - - fake_out_gcc = (0x08070605L << 31); - fake_out_gcc = (fake_out_gcc << 1); - u.l = fake_out_gcc | 0x04030201L; -#else - u.l = (0x08070605L << 32) | 0x04030201L; -#endif /* !__GNUC__ */ - (void) strcpy (string, "87654321"); - } - else - { - fprintf (stderr, - "%s: sizeof (long int) = %d, which isn't handled here.\n", - progname, sizeof (long int)); - exit (2); - } - - for (i = 0; i < sizeof (long); i++) - nstring[i] = u.s[i] + '0'; - nstring[i] = '\0'; - - if (strcmp (nstring, string) == 0) - endian_define = "BIG_ENDIAN"; - else - endian_define = "LITTLE_ENDIAN"; - - fprintf (stream, "/* %s - Define BIG or LITTLE endian. */\n\n", stream_name); - fprintf (stream, -"/* This file was automatically created by `%s'. You shouldn't\n\ - edit this file, because your changes will be overwritten. Instead,\n\ - edit the source code file `%s'. */\n\n", - progname, source_name); - - fprintf (stream, "#if !defined (%s)\n", endian_define); - fprintf (stream, "# define %s\n", endian_define); - fprintf (stream, "#endif /* %s */\n", endian_define); - - if (stream != stdout) - fclose (stream); - - exit (0); -} diff --git a/error.c b/error.c index 5ffd4ab..a80810f 100644 --- a/error.c +++ b/error.c @@ -17,12 +17,22 @@ with Bash; see the file COPYING. If not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include "config.h" + #include #include #include -#if defined (HAVE_VFPRINTF) -#include +#if defined (HAVE_UNISTD_H) +# include +#endif + +#if defined (PREFER_STDARG) +# include +#else +# if defined (PREFER_VARARGS) +# include +# endif #endif #include @@ -35,32 +45,53 @@ extern int errno; #include "error.h" #include "command.h" #include "general.h" +#include "externs.h" +#include "input.h" -extern int interactive_shell; +#if defined (HISTORY) +# include "bashhist.h" +#endif + +extern int interactive_shell, interactive; extern char *dollar_vars[]; extern char *shell_name; -extern char *the_current_maintainer; #if defined (JOB_CONTROL) extern pid_t shell_pgrp; +extern int give_terminal_to (); #endif /* JOB_CONTROL */ +/* The current maintainer of the shell. You change this in the + Makefile. */ +#if !defined (MAINTAINER) +#define MAINTAINER "bash-maintainers@prep.ai.mit.edu" +#endif + +char *the_current_maintainer = MAINTAINER; + /* Return the name of the shell or the shell script for error reporting. */ char * get_name_for_error () { - char *name = (char *) NULL; + char *name; - if (!interactive_shell) + name = (char *)NULL; + if (interactive_shell == 0) name = dollar_vars[0]; - if (!name && shell_name && *shell_name) + if (name == 0 && shell_name && *shell_name) name = base_pathname (shell_name); - if (!name) + if (name == 0) +#if defined (PROGRAM) + name = PROGRAM; +#else name = "bash"; +#endif return (name); } -/* Report an error having to do with FILENAME. */ +/* Report an error having to do with FILENAME. This does not use + sys_error so the filename is not interpreted as a printf-style + format string. */ void file_error (filename) char *filename; @@ -68,19 +99,31 @@ file_error (filename) report_error ("%s: %s", filename, strerror (errno)); } -#if !defined (HAVE_VFPRINTF) +#if !defined (USE_VARARGS) void programming_error (reason, arg1, arg2, arg3, arg4, arg5) char *reason; { + char *h; + #if defined (JOB_CONTROL) give_terminal_to (shell_pgrp); #endif /* JOB_CONTROL */ report_error (reason, arg1, arg2); + +#if defined (HISTORY) + if (remember_on_history) + { + h = last_history_line (); + fprintf (stderr, "last command: %s\n", h ? h : "(null)"); + } +#endif + fprintf (stderr, "Report this to %s\n", the_current_maintainer); fprintf (stderr, "Stopping myself..."); fflush (stderr); + abort (); } @@ -94,7 +137,34 @@ report_error (format, arg1, arg2, arg3, arg4, arg5) fprintf (stderr, "\n"); if (exit_immediately_on_error) exit (1); -} +} + +void +parser_error (lineno, format, arg1, arg2, arg3, arg4, arg5); + int lineno; + char *format; + va_dcl +{ + char *ename, *iname; + + ename = get_name_for_error (); + iname = bash_input.name ? bash_input.name : "stdin"; + + if (interactive) + fprintf (stderr, "%s: ", ename); + else if (interactive_shell) + fprintf (stderr, "%s: %s: line %d: ", ename, iname, lineno); + else if (STREQ (ename, iname)) + fprintf (stderr, "%s: line %d: ", ename, lineno); + else + fprintf (stderr, "%s: %s: line %d: ", ename, iname, lineno); + + fprintf (stderr, format, arg1, arg2, arg3, arg4, arg5); + fprintf (stderr, "\n"); + + if (exit_immediately_on_error) + exit (2); +} void fatal_error (format, arg1, arg2, arg3, arg4, arg5) @@ -118,41 +188,78 @@ internal_error (format, arg1, arg2, arg3, arg4, arg5) fprintf (stderr, "\n"); } +void +sys_error (format, arg1, arg2, arg3, arg4, arg5) + char *format; +{ + fprintf (stderr, "%s: ", get_name_for_error ()); + + fprintf (stderr, format, arg1, arg2, arg3, arg4, arg5); + fprintf (stderr, ": %s\n", strerror (errno)); +} + #else /* We have VARARGS support, so use it. */ void -programming_error (va_alist) +#if defined (PREFER_STDARG) +programming_error (const char *format, ...) +#else +programming_error (format, va_alist) + const char *format; va_dcl +#endif { va_list args; - char *format; + char *h; #if defined (JOB_CONTROL) give_terminal_to (shell_pgrp); #endif /* JOB_CONTROL */ +#if defined (PREFER_STDARG) + va_start (args, format); +#else va_start (args); - format = va_arg (args, char *); +#endif + vfprintf (stderr, format, args); fprintf (stderr, "\n"); va_end (args); +#if defined (HISTORY) + if (remember_on_history) + { + h = last_history_line (); + fprintf (stderr, "last command: %s\n", h ? h : "(null)"); + } +#endif + fprintf (stderr, "Tell %s to fix this someday.\n", the_current_maintainer); fprintf (stderr, "Stopping myself..."); fflush (stderr); + abort (); } void -report_error (va_alist) +#if defined (PREFER_STDARG) +report_error (const char *format, ...) +#else +report_error (format, va_alist) + const char *format; va_dcl +#endif { va_list args; - char *format; fprintf (stderr, "%s: ", get_name_for_error ()); + +#if defined (PREFER_STDARG) + va_start (args, format); +#else va_start (args); - format = va_arg (args, char *); +#endif + vfprintf (stderr, format, args); fprintf (stderr, "\n"); @@ -162,15 +269,24 @@ report_error (va_alist) } void -fatal_error (va_alist) +#if defined (PREFER_STDARG) +fatal_error (const char *format, ...) +#else +fatal_error (format, va_alist) + const char *format; va_dcl +#endif { va_list args; - char *format; fprintf (stderr, "%s: ", get_name_for_error ()); + +#if defined (PREFER_STDARG) + va_start (args, format); +#else va_start (args); - format = va_arg (args, char *); +#endif + vfprintf (stderr, format, args); fprintf (stderr, "\n"); @@ -179,30 +295,122 @@ fatal_error (va_alist) } void -internal_error (va_alist) +#if defined (PREFER_STDARG) +internal_error (const char *format, ...) +#else +internal_error (format, va_alist) + const char *format; + va_dcl +#endif +{ + va_list args; + + fprintf (stderr, "%s: ", get_name_for_error ()); + +#if defined (PREFER_STDARG) + va_start (args, format); +#else + va_start (args); +#endif + + vfprintf (stderr, format, args); + fprintf (stderr, "\n"); + + va_end (args); +} + +void +#if defined (PREFER_STDARG) +sys_error (const char *format, ...) +#else +sys_error (format, va_alist) + const char *format; va_dcl +#endif { va_list args; - char *format; fprintf (stderr, "%s: ", get_name_for_error ()); + +#if defined (PREFER_STDARG) + va_start (args, format); +#else + va_start (args); +#endif + + vfprintf (stderr, format, args); + fprintf (stderr, ": %s\n", strerror (errno)); + + va_end (args); +} + +/* An error from the parser takes the general form + + shell_name: input file name: line number: message + + The input file name and line number are omitted if the shell is + currently interactive. If the shell is not currently interactive, + the input file name is inserted only if it is different from the + shell name. */ +void +#if defined (PREFER_STDARG) +parser_error (int lineno, const char *format, ...) +#else +parser_error (lineno, format, va_alist) + int lineno; + const char *format; + va_dcl +#endif +{ + va_list args; + char *ename, *iname; + + ename = get_name_for_error (); + iname = bash_input.name ? bash_input.name : "stdin"; + + if (interactive) + fprintf (stderr, "%s: ", ename); + else if (interactive_shell) + fprintf (stderr, "%s: %s: line %d: ", ename, iname, lineno); + else if (STREQ (ename, iname)) + fprintf (stderr, "%s: line %d: ", ename, lineno); + else + fprintf (stderr, "%s: %s: line %d: ", ename, iname, lineno); + +#if defined (PREFER_STDARG) + va_start (args, format); +#else va_start (args); - format = va_arg (args, char *); +#endif + vfprintf (stderr, format, args); fprintf (stderr, "\n"); va_end (args); + + if (exit_immediately_on_error) + exit (2); } -itrace (va_alist) +void +#if defined (PREFER_STDARG) +itrace (const char *format, ...) +#else +itrace (format, va_alist) + const char *format; va_dcl +#endif { va_list args; - char *format; - fprintf(stderr, "TRACE: pid %d: ", getpid()); + fprintf(stderr, "TRACE: pid %d: ", (int)getpid()); + +#if defined (PREFER_STDARG) + va_start (args, format); +#else va_start (args); - format = va_arg (args, char *); +#endif + vfprintf (stderr, format, args); fprintf (stderr, "\n"); @@ -214,11 +422,16 @@ itrace (va_alist) #if 0 /* A trace function for silent debugging -- doesn't require a control terminal. */ -trace (va_alist) +void +#if defined (PREFER_STDARG) +trace (const char *format, ...) +#else +trace (format, va_alist) + const char *format; va_dcl +#endif { va_list args; - char *format; static FILE *tracefp = (FILE *)NULL; if (tracefp == NULL) @@ -231,8 +444,12 @@ trace (va_alist) fprintf(tracefp, "TRACE: pid %d: ", getpid()); +#if defined (PREFER_STDARG) + va_start (args, format); +#else va_start (args); - format = va_arg (args, char *); +#endif + vfprintf (tracefp, format, args); fprintf (tracefp, "\n"); @@ -240,5 +457,6 @@ trace (va_alist) fflush(tracefp); } -#endif -#endif /* HAVE_VFPRINTF */ +#endif /* 0 */ + +#endif /* USE_VARARGS */ diff --git a/error.h b/error.h index 15a5091..ea4b2ea 100644 --- a/error.h +++ b/error.h @@ -18,17 +18,33 @@ with Bash; see the file COPYING. If not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ +#if !defined (_ERROR_H_) +#define _ERROR_H_ + +#include "stdc.h" + /* Get the name of the shell or shell script for an error message. */ extern char *get_name_for_error (); /* Report an error having to do with FILENAME. */ -extern void file_error (); +extern void file_error __P((char *)); /* Report a programmer's error, and abort. Pass REASON, and ARG1 ... ARG5. */ -extern void programming_error (); +extern void programming_error __P((const char *, ...)); /* General error reporting. Pass FORMAT and ARG1 ... ARG5. */ -extern void report_error (); +extern void report_error __P((const char *, ...)); + +/* Error messages for parts of the parser that don't call report_syntax_error */ +extern void parser_error __P((int, const char *, ...)); /* Report an unrecoverable error and exit. Pass FORMAT and ARG1 ... ARG5. */ -extern void fatal_error (); +extern void fatal_error __P((const char *, ...)); + +/* Report a system error, like BSD warn(3). */ +extern void sys_error __P((const char *, ...)); + +/* Report an internal error. */ +extern void internal_error __P((const char *, ...)); + +#endif /* !_ERROR_H_ */ diff --git a/eval.c b/eval.c new file mode 100644 index 0000000..36083be --- /dev/null +++ b/eval.c @@ -0,0 +1,258 @@ +/* eval.c -- reading and evaluating commands. + + Copyright (C) 1996 Free Software Foundation, Inc. + + This file is part of GNU Bash. + + Bash is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY. No author or distributor accepts responsibility to + anyone for the consequences of using it or for whether it serves + any particular purpose or works at all, unless he says so in + writing. Refer to the GNU Emacs General Public License for full + details. + + Everyone is granted permission to copy, modify and redistribute + Bash, but only under the conditions described in the GNU General + Public License. A copy of this license is supposed to have been + given to you along with GNU Emacs so you can know your rights and + responsibilities. It should be in a file named COPYING. + + Among other things, the copyright notice and this notice must be + preserved on all copies. */ + +#include "config.h" + +#if defined (HAVE_UNISTD_H) +# include +#endif + +#include "bashansi.h" +#include + +#include "shell.h" +#include "flags.h" +#include "trap.h" + +#include "builtins/common.h" + +#include "input.h" +#include "execute_cmd.h" + +extern int yyparse (); + +extern int EOF_reached; +extern int indirection_level, interactive, interactive_shell; +extern int subshell_environment, running_under_emacs; +extern int last_command_exit_value; +extern int need_here_doc; +extern int current_command_number, current_command_line_count, line_number; +extern char *ps1_prompt, **prompt_string_pointer; +extern int expand_aliases; + +/* Read and execute commands until EOF is reached. This assumes that + the input source has already been initialized. */ +int +reader_loop () +{ + int our_indirection_level; + COMMAND *current_command = (COMMAND *)NULL; + + our_indirection_level = ++indirection_level; + + while (EOF_Reached == 0) + { + int code; + + code = setjmp (top_level); + +#if defined (PROCESS_SUBSTITUTION) + unlink_fifo_list (); +#endif /* PROCESS_SUBSTITUTION */ + + if (interactive_shell && signal_is_ignored (SIGINT) == 0) + set_signal_handler (SIGINT, sigint_sighandler); + + if (code != NOT_JUMPED) + { + indirection_level = our_indirection_level; + + switch (code) + { + /* Some kind of throw to top_level has occured. */ + case FORCE_EOF: + case EXITPROG: + current_command = (COMMAND *)NULL; + EOF_Reached = EOF; + goto exec_done; + + case DISCARD: + last_command_exit_value = 1; + if (subshell_environment) + { + current_command = (COMMAND *)NULL; + EOF_Reached = EOF; + goto exec_done; + } + /* Obstack free command elements, etc. */ + if (current_command) + { + dispose_command (current_command); + current_command = (COMMAND *)NULL; + } + break; + + default: + programming_error ("reader_loop: bad jump: code %d", code); + } + } + + executing = 0; + dispose_used_env_vars (); + +#if (defined (ultrix) && defined (mips)) || defined (C_ALLOCA) + /* Attempt to reclaim memory allocated with alloca (). */ + (void) alloca (0); +#endif + + if (read_command () == 0) + { + if (interactive_shell == 0 && read_but_dont_execute) + { + last_command_exit_value = EXECUTION_SUCCESS; + dispose_command (global_command); + global_command = (COMMAND *)NULL; + } + else if (current_command = global_command) + { + global_command = (COMMAND *)NULL; + current_command_number++; + + executing = 1; + execute_command (current_command); + + exec_done: + if (current_command) + { + dispose_command (current_command); + current_command = (COMMAND *)NULL; + } + + QUIT; + } + } + else + { + /* Parse error, maybe discard rest of stream if not interactive. */ + if (interactive == 0) + EOF_Reached = EOF; + } + if (just_one_command) + EOF_Reached = EOF; + } + indirection_level--; + return (last_command_exit_value); +} + +static sighandler +alrm_catcher(i) + int i; +{ + printf ("%ctimed out waiting for input: auto-logout\n", '\07'); + jump_to_top_level (EXITPROG); + SIGRETURN (0); +} + +/* Send an escape sequence to emacs term mode to tell it the + current working directory. */ +static void +send_pwd_to_eterm () +{ + char *pwd; + + pwd = get_string_value ("PWD"); + if (pwd == 0) + pwd = get_working_directory ("eterm"); + fprintf (stderr, "\032/%s\n", pwd); +} + +/* Call the YACC-generated parser and return the status of the parse. + Input is read from the current input stream (bash_input). yyparse + leaves the parsed command in the global variable GLOBAL_COMMAND. + This is where PROMPT_COMMAND is executed. */ +int +parse_command () +{ + int r; + char *command_to_execute; + + need_here_doc = 0; + run_pending_traps (); + + /* Allow the execution of a random command just before the printing + of each primary prompt. If the shell variable PROMPT_COMMAND + is set then the value of it is the command to execute. */ + if (interactive && bash_input.type != st_string) + { + command_to_execute = get_string_value ("PROMPT_COMMAND"); + if (command_to_execute) + execute_prompt_command (command_to_execute); + + if (running_under_emacs == 2) + send_pwd_to_eterm (); /* Yuck */ + } + + current_command_line_count = 0; + r = yyparse (); + + if (need_here_doc) + gather_here_documents (); + + return (r); +} + +/* Read and parse a command, returning the status of the parse. The command + is left in the globval variable GLOBAL_COMMAND for use by reader_loop. + This is where the shell timeout code is executed. */ +int +read_command () +{ + SHELL_VAR *tmout_var; + int tmout_len, result; + SigHandler *old_alrm; + + prompt_string_pointer = &ps1_prompt; + global_command = (COMMAND *)NULL; + + /* Only do timeouts if interactive. */ + tmout_var = (SHELL_VAR *)NULL; + tmout_len = 0; + + if (interactive) + { + tmout_var = find_variable ("TMOUT"); + old_alrm = (SigHandler *)NULL; + + if (tmout_var && tmout_var->value) + { + tmout_len = atoi (tmout_var->value); + if (tmout_len > 0) + { + old_alrm = set_signal_handler (SIGALRM, alrm_catcher); + alarm (tmout_len); + } + } + } + + QUIT; + + current_command_line_count = 0; + result = parse_command (); + + if (interactive && tmout_var && (tmout_len > 0)) + { + alarm(0); + set_signal_handler (SIGALRM, old_alrm); + } + + return (result); +} diff --git a/examples/alias-conv.sh b/examples/alias-conv.sh deleted file mode 100755 index edbed86..0000000 --- a/examples/alias-conv.sh +++ /dev/null @@ -1,22 +0,0 @@ -#! /bin/sh -# -# Convert Csh aliases to Bash aliases. Adapted from a similar program -# supplied with zsh. -# -# This is a quick script to convert csh aliases to Bash aliases/functions. -# Pipe the output of csh's alias command through this; it will generate -# a series of alias/function definitions on stdout, suitable for -# processing by bash. -# -# This is not perfect, but it gets most common aliases; it should manage to -# cut down a lot of the busy work. -# -sed -e 's/ (\(.*\))/ \1/' >/tmp/cz$$.1 -grep ! /tmp/cz$$.1 >/tmp/cz$$.2 -grep -v ! /tmp/cz$$.1 >/tmp/cz$$.3 -sed -e "s/'/'"\\\\"''"/g -e 's/^\([^ ]*\) \(.*\)$/alias \1='"'\2'/" \ - /tmp/cz$$.3 -sed -e 's/![:#]*/$/g' -e 's/^\([^ ]*\) \(.*\)$/\1 () { \2 }/' /tmp/cz$$.2 -rm /tmp/cz$$.? - -exit 0 diff --git a/examples/bashdb/PERMISSION b/examples/bashdb/PERMISSION new file mode 100644 index 0000000..4e9460c --- /dev/null +++ b/examples/bashdb/PERMISSION @@ -0,0 +1,27 @@ +From mikel@ora.com Tue Aug 1 12:13:20 1995 +Flags: 10 +Return-Path: mikel@ora.com +Received: from ruby.ora.com (ruby.ora.com [198.112.208.25]) by odin.INS.CWRU.Edu with ESMTP (8.6.12+cwru/CWRU-2.1-ins) + id MAA01565; Tue, 1 Aug 1995 12:13:18 -0400 (from mikel@ora.com for ) +Received: (from fax@localhost) by ruby.ora.com (8.6.12/8.6.11) with UUCP id MAA23251; Tue, 1 Aug 1995 12:07:51 -0400 +Received: by los.ora.com (4.1/Spike-2.1) + id AA00672; Tue, 1 Aug 95 08:57:32 EDT +Date: Tue, 1 Aug 95 08:57:32 EDT +From: mikel@ora.com (Michael Loukides) +Message-Id: <9508011257.AA00672@los.ora.com> +Subject: Re: Ksh debugger from Rosenblatt's book [for bash] +To: Chet Ramey +Cc: cmarie@ora.com, cam@iinet.com.au, brosenblatt@tm.com +In-Reply-To: Chet Ramey , Mon, 31 Jul 1995 16:22:48 -0400 + + I've modified a (modified) version of Bill Rosenblatt's ksh debugger + to work with bash-2.0. Does ORA have any problem with me distributing + it with bash-2.0? + +That's great! + +Go ahead and circulate it; in fact, we should probably grab it and +stick it in our ftp archive, and put a reference to it in the book. +(Too late to actually discuss the thing, at least for this edition). +------- + diff --git a/examples/bashdb/README b/examples/bashdb/README new file mode 100644 index 0000000..aa3aea7 --- /dev/null +++ b/examples/bashdb/README @@ -0,0 +1,8 @@ +This is a modified version of the Korn Shell debugger from Bill +Rosenblatt's `Learning the Korn Shell', published by O'Reilly +and Associates (ISBN 1-56592-054-6). + +The original `kshdb' is available for anonymous FTP with the URL + +ftp://ftp.uu.net/published/oreilly/nutshell/ksh/ksh.tar.Z + diff --git a/examples/bashdb/bashdb b/examples/bashdb/bashdb new file mode 100644 index 0000000..9e79d71 --- /dev/null +++ b/examples/bashdb/bashdb @@ -0,0 +1,29 @@ +# kshdb - Korn Shell Debugger main file +# adapted from 'Learning the Korn Shell' by Bill Rosenblatt (O'Reilly) +# by Cigy Cyriac (cigy@felix.tulblr.unisys.com) +# Main driver: constructs full script (with preamble) and runs it + +echo 'Bourne-Again Shell Debugger version 0.1' + +_pname=${0##*/} + +[ $# -eq 0 ] && { + echo "${_pname}: usage: ${_pname} " + exit 1 +} + +_guineapig=$1 + +[ -r $_guineapig ] || { + echo "${_pname}: cannot read $_guineapig." >&2 + exit 1 +} +shift + +_tmpdir=/tmp +_libdir=. +_dbgfile=$_tmpdir/bashdb$$ #temp file for script being debugged + +cat $_libdir/bashdb.pre $_guineapig > $_dbgfile +exec bash $_dbgfile $_guineapig $_tmpdir $_libdir "$@" +# end of bashdb diff --git a/examples/bashdb/bashdb.fns b/examples/bashdb/bashdb.fns new file mode 100644 index 0000000..9a9aa49 --- /dev/null +++ b/examples/bashdb/bashdb.fns @@ -0,0 +1,235 @@ +# bashdb.fns - Bourne-Again Shell Debugger functions + +_BUFSIZ=100 + +# Here after each statement in script being debugged. +# Handle single-step and breakpoints. +_steptrap() { + let _curline=$1-1 # no. of line that just ran + let "$_curline < 1" && let _curline=1 + + let "$_curline > $_firstline+$_BUFSIZ" && _readin $_curline + + let " $_trace" && + _msg "$PS4, line $_curline: ${_lines[$(($_curline-$_firstline+1))]}" + + # if in step mode, decrement counter + let " $_steps >= 0" && let _steps="$_steps - 1" + + # first check if line num or string brkpt. reached + if _at_linenumbp || _at_stringbp; then + _msg "Reached breakpoint at line $_curline" + _cmdloop # enter debugger + + # if not, check whether break condition exists and is true + elif [ -n "$_brcond" ] && eval $_brcond; then + _msg "Break condition $_brcond true at line $_curline" + _cmdloop # enter debugger + + # next, check if step mode and no. of steps is up + elif let "$_steps == 0"; then + _msg "Stopped at line $_curline" + _cmdloop # enter debugger + fi +} + + +# Debugger command loop. +# Here at start of debugger session, when brkpt. reached, or after single-step. +_cmdloop() { + local cmd args + +# added support for default command (last one entered) + + while read -e -p "bashdb> [$lastcmd $lastargs] " cmd args; do + if [ -z "$cmd" ]; then + cmd=$lastcmd + args=$lastargs + fi + + lastcmd="$cmd" + lastargs=$args + +# made commands to be debugger commands by default, no need for '*' prefix + + case $cmd in + bp ) _setbp $args ;; #set brkpt at line num or string + + bc ) _setbc $args ;; # set break condition + + cb ) _clearbp ;; # clear all brkpts. + + g ) return ;; # start/resume execution + + s ) let _steps=${args:-1} + return ;; # single-step N times(default 1) + + x ) _xtrace ;; # toggle execution trace + + pr ) _print $args ;; # print lines in file + + \? | h | help ) _menu ;; # print command menu + + hi ) history ;; # show command history + + q ) _cleanup; exit ;; # quit + + \! ) eval $args ;; # run shell command + + * ) _msg "Invalid command: $cmd" ; _menu ;; + esac + done +} + + +# see if next line no. is a brkpt. +_at_linenumbp() { + if [ -z "${_linebp}" ]; then + return 1 + fi + echo "${curline}" | egrep -s "(${linebp%\|})" >/dev/null 2>&1 + return $? +} + + +# search string brkpts to see if next line in script matches. +_at_stringbp() { + local l; + if [ -z "$_stringbp" ]; then + return 1; + fi + l=${_lines[$_curline-$_firstline+1]} + echo "${l} | egrep -s "*(${stringbp%\|})*" >/dev/null 2>&1 + return $? +} + + +# print message to stderr +_msg() { + echo -e "$@" >&2 +} + + +# set brkpt(s) at given line numbers and/or strings +# by appending lines to brkpt file +_setbp() { + declare -i n + case "$1" in + "") _listbp ;; + [0-9]*) #number, set brkpt at that line + n=$1 + _linebp="${_linebp}$n|" + _msg "Breakpoint at line " $1 + ;; + *) #string, set brkpt at next line w/string + _stringbp="${_stringbp}$@|" + _msg "Breakpoint at next line containing $@." + ;; + esac +} + + +# list brkpts and break condition. +_listbp() { + _msg "Breakpoints at lines:" + _msg "$(echo $_linebp | tr '|' ' ')" + _msg "Breakpoints at strings:" + _msg "$(echo $_stringbp | tr '|' ' ')" + _msg "Break on condition:" + _msg "$_brcond" +} + + +# set or clear break condition +_setbc() { + if [ -n "$@" ] ; then + _brcond=$args + _msg "Break when true: $_brcond" + else + _brcond= + _msg "Break condition cleared" + fi +} + + +# clear all brkpts +_clearbp() { + _linebp= + _stringbp= + _msg "All breakpoints cleared" +} + + +# toggle execution trace feature +_xtrace() { + let _trace="! $_trace" + + _msg "Execution trace \c" + let " $_trace" && _msg "on." || _msg "off." +} + + +# print command menu +_menu() { + +# made commands to be debugger commands by default, no need for '*' prefix + + _msg 'bashdb commands: + bp N set breakpoint at line N + bp string set breakpoint at next line containing "string" + bp list breakpoints and break condition + bc string set break condition to "string" + bc clear break condition + cb clear all breakpoints + g start/resume execution + s [N] execute N statements (default 1) + x toggle execution trace on/off (default on) + pr [start|.] [cnt] print "cnt" lines from line no. "start" + ?, h, help print this menu + hi show command history + q quit + + ! cmd [args] execute command "cmd" with "args" + + default: last command (in "[ ]" at the prompt) + + Readline command line editing (emacs/vi mode) is available' +} + + +# erase temp files before exiting +_cleanup() { + rm $_dbgfile 2>/dev/null +} + + +# read $_BUFSIZ lines from $_guineapig into _lines array, starting from line $1 +# save number of first line read in _firstline +_readin() { + declare -i _i=1 + let _firstline=$1 + + SEDCMD="$_firstline,$(($_firstline+$_BUFSIZ))p" + + sed -n "$SEDCMD" $_guineapig > /tmp/_script.$$ + while read -r _lines[$_i]; do + _i=_i+1 + done < /tmp/_script.$$ + rm -f /tmp/_script.$$ 2>/dev/null +} + +_print() { + typeset _start _cnt + + if [ -z "$1" ] || [ "$1" = . ]; then + _start=$_curline + else + _start=$1 + fi + + _cnt=${2:-9} + + SEDCMD="$_start,$(($_start+$_cnt))p" + + pr -tn $_guineapig | sed -n "$SEDCMD" +} diff --git a/examples/bashdb/bashdb.pre b/examples/bashdb/bashdb.pre new file mode 100644 index 0000000..e692727 --- /dev/null +++ b/examples/bashdb/bashdb.pre @@ -0,0 +1,37 @@ +# bashdb.pre - Bourne-Again Shell Debugger preamble file +# prepended to script being ddebugged +#arguments: +# $1 = name of original guineapig script +# $2 = dir where temp files are stored +# $3 = dir where bashdb.pre and bashdb.fns are stored + +# separate history file for bashdb +HISTFILE=~/.bashdb_history +set -o history +set +H + +# prompt for trace line +PS4=$1 + +_dbgfile=$0 +_guineapig=$1 +_tmpdir=$2 +_libdir=$3 +shift 3 #move user's args into place + +. $_libdir/bashdb.fns #read in the debugger functions + +_linebp= +_stringbp= +let _trace=1 #init execution trace flag to on + +#read guineapig file into _lines array +_readin 1 + +trap _cleanup EXIT #erase files before exiting + +let _steps=1 #no. of statements to run after setting trap +#set LINENO, gets incremented to 1 +LINENO=0 +trap '_steptrap $LINENO' DEBUG +: diff --git a/examples/functions/autoload b/examples/functions/autoload index a6ae421..206b012 100644 --- a/examples/functions/autoload +++ b/examples/functions/autoload @@ -29,7 +29,7 @@ aload() { - eval $1 '() { . '$2' ; '$1' "$@" ; return $?; }' + eval $1 '() { . '$2' ; '$1' "$@" ; return $? ; }' } # diff --git a/examples/functions/autoload.v2 b/examples/functions/autoload.v2 new file mode 100644 index 0000000..8041b84 --- /dev/null +++ b/examples/functions/autoload.v2 @@ -0,0 +1,192 @@ +# +# An almost ksh-compatible `autoload'. A function declared as `autoload' will +# be read in from a file the same name as the function found by searching the +# $FPATH (which works the same as $PATH), then that definition will be run. +# +# To do this without source support, we define a dummy function that, when +# executed, will load the file (thereby re-defining the function), then +# execute that newly-redefined function with the original arguments. +# +# It's not identical to ksh because ksh apparently does lazy evaluation +# and looks for the file to load from only when the function is referenced. +# This one requires that the file exist when the function is declared as +# `autoload'. +# +# usage: autoload [-pu] [func ...] +# +# options: +# -p print in a format that can be reused as input +# -u unset each function and remove it from the autoload list +# +# The first cut of this was by Bill Trost, trost@reed.bitnet +# +# Chet Ramey +# chet@ins.CWRU.Edu + +unset _AUTOLOADS +_aindex=0 + +# +# Declare a function ($1) to be autoloaded from a file ($2) when it is first +# called. This defines a `temporary' function that will `.' the file +# containg the real function definition, then execute that new definition with +# the arguments given to this `fake' function. The autoload function defined +# by the file and the file itself *must* be named identically. +# + +_aload() +{ + eval $1 '() { . '$2' ; '$1' "$@" ; return $? ; }' + _autoload_addlist "$1" +} + +_autoload_addlist() +{ + local i=0 + + while (( i < $_aindex )); do + case "${_AUTOLOADS[i]}" in + "$1") return 1 ;; + esac + (( i += 1 )) + done + _AUTOLOADS[_aindex]="$1" + (( _aindex += 1 )) + return 0 +} + +_autoload_dump() +{ + local func + + for func in ${_AUTOLOADS[@]}; do + [ -n "$1" ] && echo -n "autoload " + echo "$func" + done +} + +# Remove $1 from the list of autoloaded functions +_autoload_remove_one() +{ + local i=0 nnl=0 + local -a nlist + + while (( i < _aindex )); do + case "${_AUTOLOADS[i]}" in + "$1") ;; + *) nlist[nnl]="${_AUTOLOADS[i]}" ; (( nnl += 1 ));; + esac + (( i += 1 )) + done + unset _AUTOLOADS _aindex + eval _AUTOLOADS=( ${nlist[@]} ) + _aindex=$nnl +} + +# Remove all function arguments from the list of autoloaded functions +_autoload_remove() +{ + local func i es=0 + + # first unset the autoloaded functions + for func; do + i=0 + while (( i < _aindex )); do + case "${_AUTOLOADS[i]}" in + "$func") unset -f $func ; break ;; + esac + (( i += 1 )) + done + if (( i == _aindex )); then + echo "autoload: $func: not an autoloaded function" >&2 + es=1 + fi + done + + # then rebuild the list of autoloaded functions + for func ; do + _autoload_remove_one "$func" + done + + return $es +} + +# +# Search $FPATH for a file the same name as the function given as $1, and +# autoload the function from that file. There is no default $FPATH. +# + +autoload() +{ + local -a fp + local _autoload_unset nfp i + + if (( $# == 0 )) ; then + _autoload_dump + return 0 + fi + + OPTIND=1 + while getopts pu opt + do + case "$opt" in + p) _autoload_dump printable; return 0;; + u) _autoload_unset=y ;; + *) echo "autoload: usage: autoload [-pu] [function ...]" >&2 + return 1 ;; + esac + done + + shift $(( $OPTIND - 1 )) + + if [ -n "$_autoload_unset" ]; then + _autoload_remove "$@" + return $? + fi + + # + # If there is no $FPATH, there is no work to be done + # + + if [ -z "$FPATH" ] ; then + echo "autoload: FPATH not set or null" >&2 + return 1 + fi + + # + # This treats FPATH exactly like PATH: a null field anywhere in the + # FPATH is treated the same as the current directory. + # + # This turns $FPATH into an array, substituting `.' for `' + # + eval fp=( $( + IFS=':' + set -- ${FPATH} + for p in "$@" ; do echo -n "${p:-.} "; done + ) + ) + + nfp=${#fp[@]} + + for FUNC ; do + i=0; + while (( i < nfp )) ; do + if [ -f ${fp[i]}/$FUNC ] ; then + break # found it! + fi + (( i += 1 )) + done + + if (( i == nfp )) ; then + echo "autoload: $FUNC: autoload function not found" >&2 + es=1 + continue + fi + +# echo auto-loading $FUNC from ${fp[i]}/$FUNC + _aload $FUNC ${fp[i]}/$FUNC + es=0 + done + + return $es +} diff --git a/examples/functions/csh-compat b/examples/functions/csh-compat index 8eaf754..a855eaf 100644 --- a/examples/functions/csh-compat +++ b/examples/functions/csh-compat @@ -1,27 +1,15 @@ # C-shell compatabilty package. # setenv VAR VALUE -function setenv () { +function setenv () +{ export $1="$2" } -function unsetenv () { +function unsetenv () +{ unset $1 } -function alias () { - local name=$1 - shift - local value="$*" - - if [ "$name" = "" ]; then - builtin alias - elif [ "$value" = "" ]; then - builtin alias $name - else - builtin alias $name="$value" - fi -} - # Can't write foreach yet. Need pattern matching, and a few extras. function foreach () { echo 'Can'\''t do `foreach'\'' yet. Type "help for".' @@ -31,6 +19,29 @@ echo 'Can'\''t do `foreach'\'' yet. Type "help for".' #set () { #} -chdir () { - builtin cd $* - } +chdir () +{ + builtin cd "$@" +} + +# alias - convert csh alias commands to bash functions +# from Mohit Aron +# posted to usenet as <4i5p17$bnu@larry.rice.edu> +function alias () +{ + if [ "x$2" = "x" ] + then + declare -f $1 + else + echo $2 | egrep -s '(\!|#)' 2>/dev/null + if [ $? -eq 0 ] + then + comm=$(echo $2 | sed 's/\\!\*/\"$\@\"/g + s/\\!:\([1-9]\)/\"$\1\"/g + s/#/\\#/g') + else + comm="$2 \"\$@\"" + fi + eval function $1 \(\) "{" command "$comm" "; }" + fi +} diff --git a/examples/functions/exitstat b/examples/functions/exitstat index bae3f27..2828a89 100644 --- a/examples/functions/exitstat +++ b/examples/functions/exitstat @@ -11,7 +11,7 @@ function check_exit_status () if [ ${status} -ne 0 -a ${status} != 128 ]; then # If process exited by a signal, determine name of signal. if [ ${status} -gt 128 ]; then - signal="$(builtin kill -l $[${status} - 128] 2>/dev/null)" + signal="$(builtin kill -l $((${status} - 128)) 2>/dev/null)" if [ "$signal" ]; then signal="($signal)"; fi fi echo "[Exit ${status} ${signal}]" 1>&2 diff --git a/examples/functions/inpath b/examples/functions/inpath new file mode 100644 index 0000000..7755b33 --- /dev/null +++ b/examples/functions/inpath @@ -0,0 +1,15 @@ +inpath() +{ + path=$(echo $PATH | sed 's/^:/.:/ + s/::/:.:/g + s/:$/:./ + s/:/ /g') + + for x in $path + do + [ -x $x/$1 ] && { PROG=$x/$1; break; } + done + [ -z "$PROG" ] + return +} + diff --git a/examples/functions/keep b/examples/functions/keep new file mode 100644 index 0000000..4433b35 --- /dev/null +++ b/examples/functions/keep @@ -0,0 +1,62 @@ +# From: Seth Chaiklin +# To: chet@ins.CWRU.Edu +# Subject: bash functions (sorta) + +# +# keep: +# usage: keep program +# declare the a program should be "kept". i.e. try to fg a stopped one +# and only when that fails start a fresh program. +# + +keep() +{ + case $# in + 1|2) ;; + *) echo "usage: keep [alias] program" 1>&2 ; return 1;; + esac + + # progname + pn=${1##*/} + + # set up an alias for the kept program + if [ $# = 1 ]; then + alias "$pn=fg $1 2>/dev/null || $1" + else + alias "$1=fg $2 2>/dev/null || $2" + fi +} + +# +# unkeep: +# usage: unkeep program +# unset the alias set up by the keep function +# + +unkeep() +{ + if [ $# != 1 ]; then + echo "usage: unkeep program" + return 2 + fi + + # unset the alias for the kept program + unalias "${1##*/}" +} + +# +# kept: +# lists all kept programs in 'alias: program' form +# + +kept() +{ + alias | grep "fg.*2>" | sed "s/alias \(.*\)='fg.*||\(.*\)'$/\1:\2/" +} + + +# some things that should be kept +#keep /usr/local/bin/emacs +#keep e ${EDITOR:-/usr/local/bin/emacs} +#keep edit ${EDITOR:-/usr/local/bin/emacs} +#keep /usr/local/bin/emm diff --git a/examples/functions/kshenv b/examples/functions/kshenv index fbec76f..636405e 100644 --- a/examples/functions/kshenv +++ b/examples/functions/kshenv @@ -39,13 +39,9 @@ whence() return 1 fi case "$1" in - -v) vflag=1 - shift 1 - ;; - -*) echo "whence: bad option: $1" - return 1 - ;; - *) ;; + -v) vflag=1 ; shift 1 ;; + -*) echo "whence: bad option: $1" ; return 1 ;; + *) ;; esac if [ "$#" = "0" ] ; then @@ -63,15 +59,12 @@ whence() echo $path else case "$cmd" in - /*) echo "" - ;; - *) case "$(builtin type -type $cmd)" in - "") echo "" - ;; - *) echo "$cmd" - ;; - esac - ;; + /*) echo "" ;; + *) case "$(builtin type -type $cmd)" in + "") echo "" ;; + *) echo "$cmd" ;; + esac + ;; esac fi fi @@ -117,7 +110,7 @@ cd() # -n do not add trailing newline # -p no-op (no coprocesses) # -r no escapes -# -s no-op (print to the history file) +# -s print to the history file # -u n redirect output to fd n # @@ -131,20 +124,20 @@ print() while getopts "Rnprsu:" c do case $c in - R) eflag= - ;; - r) eflag= - ;; - n) nflag=-n - ;; - u) fd=$OPTARG - ;; - p|s) ;; + R) eflag= ;; + r) eflag= ;; + n) nflag=-n ;; + s) sflag=y ;; + u) fd=$OPTARG ;; + p) ;; esac done shift $[ $OPTIND - 1 ] - builtin echo $eflag $nflag "$@" >&$fd + case "$sflag" in + y) builtin history -s "$*" ;; + *) builtin echo $eflag $nflag "$@" >&$fd + esac } # substring function diff --git a/examples/functions/login b/examples/functions/login new file mode 100644 index 0000000..3d59683 --- /dev/null +++ b/examples/functions/login @@ -0,0 +1,11 @@ +# replace the `login' and `newgrp' builtins in old bourne shells + +login() +{ + exec login "$@" +} + +newgrp() +{ + exec newgrp "$@" +} diff --git a/examples/functions/lowercase b/examples/functions/lowercase new file mode 100644 index 0000000..5f4fc9d --- /dev/null +++ b/examples/functions/lowercase @@ -0,0 +1,26 @@ +#! /bin/bash +# +# original from +# @(#) lowercase.ksh 1.0 92/10/08 +# 92/10/08 john h. dubois iii (john@armory.com) +# +# conversion to bash v2 syntax done by Chet Ramey + +lowercase() +{ +for file; do + filename=${file##*/} + case "$filename" in + */*) dirname=${file%/*} ;; + *) dirname=.;; + esac + nf=$(echo $filename | tr A-Z a-z) + newname="${dirname}/${nf}" + if [ "$nf" != "$filename" ]; then + mv "$file" "$newname" + echo "$0: $file -> $newname" + else + echo "$0: $file not changed." + fi +done +} diff --git a/examples/functions/mhfold b/examples/functions/mhfold new file mode 100644 index 0000000..a4a5f70 --- /dev/null +++ b/examples/functions/mhfold @@ -0,0 +1,16 @@ +# To: chet@ins.CWRU.Edu +# Subject: Bash functions +# From: Sandeep Mehta + +# print MH folders, useful only because folders(1) doesn't print +# mod date/times + +mhfold() +{ + list=`folders | tail +2 | awk '{print $1}'` + /bin/ls -lag ~/Mail > /tmp/fold$$ + for i in $list; do + grep $i /tmp/fold$$ + done + /bin/rm -f /tmp/fold$$ +} diff --git a/examples/functions/repeat2 b/examples/functions/repeat2 new file mode 100644 index 0000000..2e2dc7a --- /dev/null +++ b/examples/functions/repeat2 @@ -0,0 +1,43 @@ +# To: chet@ins.CWRU.Edu +# Subject: Bash functions +# From: Sandeep Mehta + +########################################## +# +# repeat - clone of C shell builtin `repeat' +# +# usage: repeat +# +# It has been tested inside other functions and in conditionals like +# if [ "`repeat `" ]; then COMMANDS [ else COMMANDS ] fi +# Please send me fixes/enhancements. +# +# Sandeep Mehta +########################################## +repeat() +{ + local rcount=$1 + + if [ $# -le 1 ] || [ -z "$rcount" ]; then + echo "usage: repeat " 1>&2 + return 2 + fi + + shift + + local acmd=("$@") + + if [ $rcount -le 0 ]; then + echo "count must be greater than 0" + echo "usage: repeat " 1>&2 + return 2 + fi + + st=0 + while [ $rcount -gt 0 ]; do + eval "${acmd[@]}" + st=$? + rcount=$((rcount - 1)) + done + return $st +} diff --git a/examples/functions/seq b/examples/functions/seq new file mode 100644 index 0000000..87c8a2c --- /dev/null +++ b/examples/functions/seq @@ -0,0 +1,29 @@ +# Generate a sequence from m to n, m defaults to 1. + +seq () +{ + declare -i lo hi i # makes local + local _SEQ + + case $# in + 1) seq 1 "$1" ; return $? ;; + 2) lo=$1 hi=$2 + i=$lo _SEQ="" + while let "i <= hi"; do + _SEQ="${_SEQ}$i " + let i+=1 + done + echo "${_SEQ# }" + return 0 ;; + *) echo seq: usage: seq [low] high 1>&2 ; return 2 ;; + esac +} + +# like the APL `iota' function (or at least how I remember it :-) +iota() +{ + case $# in + 1) seq 1 "$1"; return $?;; + *) echo "iota: usage: iota high" 1>&2; return 2;; + esac +} diff --git a/examples/functions/shcat b/examples/functions/shcat index 55a3096..c5d3d63 100644 --- a/examples/functions/shcat +++ b/examples/functions/shcat @@ -1,6 +1,6 @@ shcat() { - while read line + while read -r line do echo "$line" done diff --git a/examples/loadables/Makefile b/examples/loadables/Makefile new file mode 100644 index 0000000..9f93bca --- /dev/null +++ b/examples/loadables/Makefile @@ -0,0 +1,112 @@ +# +# Simple makefile for the sample loadable builtins +# +CC = cc + +# SunOS 4 +PICFLAG = -pic +# Some versions of gcc, esp. on NetBSD and FreeBSD +#PICFLAG = -fpic +# Linux -- could also be -fpic +#PICFLAG = -fPIC +# SunOS 5 +#PICFLAG = -K pic +# SVR4, SVR4.2, Irix +#PICFLAG = -K PIC +# BSD/OS 2.1 +#PICFLAG = +# AIX 4.2 +#PICFLAG = -K + +# SunOS 4, BSD/OS 2.1, SVR4.2, SVR4, Linux, AIX 4.2, etc. +LD = ld +# SunOS 5, Linux +#LD = cc + +# SunOS 4 +LDOPT = -assert pure-text +# OSF/1, Digital UNIX +#LDOPT = -shared -soname $@ -expect_unresolved '*' +# SunOS 5 +#LDOPT = -dy -z text -G -i -h $@ +# SVR4, SVR4.2 +#LDOPT = -dy -z text -G -h $@ +# NetBSD, FreeBSD -- might also need -r +#LDOPT = -x -Bshareable +# Linux +#LDOPT = -shared +# BSD/OS 2.1 +#LDOPT = -r +# AIX 4.2 +#LDOPT = -bdynamic -bnoentry -bexpall -G + +# other libraries to link the shared object against +# BSD/OS 2.1 +#LDLIBS = -lc_s.2.1.0 + +srcdir = ../.. +INC= -I$(srcdir) -I$(srcdir)/builtins -I$(srcdir)/lib + +.c.o: + $(CC) $(PICFLAG) $(CFLAGS) $(INC) -c -o $@ $< + +all: printf print truefalse sleep pushd finfo logname basename dirname \ + tty pathchk tee head rmdir sprintf +others: necho getconf hello cat + +printf: printf.o + $(LD) $(LDOPT) -o $@ printf.o $(LDLIBS) + +sprintf: sprintf.o + $(LD) $(LDOPT) -o $@ sprintf.o $(LDLIBS) + +print: print.o + $(LD) $(LDOPT) -o $@ print.o $(LDLIBS) + +necho: necho.o + $(LD) $(LDOPT) -o $@ necho.o $(LDLIBS) + +getconf: getconf.o + $(LD) $(LDOPT) -o $@ getconf.o $(LDLIBS) + +hello: hello.o + $(LD) $(LDOPT) -o $@ hello.o $(LDLIBS) + +truefalse: truefalse.o + $(LD) $(LDOPT) -o $@ truefalse.o $(LDLIBS) + +sleep: sleep.o + $(LD) $(LDOPT) -o $@ sleep.o $(LDLIBS) + +pushd: pushd.o + $(LD) $(LDOPT) -o $@ pushd.o $(LDLIBS) + +finfo: finfo.o + $(LD) $(LDOPT) -o $@ finfo.o $(LDLIBS) + +cat: cat.o + $(LD) $(LDOPT) -o $@ cat.o $(LDLIBS) + +logname: logname.o + $(LD) $(LDOPT) -o $@ logname.o $(LDLIBS) + +basename: basename.o + $(LD) $(LDOPT) -o $@ basename.o $(LDLIBS) + +dirname: dirname.o + $(LD) $(LDOPT) -o $@ dirname.o $(LDLIBS) + +tty: tty.o + $(LD) $(LDOPT) -o $@ tty.o $(LDLIBS) + +pathchk: pathchk.o + $(LD) $(LDOPT) -o $@ pathchk.o $(LDLIBS) + +tee: tee.o + $(LD) $(LDOPT) -o $@ tee.o $(LDLIBS) + +rmdir: rmdir.o + $(LD) $(LDOPT) -o $@ rmdir.o $(LDLIBS) + +head: head.o + $(LD) $(LDOPT) -o $@ head.o $(LDLIBS) diff --git a/examples/loadables/README b/examples/loadables/README new file mode 100644 index 0000000..4c02f47 --- /dev/null +++ b/examples/loadables/README @@ -0,0 +1,27 @@ +Some examples of ready-to-dynamic-load builtins. Most of the +examples given are reimplementations of standard commands whose +execution time is dominated by process startup time. The +exceptions are sleep, which allows you to sleep for fractions +of a second, finfo, which provides access to the rest of the +elements of the `stat' structure that `test' doesn't let you +see, and pushd/popd/dirs, which allows you to compile them out +of the shell. + +All of the new builtins in ksh93 that bash didn't already have +are included here, as is the ksh `print' builtin. + +Compile with cc and whatever pic options you need (look in the +Makefile for a few common settings) + +load with ld and whatever shared object options you need (again, +look in the Makefile) + +then enable -f filename builtin-name + +enable uses a simple reference-counting scheme to avoid unloading a +shared object that implements more than one loadable builtin before +all loadable builtins implemented in the object are removed. + +Many of the details needed by builtin writers are found in hello.c, +the canonical example. There is no real `builtin writers' programming +guide'. diff --git a/examples/loadables/basename.c b/examples/loadables/basename.c new file mode 100644 index 0000000..7f254c7 --- /dev/null +++ b/examples/loadables/basename.c @@ -0,0 +1,108 @@ +/* basename - return nondirectory portion of pathname */ + +/* See Makefile for compilation details. */ + +#include "config.h" + +#if defined (HAVE_UNISTD_H) +# include +#endif + +#include +#include "builtins.h" +#include "shell.h" + +basename_builtin (list) + WORD_LIST *list; +{ + int slen, sufflen, off; + char *string, *suffix, *fn; + + if (list == 0) + { + builtin_usage (); + return (EX_USAGE); + } + + if (no_options (list)) + return (EX_USAGE); + + string = list->word->word; + suffix = (char *)NULL; + if (list->next) + { + list = list->next; + suffix = list->word->word; + } + + if (list->next) + { + builtin_usage (); + return (EX_USAGE); + } + + slen = strlen (string); + + /* Strip trailing slashes */ + while (slen > 0 && string[slen - 1] == '/') + slen--; + + /* (2) If string consists entirely of slash characters, string shall be + set to a single slash character. In this case, skip steps (3) + through (5). */ + if (slen == 0) + { + fputs ("/\n", stdout); + return (EXECUTION_SUCCESS); + } + + /* (3) If there are any trailing slash characters in string, they + shall be removed. */ + string[slen] = '\0'; + + /* (4) If there are any slash characters remaining in string, the prefix + of string up to an including the last slash character in string + shall be removed. */ + while (--slen >= 0) + if (string[slen] == '/') + break; + + fn = string + slen + 1; + + /* (5) If the suffix operand is present, is not identical to the + characters remaining in string, and is identical to a suffix + of the characters remaining in string, the suffix suffix + shall be removed from string. Otherwise, string shall not be + modified by this step. */ + if (suffix) + { + sufflen = strlen (suffix); + slen = strlen (fn); + if (sufflen < slen) + { + off = slen - sufflen; + if (strcmp (fn + off, suffix) == 0) + fn[off] = '\0'; + } + } + printf ("%s\n", fn); + return (EXECUTION_SUCCESS); +} + +char *basename_doc[] = { + "The STRING is converted to a filename corresponding to the last", + "pathname component in STRING. If the suffix string SUFFIX is", + "supplied, it is removed.", + (char *)NULL +}; + +/* The standard structure describing a builtin command. bash keeps an array + of these structures. */ +struct builtin basename_struct = { + "basename", /* builtin name */ + basename_builtin, /* function implementing the builtin */ + BUILTIN_ENABLED, /* initial flags for builtin */ + basename_doc, /* array of long documentation strings. */ + "basename string [suffix]", /* usage synopsis */ + 0 /* reserved for internal use */ +}; diff --git a/examples/loadables/cat.c b/examples/loadables/cat.c new file mode 100644 index 0000000..9dd1d1a --- /dev/null +++ b/examples/loadables/cat.c @@ -0,0 +1,100 @@ +/* + * cat replacement + * + * no options - the way cat was intended + */ + +#include +#include + +#include "builtins.h" +#include "shell.h" + +#ifndef errno +extern int errno; +#endif + +extern char *strerror (); +extern char **make_builtin_argv (); + +static int +fcopy(fd) +int fd; +{ + char buf[1024], *s; + int n, w, e; + + while (n = read(fd, buf, sizeof (buf))) { + w = write(1, buf, n); + if (w != n) { + e = errno; + write(2, "cat: write error: ", 18); + s = strerror(e); + write(2, s, strlen(s)); + write(2, "\n", 1); + return 1; + } + } + return 0; +} + +cat_main (argc, argv) +int argc; +char **argv; +{ + int i, fd, r; + char *s; + + if (argc == 1) + return (fcopy(0)); + + for (i = r = 1; i < argc; i++) { + if (argv[i][0] == '-' && argv[i][1] == '\0') + fd = 0; + else { + fd = open(argv[i], O_RDONLY, 0666); + if (fd < 0) { + s = strerror(errno); + write(2, "cat: cannot open ", 17); + write(2, argv[i], strlen(argv[i])); + write(2, ": ", 2); + write(2, s, strlen(s)); + write(2, "\n", 1); + continue; + } + } + r = fcopy(fd); + if (fd != 0) + close(fd); + } + return (r); +} + +cat_builtin(list) +WORD_LIST *list; +{ + char **v; + int c, r; + + v = make_builtin_argv(list, &c); + r = cat_main(c, v); + free(v); + + return r; +} + +char *cat_doc[] = { + "Read each FILE and display it on the standard output. If any", + "FILE is `-' or if no FILE argument is given, the standard input", + "is read.", + (char *)0 +}; + +struct builtin cat_struct = { + "cat", + cat_builtin, + BUILTIN_ENABLED, + cat_doc, + "cat [-] [file ...]", + 0 +}; diff --git a/examples/loadables/dirname.c b/examples/loadables/dirname.c new file mode 100644 index 0000000..e875865 --- /dev/null +++ b/examples/loadables/dirname.c @@ -0,0 +1,95 @@ +/* dirname - return directory portion of pathname */ + +/* See Makefile for compilation details. */ + +#include "config.h" + +#if defined (HAVE_UNISTD_H) +# include +#endif + +#include +#include "builtins.h" +#include "shell.h" + +dirname_builtin (list) + WORD_LIST *list; +{ + int slen; + char *string; + + if (list == 0 || list->next) + { + builtin_usage (); + return (EX_USAGE); + } + + if (no_options (list)) + return (EX_USAGE); + + string = list->word->word; + slen = strlen (string); + + /* Strip trailing slashes */ + while (slen > 0 && string[slen - 1] == '/') + slen--; + + /* (2) If string consists entirely of slash characters, string shall be + set to a single slash character. In this case, skip steps (3) + through (8). */ + if (slen == 0) + { + fputs ("/\n", stdout); + return (EXECUTION_SUCCESS); + } + + /* (3) If there are any trailing slash characters in string, they + shall be removed. */ + string[slen] = '\0'; + + /* (4) If there are no slash characters remaining in string, string + shall be set to a single period character. In this case, skip + steps (5) through (8). + + (5) If there are any trailing nonslash characters in string, + they shall be removed. */ + + while (--slen >= 0) + if (string[slen] == '/') + break; + + if (slen >= 0) + { + fputs (".\n", stdout); + return (EXECUTION_SUCCESS); + } + + /* (7) If there are any trailing slash characters in string, they + shall be removed. */ + while (--slen >= 0) + if (string[slen] != '/') + break; + string[++slen] = '\0'; + + /* (8) If the remaining string is empty, string shall be set to a single + slash character. */ + printf ("%s\n", (slen == 0) ? "/" : string); + return (EXECUTION_SUCCESS); +} + +char *dirname_doc[] = { + "The STRING is converted to the name of the directory containing", + "the filename corresponding to the last pathname component in STRING.", + (char *)NULL +}; + +/* The standard structure describing a builtin command. bash keeps an array + of these structures. */ +struct builtin dirname_struct = { + "dirname", /* builtin name */ + dirname_builtin, /* function implementing the builtin */ + BUILTIN_ENABLED, /* initial flags for builtin */ + dirname_doc, /* array of long documentation strings. */ + "dirname string", /* usage synopsis */ + 0 /* reserved for internal use */ +}; diff --git a/examples/loadables/finfo.c b/examples/loadables/finfo.c new file mode 100644 index 0000000..c0b0365 --- /dev/null +++ b/examples/loadables/finfo.c @@ -0,0 +1,569 @@ +/* + * finfo - print file info + */ + +#include +#include "posixstat.h" +#include +#include +#include +#include + +#include "shell.h" +#include "builtins.h" +#include "common.h" + +#ifndef errno +extern int errno; +#endif + +extern char *strrchr(); +extern char **make_builtin_argv (); + +static int printst(); +static int printsome(); +static int printfinfo(); +static int finfo_main(); + +extern int sh_optind; +extern char *sh_optarg; +extern char *this_command_name; + +static char *prog; +static int pmask; + +#define OPT_UID 0x00001 +#define OPT_GID 0x00002 +#define OPT_DEV 0x00004 +#define OPT_INO 0x00008 +#define OPT_PERM 0x00010 +#define OPT_LNKNAM 0x00020 +#define OPT_FID 0x00040 +#define OPT_NLINK 0x00080 +#define OPT_RDEV 0x00100 +#define OPT_SIZE 0x00200 +#define OPT_ATIME 0x00400 +#define OPT_MTIME 0x00800 +#define OPT_CTIME 0x01000 +#define OPT_BLKSIZE 0x02000 +#define OPT_BLKS 0x04000 +#define OPT_FTYPE 0x08000 +#define OPT_PMASK 0x10000 +#define OPT_OPERM 0x20000 + +#define OPT_ASCII 0x1000000 + +#define OPTIONS "acdgiflmnopsuACGMP:U" + +static int +octal(s) +char *s; +{ + int r; + + r = *s - '0'; + while (*++s >= '0' && *s <= '7') + r = (r * 8) + (*s - '0'); + return r; +} + +static int +finfo_main(argc, argv) +int argc; +char **argv; +{ + register int i; + int mode, flags, opt; + + sh_optind = 0; /* XXX */ + prog = base_pathname(argv[0]); + if (argc == 1) { + builtin_usage(); + return(1); + } + flags = 0; + while ((opt = sh_getopt(argc, argv, OPTIONS)) != EOF) { + switch(opt) { + case 'a': flags |= OPT_ATIME; break; + case 'A': flags |= OPT_ATIME|OPT_ASCII; break; + case 'c': flags |= OPT_CTIME; break; + case 'C': flags |= OPT_CTIME|OPT_ASCII; break; + case 'd': flags |= OPT_DEV; break; + case 'i': flags |= OPT_INO; break; + case 'f': flags |= OPT_FID; break; + case 'g': flags |= OPT_GID; break; + case 'G': flags |= OPT_GID|OPT_ASCII; break; + case 'l': flags |= OPT_LNKNAM; break; + case 'm': flags |= OPT_MTIME; break; + case 'M': flags |= OPT_MTIME|OPT_ASCII; break; + case 'n': flags |= OPT_NLINK; break; + case 'o': flags |= OPT_OPERM; break; + case 'p': flags |= OPT_PERM; break; + case 'P': flags |= OPT_PMASK; pmask = octal(sh_optarg); break; + case 's': flags |= OPT_SIZE; break; + case 'u': flags |= OPT_UID; break; + case 'U': flags |= OPT_UID|OPT_ASCII; break; + default: builtin_usage (); return(1); + } + } + + argc -= sh_optind; + argv += sh_optind; + + if (argc == 0) { + builtin_usage(); + return(1); + } + + for (i = 0; i < argc; i++) + opt = flags ? printsome (argv[i], flags) : printfinfo(argv[i]); + + return(opt); +} + +static struct stat * +getstat(f) +char *f; +{ + static struct stat st; + int fd, r; + long lfd; + + if (strncmp(f, "/dev/fd/", 8) == 0) { + if (legal_number(f + 8, &lfd) == 0) { + builtin_error("%s: invalid fd", f + 8); + return ((struct stat *)0); + } + fd = lfd; + r = fstat(fd, &st); + } else + r = stat(f, &st); + if (r < 0) { + builtin_error("%s: cannot stat: %s", f, strerror(errno)); + return ((struct stat *)0); + } + return (&st); +} + +static int +printfinfo(f) +char *f; +{ + struct stat *st; + + st = getstat(f); + return (st ? printst(st) : 1); +} + +static int +getperm(m) +int m; +{ + return (m & (S_IRWXU|S_IRWXG|S_IRWXO|S_ISUID|S_ISGID)); +} + +static int +perms(m) +int m; +{ + char ubits[4], gbits[4], obits[4]; /* u=rwx,g=rwx,o=rwx */ + int i; + + i = 0; + if (m & S_IRUSR) + ubits[i++] = 'r'; + if (m & S_IWUSR) + ubits[i++] = 'w'; + if (m & S_IXUSR) + ubits[i++] = 'x'; + ubits[i] = '\0'; + + i = 0; + if (m & S_IRGRP) + gbits[i++] = 'r'; + if (m & S_IWGRP) + gbits[i++] = 'w'; + if (m & S_IXGRP) + gbits[i++] = 'x'; + gbits[i] = '\0'; + + i = 0; + if (m & S_IROTH) + obits[i++] = 'r'; + if (m & S_IWOTH) + obits[i++] = 'w'; + if (m & S_IXOTH) + obits[i++] = 'x'; + obits[i] = '\0'; + + printf ("u=%s,g=%s,o=%s", ubits, gbits, obits); +} + +static int +printmode(mode) +int mode; +{ + if (S_ISBLK(mode)) + printf("S_IFBLK "); + if (S_ISCHR(mode)) + printf("S_IFCHR "); + if (S_ISDIR(mode)) + printf("S_IFDIR "); + if (S_ISREG(mode)) + printf("S_IFREG "); + if (S_ISFIFO(mode)) + printf("S_IFIFO "); + if (S_ISLNK(mode)) + printf("S_IFLNK "); + if (S_ISSOCK(mode)) + printf("S_IFSOCK "); + perms(getperm(mode)); + printf("\n"); +} + +static int +printst(st) +struct stat *st; +{ + struct passwd *pw; + struct group *gr; + char *owner; + + printf("Device (major/minor): %d (%d/%d)\n", (int) (st->st_dev & 0xFF), + (int) major (st->st_dev), + (int) minor (st->st_dev)); + printf("Inode: %d\n", (int) st->st_ino); + printf("Mode: (%o) ", (int) st->st_mode); + printmode((int) st->st_mode); + printf("Link count: %d\n", (int) st->st_nlink); + pw = getpwuid(st->st_uid); + owner = pw ? pw->pw_name : "unknown"; + printf("Uid of owner: %d (%s)\n", (int) st->st_uid, owner); + gr = getgrgid(st->st_gid); + owner = gr ? gr->gr_name : "unknown"; + printf("Gid of owner: %d (%s)\n", (int) st->st_gid, owner); + printf("Device type: %d\n", (int) st->st_rdev); + printf("File size: %ld\n", (long) st->st_size); + printf("File last access time: %s", ctime (&st->st_atime)); + printf("File last modify time: %s", ctime (&st->st_mtime)); + printf("File last status change time: %s", ctime (&st->st_ctime)); + fflush(stdout); + return(0); +} + +static int +printsome(f, flags) +char *f; +int flags; +{ + struct stat *st; + struct passwd *pw; + struct group *gr; + int p; + char *b; + + st = getstat(f); + if (st == NULL) + return (1); + + /* Print requested info */ + if (flags & OPT_ATIME) { + if (flags & OPT_ASCII) + printf("%s", ctime(&st->st_atime)); + else + printf("%ld\n", st->st_atime); + } else if (flags & OPT_MTIME) { + if (flags & OPT_ASCII) + printf("%s", ctime(&st->st_mtime)); + else + printf("%ld\n", st->st_mtime); + } else if (flags & OPT_CTIME) { + if (flags & OPT_ASCII) + printf("%s", ctime(&st->st_ctime)); + else + printf("%ld\n", st->st_ctime); + } else if (flags & OPT_DEV) + printf("%d\n", st->st_dev); + else if (flags & OPT_INO) + printf("%d\n", st->st_ino); + else if (flags & OPT_FID) + printf("%d:%ld\n", st->st_dev, st->st_ino); + else if (flags & OPT_NLINK) + printf("%d\n", st->st_nlink); + else if (flags & OPT_LNKNAM) { +#ifdef S_ISLNK + b = xmalloc(4096); + p = readlink(f, b, 4096); + if (p >= 0 && p < 4096) + b[p] = '\0'; + else { + p = errno; + strcpy(b, prog); + strcat(b, ": "); + strcat(b, strerror(p)); + } + printf("%s\n", b); + free(b); +#else + printf("%s\n", f); +#endif + } else if (flags & OPT_PERM) { + perms(st->st_mode); + printf("\n"); + } else if (flags & OPT_OPERM) + printf("%o\n", getperm(st->st_mode)); + else if (flags & OPT_PMASK) + printf("%o\n", getperm(st->st_mode) & pmask); + else if (flags & OPT_UID) { + pw = getpwuid(st->st_uid); + if (flags & OPT_ASCII) + printf("%s\n", pw ? pw->pw_name : "unknown"); + else + printf("%d\n", st->st_uid); + } else if (flags & OPT_GID) { + gr = getgrgid(st->st_gid); + if (flags & OPT_ASCII) + printf("%s\n", gr ? gr->gr_name : "unknown"); + else + printf("%d\n", st->st_gid); + } else if (flags & OPT_SIZE) + printf("%ld\n", st->st_size); + + return (0); +} + +#ifndef NOBUILTIN +finfo_builtin(list) + WORD_LIST *list; +{ + int c, r; + char **v; + WORD_LIST *l; + + v = make_builtin_argv (list, &c); + r = finfo_main (c, v); + free (v); + + return r; +} + +static char *finfo_doc[] = { + "Display information about each FILE. Only single operators should", + "be supplied. If no options are supplied, a summary of the info", + "available about each FILE is printed. If FILE is of the form", + "/dev/fd/XX, file descriptor XX is described. Operators, if supplied,", + "have the following meanings:", + "", + " -a last file access time", + " -A last file access time in ctime format", + " -c last file status change time", + " -C last file status change time in ctime format", + " -m last file modification time", + " -M last file modification time in ctime format", + " -d device", + " -i inode", + " -f composite file identifier (device:inode)", + " -g gid of owner", + " -G group name of owner", + " -l name of file pointed to by symlink", + " -n link count", + " -o permissions in octal", + " -p permissions in ascii", + " -P mask permissions ANDed with MASK (like with umask)", + " -s file size in bytes", + " -u uid of owner", + " -U user name of owner", + (char *)0 +}; + +struct builtin finfo_struct = { + "finfo", + finfo_builtin, + BUILTIN_ENABLED, + finfo_doc, + "finfo [-acdgiflmnopsuACGMPU] file [file...]", + 0 +}; +#endif + +#ifdef NOBUILTIN +#if defined (PREFER_STDARG) +# include +#else +# if defined (PREFER_VARARGS) +# include +# endif +#endif + +char *this_command_name; + +main(argc, argv) +int argc; +char **argv; +{ + this_command_name = argv[0]; + exit(finfo_main(argc, argv)); +} + +void +builtin_usage() +{ + fprintf(stderr, "%s: usage: %s [-%s] [file ...]\n", prog, OPTIONS); +} + +#ifndef HAVE_STRERROR +char * +strerror(e) +int e; +{ + static char ebuf[40]; + extern int sys_nerr; + extern char *sys_errlist[]; + + if (e < 0 || e > sys_nerr) { + sprintf(ebuf,"Unknown error code %d", e); + return (&ebuf[0]); + } + return (sys_errlist[e]); +} +#endif + +char * +xmalloc(s) +size_t s; +{ + char *ret; + extern char *malloc(); + + ret = malloc(s); + if (ret) + return (ret); + fprintf(stderr, "%s: cannot malloc %d bytes\n", prog, s); + exit(1); +} + +char * +base_pathname(p) +char *p; +{ + char *t; + + if (t = strrchr(p, '/')) + return(++t); + return(p); +} + +int +legal_number (string, result) + char *string; + long *result; +{ + int sign; + long value; + + sign = 1; + value = 0; + + if (result) + *result = 0; + + /* Skip leading whitespace characters. */ + while (whitespace (*string)) + string++; + + if (!*string) + return (0); + + /* We allow leading `-' or `+'. */ + if (*string == '-' || *string == '+') + { + if (!digit (string[1])) + return (0); + + if (*string == '-') + sign = -1; + + string++; + } + + while (digit (*string)) + { + if (result) + value = (value * 10) + digit_value (*string); + string++; + } + + /* Skip trailing whitespace, if any. */ + while (whitespace (*string)) + string++; + + /* Error if not at end of string. */ + if (*string) + return (0); + + if (result) + *result = value * sign; + + return (1); +} + +int sh_optind; +char *sh_optarg; +int sh_opterr; + +extern int optind; +extern char *optarg; + +int +sh_getopt(c, v, o) +int c; +char **v, *o; +{ + int r; + + r = getopt(c, v, o); + sh_optind = optind; + sh_optarg = optarg; + return r; +} + +#if defined (USE_VARARGS) +void +#if defined (PREFER_STDARG) +builtin_error (const char *format, ...) +#else +builtin_error (format, va_alist) + const char *format; + va_dcl +#endif +{ + va_list args; + + if (this_command_name && *this_command_name) + fprintf (stderr, "%s: ", this_command_name); + +#if defined (PREFER_STDARG) + va_start (args, format); +#else + va_start (args); +#endif + + vfprintf (stderr, format, args); + va_end (args); + fprintf (stderr, "\n"); +} +#else +void +builtin_error (format, arg1, arg2, arg3, arg4, arg5) + char *format, *arg1, *arg2, *arg3, *arg4, *arg5; +{ + if (this_command_name && *this_command_name) + fprintf (stderr, "%s: ", this_command_name); + + fprintf (stderr, format, arg1, arg2, arg3, arg4, arg5); + fprintf (stderr, "\n"); + fflush (stderr); +} +#endif /* !USE_VARARGS */ + +#endif diff --git a/examples/loadables/getconf.c b/examples/loadables/getconf.c new file mode 100644 index 0000000..3b53331 --- /dev/null +++ b/examples/loadables/getconf.c @@ -0,0 +1,272 @@ +/* + * Copyright (c) 1994 Winning Strategies, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Winning Strategies, Inc. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * POSIX.2 getconf utility + * + * Written by: + * J.T. Conklin (jtc@wimsey.com), Winning Strategies, Inc. + */ + +#ifndef lint +static char rcsid[] = "$Id: getconf.c,v 1.2 1994/05/10 00:04:12 jtc Exp $"; +#endif /* not lint */ + +#include +#include +#include +#include +#include +#include "bashansi.h" +#include "shell.h" +#include "builtins.h" +#include "stdc.h" + + +struct conf_variable +{ + const char *name; + enum { SYSCONF, CONFSTR, PATHCONF, CONSTANT } type; + long value; +}; + +/* BSD/OS does not define this; use Posix.2 recommended minimum value. */ +#ifndef _POSIX2_COLL_WEIGHTS_MAX +#define _POSIX2_COLL_WEIGHTS_MAX 2 +#endif + +static const struct conf_variable conf_table[] = +{ + { "PATH", CONFSTR, _CS_PATH }, + + /* Utility Limit Minimum Values */ + { "POSIX2_BC_BASE_MAX", CONSTANT, _POSIX2_BC_BASE_MAX }, + { "POSIX2_BC_DIM_MAX", CONSTANT, _POSIX2_BC_DIM_MAX }, + { "POSIX2_BC_SCALE_MAX", CONSTANT, _POSIX2_BC_SCALE_MAX }, + { "POSIX2_BC_STRING_MAX", CONSTANT, _POSIX2_BC_STRING_MAX }, + { "POSIX2_COLL_WEIGHTS_MAX", CONSTANT, _POSIX2_COLL_WEIGHTS_MAX }, + { "POSIX2_EXPR_NEST_MAX", CONSTANT, _POSIX2_EXPR_NEST_MAX }, + { "POSIX2_LINE_MAX", CONSTANT, _POSIX2_LINE_MAX }, + { "POSIX2_RE_DUP_MAX", CONSTANT, _POSIX2_RE_DUP_MAX }, + { "POSIX2_VERSION", CONSTANT, _POSIX2_VERSION }, + + /* POSIX.1 Minimum Values */ + { "_POSIX_ARG_MAX", CONSTANT, _POSIX_ARG_MAX }, + { "_POSIX_CHILD_MAX", CONSTANT, _POSIX_CHILD_MAX }, + { "_POSIX_LINK_MAX", CONSTANT, _POSIX_LINK_MAX }, + { "_POSIX_MAX_CANON", CONSTANT, _POSIX_MAX_CANON }, + { "_POSIX_MAX_INPUT", CONSTANT, _POSIX_MAX_INPUT }, + { "_POSIX_NAME_MAX", CONSTANT, _POSIX_NAME_MAX }, + { "_POSIX_NGROUPS_MAX", CONSTANT, _POSIX_NGROUPS_MAX }, + { "_POSIX_OPEN_MAX", CONSTANT, _POSIX_OPEN_MAX }, + { "_POSIX_PATH_MAX", CONSTANT, _POSIX_PIPE_BUF }, + { "_POSIX_PIPE_BUF", CONSTANT, _POSIX_PIPE_BUF }, + { "_POSIX_SSIZE_MAX", CONSTANT, _POSIX_SSIZE_MAX }, + { "_POSIX_STREAM_MAX", CONSTANT, _POSIX_STREAM_MAX }, + { "_POSIX_TZNAME_MAX", CONSTANT, _POSIX_TZNAME_MAX }, + + /* Symbolic Utility Limits */ + { "BC_BASE_MAX", SYSCONF, _SC_BC_BASE_MAX }, + { "BC_DIM_MAX", SYSCONF, _SC_BC_DIM_MAX }, + { "BC_SCALE_MAX", SYSCONF, _SC_BC_SCALE_MAX }, + { "BC_STRING_MAX", SYSCONF, _SC_BC_STRING_MAX }, + { "COLL_WEIGHTS_MAX", SYSCONF, _SC_COLL_WEIGHTS_MAX }, + { "EXPR_NEST_MAX", SYSCONF, _SC_EXPR_NEST_MAX }, + { "LINE_MAX", SYSCONF, _SC_LINE_MAX }, + { "RE_DUP_MAX", SYSCONF, _SC_RE_DUP_MAX }, + + /* Optional Facility Configuration Values */ + { "POSIX2_C_BIND", SYSCONF, _SC_2_C_BIND }, + { "POSIX2_C_DEV", SYSCONF, _SC_2_C_DEV }, + { "POSIX2_CHAR_TERM", SYSCONF, _SC_2_CHAR_TERM }, + { "POSIX2_FORT_DEV", SYSCONF, _SC_2_FORT_DEV }, + { "POSIX2_FORT_RUN", SYSCONF, _SC_2_FORT_RUN }, + { "POSIX2_LOCALEDEF", SYSCONF, _SC_2_LOCALEDEF }, + { "POSIX2_SW_DEV", SYSCONF, _SC_2_SW_DEV }, + { "POSIX2_UPE", SYSCONF, _SC_2_UPE }, + + /* POSIX.1 Configurable System Variables */ + { "ARG_MAX", SYSCONF, _SC_ARG_MAX }, + { "CHILD_MAX", SYSCONF, _SC_CHILD_MAX }, + { "CLK_TCK", SYSCONF, _SC_CLK_TCK }, + { "NGROUPS_MAX", SYSCONF, _SC_NGROUPS_MAX }, + { "OPEN_MAX", SYSCONF, _SC_OPEN_MAX }, + { "STREAM_MAX", SYSCONF, _SC_STREAM_MAX }, + { "TZNAME_MAX", SYSCONF, _SC_TZNAME_MAX }, + { "_POSIX_JOB_CONTROL", SYSCONF, _SC_JOB_CONTROL }, + { "_POSIX_SAVED_IDS", SYSCONF, _SC_SAVED_IDS }, + { "_POSIX_VERSION", SYSCONF, _SC_VERSION }, + + { "LINK_MAX", PATHCONF, _PC_LINK_MAX }, + { "MAX_CANON", PATHCONF, _PC_MAX_CANON }, + { "MAX_INPUT", PATHCONF, _PC_MAX_INPUT }, + { "NAME_MAX", PATHCONF, _PC_NAME_MAX }, + { "PATH_MAX", PATHCONF, _PC_PATH_MAX }, + { "PIPE_BUF", PATHCONF, _PC_PIPE_BUF }, + { "_POSIX_CHOWN_RESTRICTED", PATHCONF, _PC_CHOWN_RESTRICTED }, + { "_POSIX_NO_TRUNC", PATHCONF, _PC_NO_TRUNC }, + { "_POSIX_VDISABLE", PATHCONF, _PC_VDISABLE }, + + { NULL } +}; + +extern char *this_command_name; +extern char *xmalloc (); +extern char **make_builtin_argv (); +static int getconf_main (); + +int +getconf_builtin (list) + WORD_LIST *list; +{ + int c, r; + char **v; + WORD_LIST *l; + + v = make_builtin_argv (list, &c); + r = getconf_main (c, v); + free (v); + + return r; +} + +static int +getconf_main(argc, argv) + int argc; + char **argv; +{ + int ch; + const struct conf_variable *cp; + + long val; + size_t slen; + char *sval; + + setlocale(LC_ALL, ""); + + while ((ch = getopt(argc, argv, "")) != -1) { + switch (ch) { + case '?': + default: + builtin_usage(); + return(EX_USAGE); + /* NOTREACHED */ + } + } + argc -= optind; + argv += optind; + + if (argc < 1 || argc > 2) { + builtin_usage(); + return(EX_USAGE); + /* NOTREACHED */ + } + + for (cp = conf_table; cp->name != NULL; cp++) { + if (strcmp(*argv, cp->name) == 0) + break; + } + if (cp->name == NULL) { + builtin_error ("%s: unknown variable", *argv); + return (EXECUTION_FAILURE); + } + + if (cp->type == PATHCONF) { + if (argc != 2) { + builtin_usage(); + return(EX_USAGE); + } + } else { + if (argc != 1) { + builtin_usage(); + return(EX_USAGE); + } + } + + switch (cp->type) { + case CONSTANT: + printf("%ld\n", cp->value); + break; + + case CONFSTR: + slen = confstr (cp->value, (char *) 0, (size_t) 0); + + sval = xmalloc(slen); + + confstr(cp->value, sval, slen); + printf("%s\n", sval); + break; + + case SYSCONF: + errno = 0; + if ((val = sysconf(cp->value)) == -1) { + if (errno != 0) { + builtin_error ("%s", strerror (errno)); + return (EXECUTION_FAILURE); + } + + printf ("undefined\n"); + } else { + printf("%ld\n", val); + } + break; + + case PATHCONF: + errno = 0; + if ((val = pathconf(argv[1], cp->value)) == -1) { + if (errno != 0) { + builtin_error ("%s: %s", argv[1], strerror (errno)); + return (EXECUTION_FAILURE); + } + + printf ("undefined\n"); + } else { + printf ("%ld\n", val); + } + break; + } + + return (ferror(stdout) ? EXECUTION_FAILURE : EXECUTION_SUCCESS); +} + +static char *getconf_doc[] = { + "getconf writes the current value of a configurable system limit or", + "option variable to the standard output.", + (char *)NULL +}; + +struct builtin getconf_struct = { + "getconf", + getconf_builtin, + BUILTIN_ENABLED, + getconf_doc, + "getconf sysvar or getconf pathvar pathname", + 0 +}; diff --git a/examples/loadables/head.c b/examples/loadables/head.c new file mode 100644 index 0000000..d2dcb72 --- /dev/null +++ b/examples/loadables/head.c @@ -0,0 +1,143 @@ +/* head - copy first part of files. */ + +/* See Makefile for compilation details. */ + +#include "config.h" + +#include "bashtypes.h" +#include "posixstat.h" +#include "filecntl.h" + +#if defined (HAVE_UNISTD_H) +# include +#endif + +#include "bashansi.h" + +#include +#include +#include + +#include "builtins.h" +#include "shell.h" +#include "bashgetopt.h" + +#if !defined (errno) +extern int errno; +#endif + +static void +munge_list (list) + WORD_LIST *list; +{ + WORD_LIST *l, *nl; + WORD_DESC *wd; + char *arg; + + for (l = list; l; l = l->next) + { + arg = l->word->word; + if (arg[0] != '-' || arg[1] == '-' || (isdigit(arg[1]) == 0)) + return; + /* We have -[0-9]* */ + wd = make_bare_word (arg+1); + nl = make_word_list (wd, l->next); + l->word->word[1] = 'n'; + l->word->word[2] = '\0'; + l->next = nl; + l = nl; /* skip over new argument */ + } +} + +static int +file_head (fp, cnt) + FILE *fp; + int cnt; +{ + int ch; + + while (cnt--) + { + while ((ch = getc (fp)) != EOF) + { + if (putchar (ch) == EOF) + { + builtin_error ("write error: %s", strerror (errno)); + return EXECUTION_FAILURE; + } + if (ch == '\n') + break; + } + } +} + +head_builtin (list) + WORD_LIST *list; +{ + int nline, opt, rval; + WORD_LIST *l; + FILE *fp; + + char *t; + + munge_list (list); /* change -num into -n num */ + + reset_internal_getopt (); + nline = 10; + while ((opt = internal_getopt (list, "n:")) != -1) + { + switch (opt) + { + case 'n': + nline = atoi (list_optarg); + if (nline <= 0) + { + builtin_error ("bad line count: %s", list_optarg); + return (EX_USAGE); + } + break; + default: + builtin_usage (); + return (EX_USAGE); + } + } + list = loptend; + + if (list == 0) + return (file_head (stdin, nline)); + + for (rval = EXECUTION_SUCCESS, opt = 1, l = list; l; l = l->next) + { + fp = fopen (l->word->word, "r"); + if (fp == NULL) + { + builtin_error ("%s: %s", l->word->word, strerror (errno)); + continue; + } + if (list->next) /* more than one file */ + { + printf ("%s==> %s <==\n", opt ? "" : "\n", l->word->word); + opt = 0; + } + rval = file_head (fp, nline); + fclose (fp); + } + + return (rval); +} + +char *head_doc[] = { + "Copy the first N lines from the input files to the standard output.", + "N is supplied as an argument to the `-n' option. If N is not given,", + "the first ten lines are copied.", + (char *)NULL +}; + +struct builtin head_struct = { + "head", /* builtin name */ + head_builtin, /* function implementing the builtin */ + BUILTIN_ENABLED, /* initial flags for builtin */ + head_doc, /* array of long documentation strings. */ + "head [-n num] [file ...]", /* usage synopsis; becomes short_doc */ + 0 /* reserved for internal use */ +}; diff --git a/examples/loadables/hello.c b/examples/loadables/hello.c new file mode 100644 index 0000000..3f371e5 --- /dev/null +++ b/examples/loadables/hello.c @@ -0,0 +1,59 @@ +/* Sample builtin to be dynamically loaded with enable -f and create a new + builtin. */ + +/* See Makefile for compilation details. */ + +#include "config.h" + +#if defined (HAVE_UNISTD_H) +# include +#endif + +#include +#include "builtins.h" +#include "shell.h" + +/* A builtin `xxx' is normally implemented with an `xxx_builtin' function. + If you're converting a command that uses the normal Unix argc/argv + calling convention, use argv = word_list_to_argv (list, &argc) and call + the original `main' something like `xxx_main'. Look at cat.c for an + example. + + Builtins should use internal_getopt to parse options. It is the same as + getopt(3), but it takes a WORD_LIST *. Look at print.c for an example + of its use. + + If the builtin takes no options, call no_options(list) before doing + anything else. If it returns a non-zero value, your builtin should + immediately return EX_USAGE. Look at logname.c for an example. + + A builtin command returns EXECUTION_SUCCESS for success and + EXECUTION_FAILURE to indicate failure. */ +hello_builtin (list) + WORD_LIST *list; +{ + printf("hello world\n"); + fflush (stdout); + return (EXECUTION_SUCCESS); +} + +/* An array of strings forming the `long' documentation for a builtin xxx, + which is printed by `help xxx'. It must end with a NULL. */ +char *hello_doc[] = { + "this is the long doc for the sample hello builtin", + "which is a bare-bones echo", + (char *)NULL +}; + +/* The standard structure describing a builtin command. bash keeps an array + of these structures. The flags must include BUILTIN_ENABLED so the + builtin can be used. */ +struct builtin hello_struct = { + "hello", /* builtin name */ + hello_builtin, /* function implementing the builtin */ + BUILTIN_ENABLED, /* initial flags for builtin */ + hello_doc, /* array of long documentation strings. */ + "hello [args]", /* usage synopsis; becomes short_doc */ + 0 /* reserved for internal use */ +}; + diff --git a/examples/loadables/logname.c b/examples/loadables/logname.c new file mode 100644 index 0000000..00cfd19 --- /dev/null +++ b/examples/loadables/logname.c @@ -0,0 +1,52 @@ +/* logname - print login name of current user */ + +#include + +#if defined (HAVE_UNISTD_H) +# include +#endif + +#include +#include + +#include "builtins.h" +#include "shell.h" + +#if !defined (errno) +extern int errno; +#endif + +logname_builtin (list) + WORD_LIST *list; +{ + char *np; + + if (no_options (list)) + return (EX_USAGE); + + np = getlogin (); + if (np == 0) + { + builtin_error ("cannot find username: %s", strerror (errno)); + return (EXECUTION_FAILURE); + } + printf ("%s\n", np); + return (EXECUTION_SUCCESS); +} + +char *logname_doc[] = { + "write the current user's login name to the standard output", + "and exit. logname ignores the LOGNAME and USER variables.", + "logname ignores any non-option arguments.", + (char *)NULL +}; + +struct builtin logname_struct = { + "logname", + logname_builtin, + BUILTIN_ENABLED, + logname_doc, + "logname", + 0 +}; + diff --git a/examples/loadables/necho.c b/examples/loadables/necho.c new file mode 100644 index 0000000..695062a --- /dev/null +++ b/examples/loadables/necho.c @@ -0,0 +1,33 @@ +/* necho - echo without options or argument interpretation */ + +/* Sample builtin to be dynamically loaded with enable -f and replace an + existing builtin. */ + +#include +#include "builtins.h" +#include "shell.h" + +necho_builtin (list) +WORD_LIST *list; +{ + print_word_list (list, " "); + printf("\n"); + fflush (stdout); + return (EXECUTION_SUCCESS); +} + +char *necho_doc[] = { + "Print the arguments to the standard ouput separated", + "by space characters and terminated with a newline.", + (char *)NULL +}; + +struct builtin echo_struct = { + "echo", + necho_builtin, + BUILTIN_ENABLED, + necho_doc, + "echo [args]", + 0 +}; + diff --git a/examples/loadables/pathchk.c b/examples/loadables/pathchk.c new file mode 100644 index 0000000..dc02fce --- /dev/null +++ b/examples/loadables/pathchk.c @@ -0,0 +1,359 @@ +/* pathchk - check pathnames for validity and portability */ + +/* Usage: pathchk [-p] path ... + + For each PATH, print a message if any of these conditions are false: + * all existing leading directories in PATH have search (execute) permission + * strlen (PATH) <= PATH_MAX + * strlen (each_directory_in_PATH) <= NAME_MAX + + Exit status: + 0 All PATH names passed all of the tests. + 1 An error occurred. + + Options: + -p Instead of performing length checks on the + underlying filesystem, test the length of the + pathname and its components against the POSIX.1 + minimum limits for portability, _POSIX_NAME_MAX + and _POSIX_PATH_MAX in 2.9.2. Also check that + the pathname contains no character not in the + portable filename character set. */ + +/* See Makefile for compilation details. */ + +#include + +#include +#include "posixstat.h" + +#if defined (HAVE_UNISTD_H) +# include +#endif + +#if defined (HAVE_LIMITS_H) +# include +#endif + +#include "bashansi.h" + +#include +#include + +#include "builtins.h" +#include "shell.h" +#include "stdc.h" +#include "bashgetopt.h" +#include "maxpath.h" + +#if !defined (errno) +extern int errno; +#endif + +#if !defined (_POSIX_PATH_MAX) +# define _POSIX_PATH_MAX 255 +#endif +#if !defined (_POSIX_NAME_MAX) +# define _POSIX_NAME_MAX 14 +#endif + +/* How do we get PATH_MAX? */ +#if defined (_POSIX_VERSION) && !defined (PATH_MAX) +# define PATH_MAX_FOR(p) pathconf ((p), _PC_PATH_MAX) +#endif + +/* How do we get NAME_MAX? */ +#if defined (_POSIX_VERSION) && !defined (NAME_MAX) +# define NAME_MAX_FOR(p) pathconf ((p), _PC_NAME_MAX) +#endif + +#if !defined (PATH_MAX_FOR) +# define PATH_MAX_FOR(p) PATH_MAX +#endif + +#if !defined (NAME_MAX_FOR) +# define NAME_MAX_FOR(p) NAME_MAX +#endif + +extern char *strerror (); + +static int validate_path (); + +pathchk_builtin (list) + WORD_LIST *list; +{ + int retval, pflag, opt; + + reset_internal_getopt (); + while ((opt = internal_getopt (list, "p")) != -1) + { + switch (opt) + { + case 'p': + pflag = 1; + break; + default: + builtin_usage (); + return (EX_USAGE); + } + } + list = loptend; + + if (list == 0) + { + builtin_usage (); + return (EX_USAGE); + } + + for (retval = 0; list; list = list->next) + retval |= validate_path (list->word->word, pflag); + + return (retval ? EXECUTION_FAILURE : EXECUTION_SUCCESS); +} + +char *pathchk_doc[] = { + "Check each pathname argument for validity (i.e., it may be used to", + "create or access a file without casuing syntax errors) and portability", + "(i.e., no filename truncation will result). If the `-p' option is", + "supplied, more extensive portability checks are performed.", + (char *)NULL +}; + +/* The standard structure describing a builtin command. bash keeps an array + of these structures. */ +struct builtin pathchk_struct = { + "pathchk", /* builtin name */ + pathchk_builtin, /* function implementing the builtin */ + BUILTIN_ENABLED, /* initial flags for builtin */ + pathchk_doc, /* array of long documentation strings. */ + "pathchk [-p] pathname ...", /* usage synopsis */ + 0 /* reserved for internal use */ +}; + +/* The remainder of this file is stolen shamelessly from `pathchk.c' in + the sh-utils-1.12 distribution, by + + David MacKenzie + and Jim Meyering */ + +/* Each element is nonzero if the corresponding ASCII character is + in the POSIX portable character set, and zero if it is not. + In addition, the entry for `/' is nonzero to simplify checking. */ +static char const portable_chars[256] = +{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0-15 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 16-31 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, /* 32-47 */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, /* 48-63 */ + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 64-79 */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, /* 80-95 */ + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 96-111 */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, /* 112-127 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +/* If PATH contains only portable characters, return 1, else 0. */ + +static int +portable_chars_only (path) + const char *path; +{ + const char *p; + + for (p = path; *p; ++p) + if (portable_chars[(const unsigned char) *p] == 0) + { + error (0, 0, "path `%s' contains nonportable character `%c'", + path, *p); + return 0; + } + return 1; +} + +/* On some systems, stat can return EINTR. */ + +#ifndef EINTR +# define SAFE_STAT(name, buf) stat (name, buf) +#else +# define SAFE_STAT(name, buf) safe_stat (name, buf) +static inline int +safe_stat (name, buf) + const char *name; + struct stat *buf; +{ + int ret; + + do + ret = stat (name, buf); + while (ret < 0 && errno == EINTR); + + return ret; +} +#endif + +/* Return 1 if PATH is a usable leading directory, 0 if not, + 2 if it doesn't exist. */ + +static int +dir_ok (path) + const char *path; +{ + struct stat stats; + + if (SAFE_STAT (path, &stats)) + return 2; + + if (!S_ISDIR (stats.st_mode)) + { + error (0, 0, "`%s' is not a directory", path); + return 0; + } + + /* Use access to test for search permission because + testing permission bits of st_mode can lose with new + access control mechanisms. Of course, access loses if you're + running setuid. */ + if (access (path, X_OK) != 0) + { + if (errno == EACCES) + builtin_error ("directory `%s' is not searchable", path); + else + builtin_error ("%s: %s", path, strerror (errno)); + return 0; + } + + return 1; +} + +static char * +xstrdup (s) + char *s; +{ + return (savestring (s)); +} + +/* Make sure that + strlen (PATH) <= PATH_MAX + && strlen (each-existing-directory-in-PATH) <= NAME_MAX + + If PORTABILITY is nonzero, compare against _POSIX_PATH_MAX and + _POSIX_NAME_MAX instead, and make sure that PATH contains no + characters not in the POSIX portable filename character set, which + consists of A-Z, a-z, 0-9, ., _, -. + + Make sure that all leading directories along PATH that exist have + `x' permission. + + Return 0 if all of these tests are successful, 1 if any fail. */ + +static int +validate_path (path, portability) + char *path; + int portability; +{ + int path_max; + int last_elem; /* Nonzero if checking last element of path. */ + int exists; /* 2 if the path element exists. */ + char *slash; + char *parent; /* Last existing leading directory so far. */ + + if (portability && !portable_chars_only (path)) + return 1; + + if (*path == '\0') + return 0; + +#ifdef lint + /* Suppress `used before initialized' warning. */ + exists = 0; +#endif + + /* Figure out the parent of the first element in PATH. */ + parent = xstrdup (*path == '/' ? "/" : "."); + + slash = path; + last_elem = 0; + while (1) + { + int name_max; + int length; /* Length of partial path being checked. */ + char *start; /* Start of path element being checked. */ + + /* Find the end of this element of the path. + Then chop off the rest of the path after this element. */ + while (*slash == '/') + slash++; + start = slash; + slash = strchr (slash, '/'); + if (slash != NULL) + *slash = '\0'; + else + { + last_elem = 1; + slash = strchr (start, '\0'); + } + + if (!last_elem) + { + exists = dir_ok (path); + if (dir_ok == 0) + { + free (parent); + return 1; + } + } + + length = slash - start; + /* Since we know that `parent' is a directory, it's ok to call + pathconf with it as the argument. (If `parent' isn't a directory + or doesn't exist, the behavior of pathconf is undefined.) + But if `parent' is a directory and is on a remote file system, + it's likely that pathconf can't give us a reasonable value + and will return -1. (NFS and tempfs are not POSIX . . .) + In that case, we have no choice but to assume the pessimal + POSIX minimums. */ + name_max = portability ? _POSIX_NAME_MAX : NAME_MAX_FOR (parent); + if (name_max < 0) + name_max = _POSIX_NAME_MAX; + if (length > name_max) + { + error (0, 0, "name `%s' has length %d; exceeds limit of %d", + start, length, name_max); + free (parent); + return 1; + } + + if (last_elem) + break; + + if (exists == 1) + { + free (parent); + parent = xstrdup (path); + } + + *slash++ = '/'; + } + + /* `parent' is now the last existing leading directory in the whole path, + so it's ok to call pathconf with it as the argument. */ + path_max = portability ? _POSIX_PATH_MAX : PATH_MAX_FOR (parent); + if (path_max < 0) + path_max = _POSIX_PATH_MAX; + free (parent); + if (strlen (path) > path_max) + { + error (0, 0, "path `%s' has length %d; exceeds limit of %d", + path, strlen (path), path_max); + return 1; + } + + return 0; +} diff --git a/examples/loadables/print.c b/examples/loadables/print.c new file mode 100644 index 0000000..8fea61c --- /dev/null +++ b/examples/loadables/print.c @@ -0,0 +1,553 @@ +/* + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +#include +#include +#include + +#include "bashansi.h" +#include "shell.h" +#include "builtins.h" +#include "stdc.h" +#include "bashgetopt.h" + +#if !defined (errno) +extern int errno; +#endif + +#define PF(f, func) { \ + if (fieldwidth) \ + if (precision) \ + (void)fprintf(ofp, f, fieldwidth, precision, func); \ + else \ + (void)fprintf(ofp, f, fieldwidth, func); \ + else if (precision) \ + (void)fprintf(ofp, f, precision, func); \ + else \ + (void)fprintf(ofp, f, func); \ +} + +static int asciicode __P((void)); +static void escape __P((char *)); +static int getchr __P((void)); +static double getdouble __P((void)); +static int getint __P((int *)); +static int getlong __P((long *)); +static char *getstr __P((void)); +static char *mklong __P((char *, int)); +static void usage __P((void)); + +static char **gargv; + +int print_builtin (); +static int printf_main (); +static int printargs (); + +static FILE *ofp; + +extern char *ansicstr (); +extern char *single_quote (); +extern char **make_builtin_argv (); + +extern char *this_command_name; + +extern int optind; + +static char *print_doc[] = { + "Output the arguments. The -f option means to use the argument as a", + "format string as would be supplied to printf(1). The rest of the", + "options are as in ksh.", + (char *)NULL +}; + +struct builtin print_struct = { + "print", + print_builtin, + BUILTIN_ENABLED, + print_doc, + "print [-Rnprs] [-u unit] [-f format] [arguments]", + (char *)0 +}; + +#ifndef ISOPTION +#define ISOPTION(s, c) (s[0] == '-' && s[2] == '\0' && s[1] == c) +#endif + +int +print_builtin (list) + WORD_LIST *list; +{ + int c, r, nflag, raw, ofd, sflag; + char **v, *pfmt, *arg; + WORD_LIST *l; + + nflag = raw = sflag = 0; + ofd = 1; + pfmt = 0; + + reset_internal_getopt (); + while ((c = internal_getopt (list, "Rnprsu:f:")) != -1) + { + switch (c) + { + case 'R': + raw = 2; + loptend = lcurrent; + if (loptend && ISOPTION (loptend->word->word, 'n')) + { + loptend = loptend->next; + nflag = 1; + } + goto opt_end; + case 'r': + raw = 1; + break; + case 'n': + nflag = 1; + break; + case 's': + sflag = 1; + break; + case 'p': + break; /* NOP */ + case 'u': + if (all_digits (list_optarg)) + ofd = atoi (list_optarg); + else + { + for (l = list; l->next && l->next != lcurrent; l = l->next); + lcurrent = loptend = l; + goto opt_end; + } + break; + case 'f': + pfmt = list_optarg; + break; + default: + builtin_usage (); + return (EX_USAGE); + } + } + +opt_end: + list = loptend; + + ofp = (ofd == 1) ? stdout : fdopen (dup (ofd), "w"); + + if (pfmt) + { + v = word_list_to_argv (list, 0, 2, &c); + v[0] = this_command_name; + v[1] = pfmt; + r = printf_main (c, v); + free (v); + return r; + } + + if (raw) + { + for (l = list; l; l = l->next) + { + fprintf (ofp, "%s", l->word->word); + if (l->next) + fprintf (ofp, " "); + } + if (nflag == 0) + fprintf (ofp, "\n"); + fflush (ofp); + return (0); + } + + r = printargs (list, ofp); + if (r && nflag == 0) + fprintf (ofp, "\n"); + if (ofd != 1) + fclose (ofp); + return 0; +} + +static int printargs (list, ofp) + WORD_LIST *list; + FILE *ofp; +{ + WORD_LIST *l; + char *ostr; + int sawc; + + for (sawc = 0, l = list; l; l = l->next) + { + ostr = ansicstr (l->word->word, strlen (l->word->word), &sawc); + fprintf (ofp, "%s", ostr); + free (ostr); + if (sawc) + return (0); + if (l->next) + fprintf (ofp, " "); + } + return (1); +} + +static int +printf_main(argc, argv) + int argc; + char *argv[]; +{ + static char *skip1, *skip2; + int ch, end, fieldwidth, precision; + char convch, nextch, *format, *fmt, *start; + + while ((ch = getopt(argc, argv, "")) != EOF) + switch (ch) { + case '?': + default: + usage(); + return (1); + } + argc -= optind; + argv += optind; + + if (argc < 1) { + usage(); + return (1); + } + + /* + * Basic algorithm is to scan the format string for conversion + * specifications -- once one is found, find out if the field + * width or precision is a '*'; if it is, gather up value. Note, + * format strings are reused as necessary to use up the provided + * arguments, arguments of zero/null string are provided to use + * up the format string. + */ + skip1 = "#-+ 0"; + skip2 = "*0123456789"; + + escape(fmt = format = *argv); /* backslash interpretation */ + gargv = ++argv; + for (;;) { + end = 0; + /* find next format specification */ +next: for (start = fmt;; ++fmt) { + if (!*fmt) { + /* avoid infinite loop */ + if (end == 1) { + warnx("missing format character", + NULL, NULL); + return (1); + } + end = 1; + if (fmt > start) + (void)printf("%s", start); + if (!*gargv) + return (0); + fmt = format; + goto next; + } + /* %% prints a % */ + if (*fmt == '%') { + if (*++fmt != '%') + break; + *fmt++ = '\0'; + (void)printf("%s", start); + goto next; + } + } + + /* skip to field width */ + for (; strchr(skip1, *fmt); ++fmt); + if (*fmt == '*') { + if (getint(&fieldwidth)) + return (1); + } else + fieldwidth = 0; + + /* skip to possible '.', get following precision */ + for (; strchr(skip2, *fmt); ++fmt); + if (*fmt == '.') + ++fmt; + if (*fmt == '*') { + if (getint(&precision)) + return (1); + } else + precision = 0; + + /* skip to conversion char */ + for (; strchr(skip2, *fmt); ++fmt); + if (!*fmt) { + warnx("missing format character", NULL, NULL); + return (1); + } + + convch = *fmt; + nextch = *++fmt; + *fmt = '\0'; + switch(convch) { + case 'c': { + char p; + + p = getchr(); + PF(start, p); + break; + } + case 's': { + char *p; + + p = getstr(); + PF(start, p); + break; + } + case 'b': { /* expand escapes in argument */ + char *p; + + p = getstr(); + escape(p); + PF(start, p); + break; + } + case 'q': { /* print with shell single quoting */ + char *p, *p2; + + p = getstr(); + p2 = single_quote(p); + PF(start, p2); + free(p2); + break; + } + case 'd': case 'i': case 'o': case 'u': case 'x': case 'X': { + long p; + char *f; + + if ((f = mklong(start, convch)) == NULL) + return (1); + if (getlong(&p)) + return (1); + PF(f, p); + break; + } + case 'e': case 'E': case 'f': case 'g': case 'G': { + double p; + + p = getdouble(); + PF(start, p); + break; + } + default: + warnx("illegal format character", NULL, NULL); + return (1); + } + *fmt = nextch; + } + /* NOTREACHED */ +} + +static char * +mklong(str, ch) + char *str; + int ch; +{ + static char copy[64]; + int len; + + len = strlen(str) + 2; + memmove(copy, str, len - 3); + copy[len - 3] = 'l'; + copy[len - 2] = ch; + copy[len - 1] = '\0'; + return (copy); +} + +static void +escape(fmt) + register char *fmt; +{ + register char *store; + register int value, c; + + for (store = fmt; c = *fmt; ++fmt, ++store) { + if (c != '\\') { + *store = c; + continue; + } + switch (*++fmt) { + case '\0': /* EOS, user error */ + *store = '\\'; + *++store = '\0'; + return; + case '\\': /* backslash */ + case '\'': /* single quote */ + *store = *fmt; + break; + case 'a': /* bell/alert */ + *store = '\7'; + break; + case 'b': /* backspace */ + *store = '\b'; + break; + case 'c': + return; + case 'e': + case 'E': + *store = '\033'; + break; + case 'f': /* form-feed */ + *store = '\f'; + break; + case 'n': /* newline */ + *store = '\n'; + break; + case 'r': /* carriage-return */ + *store = '\r'; + break; + case 't': /* horizontal tab */ + *store = '\t'; + break; + case 'v': /* vertical tab */ + *store = '\13'; + break; + /* octal constant */ + case '0': case '1': case '2': case '3': + case '4': case '5': case '6': case '7': + for (c = 3, value = 0; + c-- && *fmt >= '0' && *fmt <= '7'; ++fmt) { + value <<= 3; + value += *fmt - '0'; + } + --fmt; + *store = value; + break; + default: + *store = *fmt; + break; + } + } + *store = '\0'; +} + +static int +getchr() +{ + if (!*gargv) + return ('\0'); + return ((int)**gargv++); +} + +static char * +getstr() +{ + if (!*gargv) + return (""); + return (*gargv++); +} + +static char *Number = "+-.0123456789"; +static int +getint(ip) + int *ip; +{ + long val; + + if (getlong(&val)) + return (1); + if (val > INT_MAX) { + warnx("%s: %s", *gargv, strerror(ERANGE)); + return (1); + } + *ip = val; + return (0); +} + +static int +getlong(lp) + long *lp; +{ + long val; + char *ep; + + if (!*gargv) { + *lp = 0; + return (0); + } + if (strchr(Number, **gargv)) { + errno = 0; + val = strtol(*gargv, &ep, 0); + if (*ep != '\0') { + warnx("%s: illegal number", *gargv, NULL); + return (1); + } + if (errno == ERANGE) + if (val == LONG_MAX) { + warnx("%s: %s", *gargv, strerror(ERANGE)); + return (1); + } + if (val == LONG_MIN) { + warnx("%s: %s", *gargv, strerror(ERANGE)); + return (1); + } + + *lp = val; + ++gargv; + return (0); + } + *lp = (long)asciicode(); + return (0); +} + +static double +getdouble() +{ + if (!*gargv) + return ((double)0); + if (strchr(Number, **gargv)) + return (atof(*gargv++)); + return ((double)asciicode()); +} + +static int +asciicode() +{ + register int ch; + + ch = **gargv; + if (ch == '\'' || ch == '"') + ch = (*gargv)[1]; + ++gargv; + return (ch); +} + +static void +usage() +{ + (void)fprintf(stderr, "usage: print [-Rnprs] [-u unit] [-f format] [arg ...]\n"); +} diff --git a/examples/loadables/printf.c b/examples/loadables/printf.c new file mode 100644 index 0000000..33996c6 --- /dev/null +++ b/examples/loadables/printf.c @@ -0,0 +1,460 @@ +/* + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#if !defined(BUILTIN) && !defined(SHELL) +#ifndef lint +static char copyright[] = +"@(#) Copyright (c) 1989, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ +#endif + +#ifndef lint +static char sccsid[] = "@(#)printf.c 8.1 (Berkeley) 7/20/93"; +#endif /* not lint */ + +#include + +#include +#include +#include + +#include "bashansi.h" +#include "shell.h" +#include "builtins.h" +#include "stdc.h" + +#if !defined (errno) +extern int errno; +#endif + +#define PF(f, func) { \ + if (fieldwidth) \ + if (precision) \ + (void)printf(f, fieldwidth, precision, func); \ + else \ + (void)printf(f, fieldwidth, func); \ + else if (precision) \ + (void)printf(f, precision, func); \ + else \ + (void)printf(f, func); \ +} + +static int asciicode __P((void)); +static void escape __P((char *)); +static int getchr __P((void)); +static double getdouble __P((void)); +static int getint __P((int *)); +static int getlong __P((long *)); +static char *getstr __P((void)); +static char *mklong __P((char *, int)); +static void usage __P((void)); + +static char **gargv; + +int printf_builtin (); +static int printf_main (); +extern char *this_command_name; +extern char *single_quote (); +extern char **make_builtin_argv (); + +static char *printf_doc[] = { + "printf formats and prints its arguments, after the first, under control", + "of the format. The format is a character string which contains three", + "types of objects: plain characters, which are simply copied to standard", + "output, character escape sequences which are converted and copied to the", + "standard output, and format specifications, each of which causes printing", + "of the next successive argument. In addition to the standard printf(1)", + "formats, %%b means to expand escapes in the corresponding argument, and", + "%%q means to quote the argument in a way that can be reused as shell input.", + (char *)NULL +}; + +struct builtin printf_struct = { + "printf", + printf_builtin, + BUILTIN_ENABLED, + printf_doc, + "printf format [arguments]", + (char *)0 +}; + +int +printf_builtin (list) + WORD_LIST *list; +{ + int c, r; + char **v; + WORD_LIST *l; + + v = make_builtin_argv (list, &c); + r = printf_main (c, v); + free (v); + fflush(stdout); + + return r; +} + +static int +printf_main(argc, argv) + int argc; + char *argv[]; +{ + extern int optind; + static char *skip1, *skip2; + int ch, end, fieldwidth, precision; + char convch, nextch, *format, *fmt, *start; + + while ((ch = getopt(argc, argv, "")) != EOF) + switch (ch) { + case '?': + default: + usage(); + return (1); + } + argc -= optind; + argv += optind; + + if (argc < 1) { + usage(); + return (1); + } + + /* + * Basic algorithm is to scan the format string for conversion + * specifications -- once one is found, find out if the field + * width or precision is a '*'; if it is, gather up value. Note, + * format strings are reused as necessary to use up the provided + * arguments, arguments of zero/null string are provided to use + * up the format string. + */ + skip1 = "#-+ 0"; + skip2 = "*0123456789"; + + escape(fmt = format = *argv); /* backslash interpretation */ + gargv = ++argv; + for (;;) { + end = 0; + /* find next format specification */ +next: for (start = fmt;; ++fmt) { + if (!*fmt) { + /* avoid infinite loop */ + if (end == 1) { + warnx("missing format character", + NULL, NULL); + return (1); + } + end = 1; + if (fmt > start) + (void)printf("%s", start); + if (!*gargv) + return (0); + fmt = format; + goto next; + } + /* %% prints a % */ + if (*fmt == '%') { + if (*++fmt != '%') + break; + *fmt++ = '\0'; + (void)printf("%s", start); + goto next; + } + } + + /* skip to field width */ + for (; strchr(skip1, *fmt); ++fmt); + if (*fmt == '*') { + if (getint(&fieldwidth)) + return (1); + } else + fieldwidth = 0; + + /* skip to possible '.', get following precision */ + for (; strchr(skip2, *fmt); ++fmt); + if (*fmt == '.') + ++fmt; + if (*fmt == '*') { + if (getint(&precision)) + return (1); + } else + precision = 0; + + /* skip to conversion char */ + for (; strchr(skip2, *fmt); ++fmt); + if (!*fmt) { + warnx("missing format character", NULL, NULL); + return (1); + } + + convch = *fmt; + nextch = *++fmt; + *fmt = '\0'; + switch(convch) { + case 'c': { + char p; + + p = getchr(); + PF(start, p); + break; + } + case 's': { + char *p; + + p = getstr(); + PF(start, p); + break; + } + case 'b': { /* expand escapes in argument */ + char *p; + + p = getstr(); + escape(p); + PF("%s", p); + break; + } + case 'q': { /* print with shell single quoting */ + char *p, *p2; + + p = getstr(); + p2 = single_quote(p); + PF("%s", p2); + free(p2); + break; + } + case 'd': case 'i': case 'o': case 'u': case 'x': case 'X': { + long p; + char *f; + + if ((f = mklong(start, convch)) == NULL) + return (1); + if (getlong(&p)) + return (1); + PF(f, p); + break; + } + case 'e': case 'E': case 'f': case 'g': case 'G': { + double p; + + p = getdouble(); + PF(start, p); + break; + } + default: + warnx("illegal format character", NULL, NULL); + return (1); + } + *fmt = nextch; + } + /* NOTREACHED */ +} + +static char * +mklong(str, ch) + char *str; + int ch; +{ + static char copy[64]; + int len; + + len = strlen(str) + 2; + memmove(copy, str, len - 3); + copy[len - 3] = 'l'; + copy[len - 2] = ch; + copy[len - 1] = '\0'; + return (copy); +} + +static void +escape(fmt) + register char *fmt; +{ + register char *store; + register int value, c; + + for (store = fmt; c = *fmt; ++fmt, ++store) { + if (c != '\\') { + *store = c; + continue; + } + switch (*++fmt) { + case '\0': /* EOS, user error */ + *store = '\\'; + *++store = '\0'; + return; + case '\\': /* backslash */ + case '\'': /* single quote */ + *store = *fmt; + break; + case 'a': /* bell/alert */ + *store = '\7'; + break; + case 'b': /* backspace */ + *store = '\b'; + break; + case 'c': + return; + case 'e': + case 'E': + *store = '\033'; + break; + case 'f': /* form-feed */ + *store = '\f'; + break; + case 'n': /* newline */ + *store = '\n'; + break; + case 'r': /* carriage-return */ + *store = '\r'; + break; + case 't': /* horizontal tab */ + *store = '\t'; + break; + case 'v': /* vertical tab */ + *store = '\13'; + break; + /* octal constant */ + case '0': case '1': case '2': case '3': + case '4': case '5': case '6': case '7': + for (c = 3, value = 0; + c-- && *fmt >= '0' && *fmt <= '7'; ++fmt) { + value <<= 3; + value += *fmt - '0'; + } + --fmt; + *store = value; + break; + default: + *store = *fmt; + break; + } + } + *store = '\0'; +} + +static int +getchr() +{ + if (!*gargv) + return ('\0'); + return ((int)**gargv++); +} + +static char * +getstr() +{ + if (!*gargv) + return (""); + return (*gargv++); +} + +static char *Number = "+-.0123456789"; +static int +getint(ip) + int *ip; +{ + long val; + + if (getlong(&val)) + return (1); + if (val > INT_MAX) { + warnx("%s: %s", *gargv, strerror(ERANGE)); + return (1); + } + *ip = val; + return (0); +} + +static int +getlong(lp) + long *lp; +{ + long val; + char *ep; + + if (!*gargv) { + *lp = 0; + return (0); + } + if (strchr(Number, **gargv)) { + errno = 0; + val = strtol(*gargv, &ep, 0); + if (*ep != '\0') { + warnx("%s: illegal number", *gargv, NULL); + return (1); + } + if (errno == ERANGE) + if (val == LONG_MAX) { + warnx("%s: %s", *gargv, strerror(ERANGE)); + return (1); + } + if (val == LONG_MIN) { + warnx("%s: %s", *gargv, strerror(ERANGE)); + return (1); + } + + *lp = val; + ++gargv; + return (0); + } + *lp = (long)asciicode(); + return (0); +} + +static double +getdouble() +{ + if (!*gargv) + return ((double)0); + if (strchr(Number, **gargv)) + return (atof(*gargv++)); + return ((double)asciicode()); +} + +static int +asciicode() +{ + register int ch; + + ch = **gargv; + if (ch == '\'' || ch == '"') + ch = (*gargv)[1]; + ++gargv; + return (ch); +} + +static void +usage() +{ + (void)fprintf(stderr, "usage: printf format [arg ...]\n"); +} diff --git a/examples/loadables/pushd.c b/examples/loadables/pushd.c new file mode 100644 index 0000000..75cd627 --- /dev/null +++ b/examples/loadables/pushd.c @@ -0,0 +1,601 @@ +/* pushd.c, created from pushd.def. */ +#include + +#include +#include + +#if defined (HAVE_UNISTD_H) +# include +#endif + +#include "bashansi.h" + +#include + +#include + +#include "shell.h" +#include "builtins.h" +#include "maxpath.h" +#include "common.h" + +#if !defined (errno) +extern int errno; +#endif /* !errno */ + +static char *m_badarg = "%s: bad argument"; + +/* The list of remembered directories. */ +static char **pushd_directory_list = (char **)NULL; + +/* Number of existing slots in this list. */ +static int directory_list_size; + +/* Offset to the end of the list. */ +static int directory_list_offset; + +static void pushd_error (); +static void clear_directory_stack (); +static int cd_to_string (); +static int change_to_temp (); +static int get_dirstack_index (); +static void add_dirstack_element (); + +#define NOCD 0x01 +#define ROTATE 0x02 +#define LONGFORM 0x04 +#define CLEARSTAK 0x08 + +int +pushd_builtin (list) + WORD_LIST *list; +{ + char *temp, *current_directory, *top; + int j, flags; + long num; + char direction; + + /* If there is no argument list then switch current and + top of list. */ + if (list == 0) + { + if (directory_list_offset == 0) + { + builtin_error ("no other directory"); + return (EXECUTION_FAILURE); + } + + current_directory = get_working_directory ("pushd"); + if (current_directory == 0) + return (EXECUTION_FAILURE); + + j = directory_list_offset - 1; + temp = pushd_directory_list[j]; + pushd_directory_list[j] = current_directory; + j = change_to_temp (temp); + free (temp); + return j; + } + + for (flags = 0; list; list = list->next) + { + if (ISOPTION (list->word->word, 'n')) + { + flags |= NOCD; + } + else if (ISOPTION (list->word->word, '-')) + { + list = list->next; + break; + } + else if (list->word->word[0] == '-' && list->word->word[1] == '\0') + /* Let `pushd -' work like it used to. */ + break; + else if (((direction = list->word->word[0]) == '+') || direction == '-') + { + if (legal_number (list->word->word + 1, &num) == 0) + { + builtin_error (m_badarg, list->word->word); + builtin_usage (); + return (EXECUTION_FAILURE); + } + + if (direction == '-') + num = directory_list_offset - num; + + if (num > directory_list_offset || num < 0) + { + pushd_error (directory_list_offset, list->word->word); + return (EXECUTION_FAILURE); + } + flags |= ROTATE; + } + else if (*list->word->word == '-') + { + bad_option (list->word->word); + builtin_usage (); + return (EXECUTION_FAILURE); + } + else + break; + } + + if (flags & ROTATE) + { + /* Rotate the stack num times. Remember, the current + directory acts like it is part of the stack. */ + temp = get_working_directory ("pushd"); + + if (num == 0) + { + j = ((flags & NOCD) == 0) ? change_to_temp (temp) : EXECUTION_SUCCESS; + free (temp); + return j; + } + + do + { + top = pushd_directory_list[directory_list_offset - 1]; + + for (j = directory_list_offset - 2; j > -1; j--) + pushd_directory_list[j + 1] = pushd_directory_list[j]; + + pushd_directory_list[j + 1] = temp; + + temp = top; + num--; + } + while (num); + + j = ((flags & NOCD) == 0) ? change_to_temp (temp) : EXECUTION_SUCCESS; + free (temp); + return j; + } + + if (list == 0) + return (EXECUTION_SUCCESS); + + /* Change to the directory in list->word->word. Save the current + directory on the top of the stack. */ + current_directory = get_working_directory ("pushd"); + if (current_directory == 0) + return (EXECUTION_FAILURE); + + j = ((flags & NOCD) == 0) ? cd_builtin (list) : EXECUTION_SUCCESS; + if (j == EXECUTION_SUCCESS) + { + add_dirstack_element ((flags & NOCD) ? savestring (list->word->word) : current_directory); + dirs_builtin ((WORD_LIST *)NULL); + return (EXECUTION_SUCCESS); + } + else + { + free (current_directory); + return (EXECUTION_FAILURE); + } +} + +/* Pop the directory stack, and then change to the new top of the stack. + If LIST is non-null it should consist of a word +N or -N, which says + what element to delete from the stack. The default is the top one. */ +int +popd_builtin (list) + WORD_LIST *list; +{ + register int i; + long which; + int flags; + char direction; + + for (flags = 0, which = 0L, direction = '+'; list; list = list->next) + { + if (ISOPTION (list->word->word, 'n')) + { + flags |= NOCD; + } + else if (ISOPTION (list->word->word, '-')) + { + list = list->next; + break; + } + else if (((direction = list->word->word[0]) == '+') || direction == '-') + { + if (legal_number (list->word->word + 1, &which) == 0) + { + builtin_error (m_badarg, list->word->word); + builtin_usage (); + return (EXECUTION_FAILURE); + } + } + else if (*list->word->word == '-') + { + bad_option (list->word->word); + builtin_usage (); + return (EXECUTION_FAILURE); + } + else + break; + } + + if (which > directory_list_offset || (directory_list_offset == 0 && which == 0)) + { + pushd_error (directory_list_offset, list ? list->word->word : ""); + return (EXECUTION_FAILURE); + } + + /* Handle case of no specification, or top of stack specification. */ + if ((direction == '+' && which == 0) || + (direction == '-' && which == directory_list_offset)) + { + i = ((flags & NOCD) == 0) ? cd_to_string (pushd_directory_list[directory_list_offset - 1]) + : EXECUTION_SUCCESS; + if (i != EXECUTION_SUCCESS) + return (i); + free (pushd_directory_list[--directory_list_offset]); + } + else + { + /* Since an offset other than the top directory was specified, + remove that directory from the list and shift the remainder + of the list into place. */ + i = (direction == '+') ? directory_list_offset - which : which; + free (pushd_directory_list[i]); + directory_list_offset--; + + /* Shift the remainder of the list into place. */ + for (; i < directory_list_offset; i++) + pushd_directory_list[i] = pushd_directory_list[i + 1]; + } + + dirs_builtin ((WORD_LIST *)NULL); + return (EXECUTION_SUCCESS); +} + +/* Print the current list of directories on the directory stack. */ +int +dirs_builtin (list) + WORD_LIST *list; +{ + int flags, desired_index, index_flag, vflag; + long i; + char *temp, *w; + + for (flags = vflag = index_flag = 0, desired_index = -1, w = ""; list; list = list->next) + { + if (ISOPTION (list->word->word, 'l')) + { + flags |= LONGFORM; + } + else if (ISOPTION (list->word->word, 'c')) + { + flags |= CLEARSTAK; + } + else if (ISOPTION (list->word->word, 'v')) + { + vflag |= 2; + } + else if (ISOPTION (list->word->word, 'p')) + { + vflag |= 1; + } + else if (ISOPTION (list->word->word, '-')) + { + list = list->next; + break; + } + else if (*list->word->word == '+' || *list->word->word == '-') + { + int sign; + if (legal_number (w = list->word->word + 1, &i) == 0) + { + builtin_error (m_badarg, list->word->word); + builtin_usage (); + return (EXECUTION_FAILURE); + } + sign = (*list->word->word == '+') ? 1 : -1; + desired_index = get_dirstack_index (i, sign, &index_flag); + } + else + { + bad_option (list->word->word); + builtin_usage (); + return (EXECUTION_FAILURE); + } + } + + if (flags & CLEARSTAK) + { + clear_directory_stack (); + return (EXECUTION_SUCCESS); + } + + if (index_flag && (desired_index < 0 || desired_index > directory_list_offset)) + { + pushd_error (directory_list_offset, w); + return (EXECUTION_FAILURE); + } + +#define DIRSTACK_FORMAT(temp) \ + (flags & LONGFORM) ? temp : polite_directory_format (temp) + + /* The first directory printed is always the current working directory. */ + if (index_flag == 0 || (index_flag == 1 && desired_index == 0)) + { + temp = get_working_directory ("dirs"); + if (temp == 0) + temp = savestring (""); + if (vflag & 2) + printf ("%2d %s", 0, DIRSTACK_FORMAT (temp)); + else + printf ("%s", DIRSTACK_FORMAT (temp)); + free (temp); + if (index_flag) + { + putchar ('\n'); + return EXECUTION_SUCCESS; + } + } + +#define DIRSTACK_ENTRY(i) \ + (flags & LONGFORM) ? pushd_directory_list[i] \ + : polite_directory_format (pushd_directory_list[i]) + + /* Now print the requested directory stack entries. */ + if (index_flag) + { + if (vflag & 2) + printf ("%2d %s", directory_list_offset - desired_index, + DIRSTACK_ENTRY (desired_index)); + else + printf ("%s", DIRSTACK_ENTRY (desired_index)); + } + else + for (i = directory_list_offset - 1; i >= 0; i--) + if (vflag >= 2) + printf ("\n%2d %s", directory_list_offset - (int)i, DIRSTACK_ENTRY (i)); + else + printf ("%s%s", (vflag & 1) ? "\n" : " ", DIRSTACK_ENTRY (i)); + + putchar ('\n'); + fflush (stdout); + return (EXECUTION_SUCCESS); +} + +static void +pushd_error (offset, arg) + int offset; + char *arg; +{ + if (offset == 0) + builtin_error ("directory stack empty"); + else if (arg) + builtin_error ("%s: bad directory stack index", arg); + else + builtin_error ("bad directory stack index"); +} + +static void +clear_directory_stack () +{ + register int i; + + for (i = 0; i < directory_list_offset; i++) + free (pushd_directory_list[i]); + directory_list_offset = 0; +} + +/* Switch to the directory in NAME. This uses the cd_builtin to do the work, + so if the result is EXECUTION_FAILURE then an error message has already + been printed. */ +static int +cd_to_string (name) + char *name; +{ + WORD_LIST *tlist; + int result; + + tlist = make_word_list (make_word (name), NULL); + result = cd_builtin (tlist); + dispose_words (tlist); + return (result); +} + +static int +change_to_temp (temp) + char *temp; +{ + int tt; + + tt = temp ? cd_to_string (temp) : EXECUTION_FAILURE; + + if (tt == EXECUTION_SUCCESS) + dirs_builtin ((WORD_LIST *)NULL); + + return (tt); +} + +static void +add_dirstack_element (dir) + char *dir; +{ + int j; + + if (directory_list_offset == directory_list_size) + { + j = (directory_list_size += 10) * sizeof (char *); + pushd_directory_list = (char **)xrealloc (pushd_directory_list, j); + } + pushd_directory_list[directory_list_offset++] = dir; +} + +static int +get_dirstack_index (ind, sign, indexp) + int ind, sign, *indexp; +{ + if (indexp) + *indexp = sign > 0 ? 1 : 2; + + /* dirs +0 prints the current working directory. */ + /* dirs -0 prints last element in directory stack */ + if (ind == 0 && sign > 0) + return 0; + else if (ind == directory_list_offset) + { + if (indexp) + *indexp = sign > 0 ? 2 : 1; + return 0; + } + else + return (sign > 0 ? directory_list_offset - ind : ind); +} + +char * +get_dirstack_element (ind, sign) + int ind, sign; +{ + int i; + + i = get_dirstack_index (ind, sign, (int *)NULL); + return (i < 0 || i > directory_list_offset) ? (char *)NULL + : pushd_directory_list[i]; +} + +void +set_dirstack_element (ind, sign, value) + int ind, sign; + char *value; +{ + int i; + + i = get_dirstack_index (ind, sign, (int *)NULL); + if (ind == 0 || i < 0 || i > directory_list_offset) + return; + free (pushd_directory_list[i]); + pushd_directory_list[i] = savestring (value); +} + +WORD_LIST * +get_directory_stack () +{ + register int i; + WORD_LIST *ret; + char *d, *t; + + for (ret = (WORD_LIST *)NULL, i = 0; i < directory_list_offset; i++) + { + d = polite_directory_format (pushd_directory_list[i]); + ret = make_word_list (make_word (d), ret); + } + /* Now the current directory. */ + d = get_working_directory ("dirstack"); + i = 0; /* sentinel to decide whether or not to free d */ + if (d == 0) + d = "."; + else + { + t = polite_directory_format (d); + /* polite_directory_format sometimes returns its argument unchanged. + If it does not, we can free d right away. If it does, we need to + mark d to be deleted later. */ + if (t != d) + { + free (d); + d = t; + } + else /* t == d, so d is what we want */ + i = 1; + } + ret = make_word_list (make_word (d), ret); + if (i) + free (d); + return ret; /* was (REVERSE_LIST (ret, (WORD_LIST *)); */ +} + +static char *dirs_doc[] = { + "Display the list of currently remembered directories. Directories", + "find their way onto the list with the `pushd' command; you can get", + "back up through the list with the `popd' command.", + "", + "The -l flag specifies that `dirs' should not print shorthand versions", + "of directories which are relative to your home directory. This means", + "that `~/bin' might be displayed as `/homes/bfox/bin'. The -v flag", + "causes `dirs' to print the directory stack with one entry per line,", + "prepending the directory name with its position in the stack. The -p", + "flag does the same thing, but the stack position is not prepended.", + "The -c flag clears the directory stack by deleting all of the elements.", + "", + "+N displays the Nth entry counting from the left of the list shown by", + " dirs when invoked without options, starting with zero.", + "", + "-N displays the Nth entry counting from the right of the list shown by", + " dirs when invoked without options, starting with zero.", + (char *)NULL +}; + +static char *pushd_doc[] = { + "Adds a directory to the top of the directory stack, or rotates", + "the stack, making the new top of the stack the current working", + "directory. With no arguments, exchanges the top two directories.", + "", + "+N Rotates the stack so that the Nth directory (counting", + " from the left of the list shown by `dirs') is at the top.", + "", + "-N Rotates the stack so that the Nth directory (counting", + " from the right) is at the top.", + "", + "-n suppress the normal change of directory when adding directories", + " to the stack, so only the stack is manipulated.", + "", + "dir adds DIR to the directory stack at the top, making it the", + " new current working directory.", + "", + "You can see the directory stack with the `dirs' command.", + (char *)NULL +}; + +static char *popd_doc[] = { + "Removes entries from the directory stack. With no arguments,", + "removes the top directory from the stack, and cd's to the new", + "top directory.", + "", + "+N removes the Nth entry counting from the left of the list", + " shown by `dirs', starting with zero. For example: `popd +0'", + " removes the first directory, `popd +1' the second.", + "", + "-N removes the Nth entry counting from the right of the list", + " shown by `dirs', starting with zero. For example: `popd -0'", + " removes the last directory, `popd -1' the next to last.", + "", + "-n suppress the normal change of directory when removing directories", + " from the stack, so only the stack is manipulated.", + "", + "You can see the directory stack with the `dirs' command.", + (char *)NULL +}; + +struct builtin pushd_struct = { + "pushd", + pushd_builtin, + BUILTIN_ENABLED, + pushd_doc, + "pushd [+N | -N] [-n] [dir]", + 0 +}; + +struct builtin popd_struct = { + "popd", + popd_builtin, + BUILTIN_ENABLED, + popd_doc, + "popd [+N | -N] [-n]", + 0 +}; + +struct builtin dirs_struct = { + "dirs", + dirs_builtin, + BUILTIN_ENABLED, + dirs_doc, + "dirs [-clpv] [+N] [-N]", + 0 +}; diff --git a/examples/loadables/rmdir.c b/examples/loadables/rmdir.c new file mode 100644 index 0000000..8d0f06a --- /dev/null +++ b/examples/loadables/rmdir.c @@ -0,0 +1,50 @@ +/* rmdir - remove directory */ + +/* See Makefile for compilation details. */ + +#include "config.h" + +#include +#include +#include "builtins.h" +#include "shell.h" + +#if !defined (errno) +extern int errno; +#endif + +rmdir_builtin (list) + WORD_LIST *list; +{ + int rval; + WORD_LIST *l; + + if (no_options (list)) + return (EX_USAGE); + + for (rval = EXECUTION_SUCCESS, l = list; l; l = l->next) + if (rmdir (l->word->word) < 0) + { + builtin_error ("%s: %s", l->word->word, strerror (errno)); + rval = EXECUTION_FAILURE; + } + + return rval; +} + +char *rmdir_doc[] = { + "rmdir removes the directory entry specified by each argument,", + "provided the directory is empty.", + (char *)NULL +}; + +/* The standard structure describing a builtin command. bash keeps an array + of these structures. */ +struct builtin rmdir_struct = { + "rmdir", /* builtin name */ + rmdir_builtin, /* function implementing the builtin */ + BUILTIN_ENABLED, /* initial flags for builtin */ + rmdir_doc, /* array of long documentation strings. */ + "rmdir directory ...", /* usage synopsis; becomes short_doc */ + 0 /* reserved for internal use */ +}; diff --git a/examples/loadables/sleep.c b/examples/loadables/sleep.c new file mode 100644 index 0000000..57f2cb6 --- /dev/null +++ b/examples/loadables/sleep.c @@ -0,0 +1,150 @@ +/* + * sleep -- sleep for fractions of a second + * + * usage: sleep seconds[.fraction] + */ +#include "config.h" + +#include "bashtypes.h" + +#if defined (TIME_WITH_SYS_TIME) +# include +# include +#else +# if defined (HAVE_SYS_TIME_H) +# include +# else +# include +# endif +#endif + +#if defined (HAVE_UNISTD_H) +#include +#endif + +#include + +#include "shell.h" +#include "builtins.h" + +#define RETURN(x) \ + do { \ + if (sp) *sp = sec; \ + if (usp) *usp = usec; \ + return (x); \ + } while (0) + +#if defined (HAVE_TIMEVAL) && defined (HAVE_SELECT) +static int +fsleep(sec, usec) +long sec, usec; +{ + struct timeval tv; + + tv.tv_sec = sec; + tv.tv_usec = usec; + + return select(0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &tv); +} +#else /* !HAVE_TIMEVAL || !HAVE_SELECT */ +static int +fsleep(sec, usec) +long sec, usec; +{ + if (usec >= 500000) /* round */ + sec++; + return (sleep(sec)); +} +#endif /* !HAVE_TIMEVAL || !HAVE_SELECT */ + +/* + * An incredibly simplistic floating point converter. + */ +static int +convert(s, sp, usp) +char *s; +long *sp, *usp; +{ + int n; + long sec, usec; + char *p; + + sec = usec = 0; + +#define DECIMAL '.' + + for (p = s; p && *p; p++) { + if (*p == DECIMAL) /* decimal point */ + break; + if (isdigit(*p) == 0) + RETURN(0); + sec = (sec * 10) + (*p - '0'); + } + + if (*p == 0) + RETURN(1); + + if (*p == DECIMAL) + p++; + + /* Look for up to six digits past a decimal point. */ + for (n = 0; n < 6 && p[n]; n++) { + if (isdigit(p[n]) == 0) + RETURN(0); + usec = (usec * 10) + (p[n] - '0'); + } + + /* Now convert to millionths */ + if (n == 1) + usec *= 100000; + else if (n == 2) + usec *= 10000; + else if (n == 3) + usec *= 1000; + else if (n == 4) + usec *= 100; + else if (n == 5) + usec *= 10; + else if (n == 6 && p[6] && isdigit(p[6]) && p[6] >= '5') + usec++; /* round up 1 */ + RETURN(1); +} + +int +sleep_builtin (list) +WORD_LIST *list; +{ + long sec, usec; + + if (list == 0) { + builtin_usage(); + return(EX_USAGE); + } + + if (*list->word->word == '-' || list->next) { + builtin_usage (); + return (EX_USAGE); + } + + if (convert(list->word->word, &sec, &usec)) { + fsleep(sec, usec); + return(EXECUTION_SUCCESS); + } + + builtin_error("%s: bad sleep interval", list->word->word); + return (EXECUTION_FAILURE); +} + +static char *sleep_doc[] = { + "sleep suspends execution for a minimum of SECONDS[.FRACTION] seconds.", + (char *)NULL +}; + +struct builtin sleep_struct = { + "sleep", + sleep_builtin, + BUILTIN_ENABLED, + sleep_doc, + "sleep seconds[.fraction]", + 0 +}; diff --git a/examples/loadables/sprintf.c b/examples/loadables/sprintf.c new file mode 100644 index 0000000..b8cb824 --- /dev/null +++ b/examples/loadables/sprintf.c @@ -0,0 +1,514 @@ +/* + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#if !defined(BUILTIN) && !defined(SHELL) +#ifndef lint +static char copyright[] = +"@(#) Copyright (c) 1989, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ +#endif + +#ifndef lint +static char sccsid[] = "@(#)printf.c 8.1 (Berkeley) 7/20/93"; +#endif /* not lint */ + +#include + +#include +#include +#include + +#include "bashansi.h" +#include "shell.h" +#include "builtins.h" +#include "stdc.h" + +#if !defined (errno) +extern int errno; +#endif + +static char sbuf[1024]; +static int sblen; + +/* Gee, I wish sprintf could be reliably counted upon to return the + number of characters written :-( */ +#define PF(f, func) \ +do { \ + if (fieldwidth) \ + if (precision) \ + sprintf(sbuf, f, fieldwidth, precision, func); \ + else \ + sprintf(sbuf, f, fieldwidth, func); \ + else if (precision) \ + sprintf(sbuf, f, precision, func); \ + else \ + sprintf(sbuf, f, func); \ + spaddstr (sbuf, strlen (sbuf)); \ +} while (0) + +static int asciicode __P((void)); +static void escape __P((char *)); +static int getchr __P((void)); +static double getdouble __P((void)); +static int getint __P((int *)); +static int getlong __P((long *)); +static char *getstr __P((void)); +static char *mklong __P((char *, int)); +static void usage __P((void)); + +static char **gargv; + +static char *outstr; +static int outsize; +static int outind; + +int sprintf_builtin (); +static int sprintf_main (); +static void spaddstr (); + +extern char *this_command_name; +extern char *single_quote (); +extern char **make_builtin_argv (); + +static char *sprintf_doc[] = { + "sprintf formats and outputs its arguments, after the second, under control", + "of the format and assigns the result to the variable named by its first", + "argument. The format is a character string which contains three types", + "of objects: plain characters, which are simply copied to the output string,", + "character escape sequences which are converted and copied to the output", + "string, and format specifications, each of which causes printing of the", + "next successive argument. In addition to the standard sprintf(3) formats,", + "%b means to expand escapes in the corresponding argument, and %q means", + "to quote the argument in a way that can be reused as shell input. Each", + "one of the format specifications must not expand to more than 1024", + "characters, though there is no limit on the total size of the output", + "string.", + (char *)NULL +}; + +struct builtin sprintf_struct = { + "sprintf", + sprintf_builtin, + BUILTIN_ENABLED, + sprintf_doc, + "sprintf var format [arguments]", + (char *)0 +}; + +int +sprintf_builtin (list) + WORD_LIST *list; +{ + int c, r; + char **v, *varname; + WORD_LIST *l; + SHELL_VAR *var; + + if (list == 0) + { + builtin_usage (); + return (EXECUTION_FAILURE); + } + + varname = list->word->word; + list = list->next; + + if (legal_identifier (varname) == 0) + { + builtin_error ("%s: not a legal variable name", varname); + return (EXECUTION_FAILURE); + } + + outind = 0; + if (outstr == 0) + outstr = xmalloc (outsize = 64); + outstr[0] = '\0'; + + v = make_builtin_argv (list, &c); + r = sprintf_main (c, v); + free (v); + + var = bind_variable (varname, outstr); + if (readonly_p (var)) + { + builtin_error ("%s: readonly variable", varname); + return (EXECUTION_FAILURE); + } + + return r; +} + +static void +spaddstr(str, len) + char *str; + int len; +{ + RESIZE_MALLOCED_BUFFER (outstr, outind, len, outsize, 64); + strcpy (outstr + outind, str); + outind += len; +} + +static int +sprintf_main(argc, argv) + int argc; + char *argv[]; +{ + extern int optind; + static char *skip1, *skip2; + int ch, end, fieldwidth, precision; + char convch, nextch, *format, *fmt, *start; + + while ((ch = getopt(argc, argv, "")) != EOF) + switch (ch) { + case '?': + default: + usage(); + return (1); + } + argc -= optind; + argv += optind; + + if (argc < 1) { + usage(); + return (1); + } + + /* + * Basic algorithm is to scan the format string for conversion + * specifications -- once one is found, find out if the field + * width or precision is a '*'; if it is, gather up value. Note, + * format strings are reused as necessary to use up the provided + * arguments, arguments of zero/null string are provided to use + * up the format string. + */ + skip1 = "#-+ 0"; + skip2 = "*0123456789"; + + escape(fmt = format = *argv); /* backslash interpretation */ + gargv = ++argv; + for (;;) { + end = 0; + /* find next format specification */ +next: for (start = fmt;; ++fmt) { + if (!*fmt) { + /* avoid infinite loop */ + if (end == 1) { + warnx("missing format character", + NULL, NULL); + return (1); + } + end = 1; + if (fmt > start) + (void)printf("%s", start); + if (!*gargv) + return (0); + fmt = format; + goto next; + } + /* %% prints a % */ + if (*fmt == '%') { + if (*++fmt != '%') + break; + *fmt++ = '\0'; + (void)printf("%s", start); + goto next; + } + } + + /* skip to field width */ + for (; strchr(skip1, *fmt); ++fmt); + if (*fmt == '*') { + if (getint(&fieldwidth)) + return (1); + } else + fieldwidth = 0; + + /* skip to possible '.', get following precision */ + for (; strchr(skip2, *fmt); ++fmt); + if (*fmt == '.') + ++fmt; + if (*fmt == '*') { + if (getint(&precision)) + return (1); + } else + precision = 0; + + /* skip to conversion char */ + for (; strchr(skip2, *fmt); ++fmt); + if (!*fmt) { + warnx("missing format character", NULL, NULL); + return (1); + } + + convch = *fmt; + nextch = *++fmt; + *fmt = '\0'; + switch(convch) { + case 'c': { + char p; + + p = getchr(); + PF(start, p); + break; + } + case 's': { + char *p; + + p = getstr(); + PF(start, p); + break; + } + case 'b': { /* expand escapes in argument */ + char *p; + + p = getstr(); + escape(p); + PF("%s", p); + break; + } + case 'q': { /* print with shell single quoting */ + char *p, *p2; + + p = getstr(); + p2 = single_quote(p); + PF("%s", p2); + free(p2); + break; + } + case 'd': case 'i': case 'o': case 'u': case 'x': case 'X': { + long p; + char *f; + + if ((f = mklong(start, convch)) == NULL) + return (1); + if (getlong(&p)) + return (1); + PF(f, p); + break; + } + case 'e': case 'E': case 'f': case 'g': case 'G': { + double p; + + p = getdouble(); + PF(start, p); + break; + } + default: + warnx("illegal format character", NULL, NULL); + return (1); + } + *fmt = nextch; + } + /* NOTREACHED */ +} + +static char * +mklong(str, ch) + char *str; + int ch; +{ + static char copy[64]; + int len; + + len = strlen(str) + 2; + memmove(copy, str, len - 3); + copy[len - 3] = 'l'; + copy[len - 2] = ch; + copy[len - 1] = '\0'; + return (copy); +} + +static void +escape(fmt) + register char *fmt; +{ + register char *store; + register int value, c; + + for (store = fmt; c = *fmt; ++fmt, ++store) { + if (c != '\\') { + *store = c; + continue; + } + switch (*++fmt) { + case '\0': /* EOS, user error */ + *store = '\\'; + *++store = '\0'; + return; + case '\\': /* backslash */ + case '\'': /* single quote */ + *store = *fmt; + break; + case 'a': /* bell/alert */ + *store = '\7'; + break; + case 'b': /* backspace */ + *store = '\b'; + break; + case 'c': + return; + case 'e': + case 'E': + *store = '\033'; + break; + case 'f': /* form-feed */ + *store = '\f'; + break; + case 'n': /* newline */ + *store = '\n'; + break; + case 'r': /* carriage-return */ + *store = '\r'; + break; + case 't': /* horizontal tab */ + *store = '\t'; + break; + case 'v': /* vertical tab */ + *store = '\13'; + break; + /* octal constant */ + case '0': case '1': case '2': case '3': + case '4': case '5': case '6': case '7': + for (c = 3, value = 0; + c-- && *fmt >= '0' && *fmt <= '7'; ++fmt) { + value <<= 3; + value += *fmt - '0'; + } + --fmt; + *store = value; + break; + default: + *store = *fmt; + break; + } + } + *store = '\0'; +} + +static int +getchr() +{ + if (!*gargv) + return ('\0'); + return ((int)**gargv++); +} + +static char * +getstr() +{ + if (!*gargv) + return (""); + return (*gargv++); +} + +static char *Number = "+-.0123456789"; +static int +getint(ip) + int *ip; +{ + long val; + + if (getlong(&val)) + return (1); + if (val > INT_MAX) { + warnx("%s: %s", *gargv, strerror(ERANGE)); + return (1); + } + *ip = val; + return (0); +} + +static int +getlong(lp) + long *lp; +{ + long val; + char *ep; + + if (!*gargv) { + *lp = 0; + return (0); + } + if (strchr(Number, **gargv)) { + errno = 0; + val = strtol(*gargv, &ep, 0); + if (*ep != '\0') { + warnx("%s: illegal number", *gargv, NULL); + return (1); + } + if (errno == ERANGE) + if (val == LONG_MAX) { + warnx("%s: %s", *gargv, strerror(ERANGE)); + return (1); + } + if (val == LONG_MIN) { + warnx("%s: %s", *gargv, strerror(ERANGE)); + return (1); + } + + *lp = val; + ++gargv; + return (0); + } + *lp = (long)asciicode(); + return (0); +} + +static double +getdouble() +{ + if (!*gargv) + return ((double)0); + if (strchr(Number, **gargv)) + return (atof(*gargv++)); + return ((double)asciicode()); +} + +static int +asciicode() +{ + register int ch; + + ch = **gargv; + if (ch == '\'' || ch == '"') + ch = (*gargv)[1]; + ++gargv; + return (ch); +} + +static void +usage() +{ + (void)fprintf(stderr, "usage: printf format [arg ...]\n"); +} diff --git a/examples/loadables/tee.c b/examples/loadables/tee.c new file mode 100644 index 0000000..934abda --- /dev/null +++ b/examples/loadables/tee.c @@ -0,0 +1,157 @@ +/* tee - duplicate standard input */ + +/* See Makefile for compilation details. */ + +#include "config.h" + +#include "bashtypes.h" +#include "posixstat.h" +#include "filecntl.h" + +#include + +#if defined (HAVE_UNISTD_H) +# include +#endif + +#include "bashansi.h" + +#include +#include + +#include "builtins.h" +#include "shell.h" +#include "bashgetopt.h" + +#if !defined (errno) +extern int errno; +#endif + +typedef struct flist { + struct flist *next; + int fd; + char *fname; +} FLIST; + +static FLIST *tee_flist; + +#define TEE_BUFSIZE 8192 + +extern int interrupt_immediately; + +extern char *strerror (); + +tee_builtin (list) + WORD_LIST *list; +{ + int opt, append, nointr, rval, fd, fflags; + int n, nr, nw; + FLIST *fl; + char *buf, *bp; + + char *t; + + reset_internal_getopt (); + append = nointr = 0; + tee_flist = (FLIST *)NULL; + while ((opt = internal_getopt (list, "ai")) != -1) + { + switch (opt) + { + case 'a': + append = 1; + break; + case 'i': + nointr = 1; + break; + default: + builtin_usage (); + return (EX_USAGE); + } + } + list = loptend; + + if (nointr == 0) + interrupt_immediately++; + + buf = xmalloc (TEE_BUFSIZE); + + /* Initialize output file list. */ + fl = tee_flist = (FLIST *)xmalloc (sizeof(FLIST)); + tee_flist->fd = 1; + tee_flist->fname = "stdout"; + tee_flist->next = (FLIST *)NULL; + + /* Add file arguments to list of output files. */ + fflags = append ? O_WRONLY|O_CREAT|O_APPEND : O_WRONLY|O_CREAT|O_TRUNC; + for (rval = EXECUTION_SUCCESS; list; list = list->next) + { + fd = open (list->word->word, fflags, 0666); + if (fd < 0) + { + builtin_error ("%s: cannot open: %s", list->word->word, strerror (errno)); + rval = EXECUTION_FAILURE; + } + else + { + fl->next = (FLIST *)xmalloc (sizeof(FLIST)); + fl->next->fd = fd; + fl->next->fname = list->word->word; + fl = fl->next; + fl->next = (FLIST *)NULL; + } + } + + while ((nr = read(0, buf, TEE_BUFSIZE)) > 0) + for (fl = tee_flist; fl; fl = fl->next) + { + n = nr; + bp = buf; + do + { + if ((nw = write (fl->fd, bp, n)) == -1) + { + builtin_error ("%s: write error: %s", fl->fname, strerror (errno)); + rval = EXECUTION_FAILURE; + break; + } + bp += nw; + } + while (n -= nw); + } + if (nr < 0) + builtin_error ("read error: %s", strerror (errno)); + + /* Deallocate resources -- this is a builtin command. */ + tee_flist = tee_flist->next; /* skip bogus close of stdout */ + while (tee_flist) + { + fl = tee_flist; + if (close (fl->fd) < 0) + { + builtin_error ("%s: close_error: %s", fl->fname, strerror (errno)); + rval = EXECUTION_FAILURE; + } + tee_flist = tee_flist->next; + free (fl); + } + + return (rval); +} + +char *tee_doc[] = { + "Copy standard input to standard output, making a copy in each", + "filename argument. If the `-a' option is gived, the specified", + "files are appended to, otherwise they are overwritten. If the", + "`-i' option is supplied, tee ignores interrupts.", + (char *)NULL +}; + +struct builtin tee_struct = { + "tee", /* builtin name */ + tee_builtin, /* function implementing the builtin */ + BUILTIN_ENABLED, /* initial flags for builtin */ + tee_doc, /* array of long documentation strings. */ + "tee [-ai] [file ...]", /* usage synopsis; becomes short_doc */ + 0 /* reserved for internal use */ +}; diff --git a/examples/loadables/truefalse.c b/examples/loadables/truefalse.c new file mode 100644 index 0000000..e77c74c --- /dev/null +++ b/examples/loadables/truefalse.c @@ -0,0 +1,45 @@ +/* true and false builtins */ + +#include "bashtypes.h" +#include "shell.h" +#include "builtins.h" + +true_builtin (list) + WORD_LIST *list; +{ + return EXECUTION_SUCCESS; +} + +false_builtin (list) + WORD_LIST *list; +{ + return EXECUTION_FAILURE; +} + +static char *true_doc[] = { + "Return a successful result.", + (char *)NULL +}; + +static char *false_doc[] = { + "Return an unsuccessful result.", + (char *)NULL +}; + +struct builtin true_struct = { + "true", + true_builtin, + BUILTIN_ENABLED, + true_doc, + "true", + 0 +}; + +struct builtin false_struct = { + "false", + false_builtin, + BUILTIN_ENABLED, + false_doc, + "false", + 0 +}; diff --git a/examples/loadables/tty.c b/examples/loadables/tty.c new file mode 100644 index 0000000..2183123 --- /dev/null +++ b/examples/loadables/tty.c @@ -0,0 +1,59 @@ +/* tty - return terminal name */ + +/* See Makefile for compilation details. */ + +#include "config.h" + +#include +#include "builtins.h" +#include "shell.h" +#include "bashgetopt.h" + +extern char *ttyname (); + +tty_builtin (list) + WORD_LIST *list; +{ + int opt, sflag; + char *t; + + reset_internal_getopt (); + sflag = 0; + while ((opt = internal_getopt (list, "s")) != -1) + { + switch (opt) + { + case 's': + sflag = 1; + break; + default: + builtin_usage (); + return (EX_USAGE); + } + } + list = loptend; + + t = ttyname (0); + if (sflag == 0) + puts (t ? t : "not a tty"); + return (t ? EXECUTION_SUCCESS : EXECUTION_FAILURE); +} + +char *tty_doc[] = { + "tty writes the name of the terminal that is opened for standard", + "input to standard output. If the `-s' option is supplied, nothing", + "is written; the exit status determines whether or not the standard", + "input is connected to a tty.", + (char *)NULL +}; + +/* The standard structure describing a builtin command. bash keeps an array + of these structures. */ +struct builtin tty_struct = { + "tty", /* builtin name */ + tty_builtin, /* function implementing the builtin */ + BUILTIN_ENABLED, /* initial flags for builtin */ + tty_doc, /* array of long documentation strings. */ + "tty [-s]", /* usage synopsis; becomes short_doc */ + 0 /* reserved for internal use */ +}; diff --git a/examples/misc/alias-conv.bash b/examples/misc/alias-conv.bash new file mode 100755 index 0000000..cb92ee0 --- /dev/null +++ b/examples/misc/alias-conv.bash @@ -0,0 +1,38 @@ +#! /bin/bash +# +# alias-conv.sh - convert csh aliases to bash aliases and functions +# +# usage: alias-conv.sh +# +# Chet Ramey +# chet@po.cwru.edu +# +trap 'rm -f /tmp/cb$$.?' 0 1 2 3 6 15 + +T=$'\t' + +cat << \EOF >/tmp/cb$$.1 +mkalias () +{ + if [ "x$2" = "x" ]; then + echo alias ${1}="''" + elif echo "$2" | egrep -s '(\!|#)' >/dev/null 2>&1; then + comm=$(echo $2 | sed 's/\!\*/"$\@"/g + s/\!:\([1-9]\)/"$\1"/g + s/#/\#/g') + echo $1 \(\) "{" command "$comm" "; }" + else + echo alias ${1}=\'$(echo "${2}" | sed "s:':'\\\\'':")\' + fi +} +EOF + +sed "s/^\([a-zA-Z0-9_-]*\)$T\(.*\)$/mkalias \1 '\2'/" >>/tmp/cb$$.1 + +$BASH /tmp/cb$$.1 | sed -e 's/\$cwd/\$PWD/g' \ + -e 's/\$term/\$TERM/g' \ + -e 's/\$home/\$HOME/g' \ + -e 's/\$user/\$USER/g' \ + -e 's/\$prompt/\$PS1/g' + +exit 0 diff --git a/examples/misc/alias-conv.sh b/examples/misc/alias-conv.sh new file mode 100755 index 0000000..4cbebfb --- /dev/null +++ b/examples/misc/alias-conv.sh @@ -0,0 +1,38 @@ +#! /bin/bash +# +# alias-conv.sh - convert csh aliases to bash aliases and functions +# +# usage: alias-conv.sh +# +# Chet Ramey +# chet@po.cwru.edu +# +trap 'rm -f /tmp/cb$$.?' 0 1 2 3 6 15 + +T=' ' + +cat << \EOF >/tmp/cb$$.1 +mkalias () +{ + if [ "x$2" = "x" ]; then + echo alias ${1}="''" + elif echo "$2" | egrep -s '(\!|#)' >/dev/null 2>&1; then + comm=`echo $2 | sed 's/\\!\*/"$\@"/g + s/\\!:\([1-9]\)/"$\1"/g + s/#/\#/g'` + echo $1 \(\) "{" command "$comm" "; }" + else + echo alias ${1}=\'`echo "${2}" | sed "s:':'\\\\\\\\'':"`\' + fi +} +EOF + +sed "s/^\([a-zA-Z0-9_-]*\)$T\(.*\)$/mkalias \1 '\2'/" >>/tmp/cb$$.1 + +sh /tmp/cb$$.1 | sed -e 's/\$cwd/\$PWD/g' \ + -e 's/\$term/\$TERM/g' \ + -e 's/\$home/\$HOME/g' \ + -e 's/\$user/\$USER/g' \ + -e 's/\$prompt/\$PS1/g' + +exit 0 diff --git a/examples/misc/cshtobash b/examples/misc/cshtobash new file mode 100755 index 0000000..9369622 --- /dev/null +++ b/examples/misc/cshtobash @@ -0,0 +1,130 @@ +#! /bin/bash +# +# cshtobash - convert csh aliases, environment variables, and variables to +# bash equivalents +# +# usage: cshtobash [filename] +# +# If filename is given, that file is sourced. Note that csh always +# sources .cshrc. To recreate your csh login environment, run +# `cshtobash ~/.login'. +# +# Inspired by (and some borrowed from) a similar program distributed with +# zsh-3.0. +# +# Chet Ramey +# chet@po.cwru.edu +# +trap 'rm -f /tmp/cb$$.? cshout cshin' 0 1 2 3 6 15 + +T=$'\t' + +SOURCE="${1:+source $1}" + +cat << EOF >cshin +$SOURCE +alias >! /tmp/cb$$.a +setenv >! /tmp/cb$$.e +set >! /tmp/cb$$.v +EOF + +# give csh a minimal environment, similar to what login would provide +/usr/bin/env - USER=$USER HOME=$HOME PATH=/usr/bin:/bin:/usr/ucb:. TERM=$TERM SHELL=$SHELL /bin/csh -i < ./cshin > cshout 2>&1 + +# First convert aliases + +cat << \EOF >/tmp/cb$$.1 +mkalias () +{ + if [ -z "$2" ]; then + echo alias ${1}="''" + elif echo "$2" | egrep -s '(\!|#)' >/dev/null 2>&1; then + comm=$(echo $2 | sed 's/\!\*/"$\@"/g + s/\!:\([1-9]\)/"$\1"/g + s/#/\#/g') + echo $1 \(\) "{" command "$comm" "; }" + else + echo alias ${1}=\'$(echo "${2}" | sed "s:':'\\\\'':")\' + fi +} +EOF + +sed "s/^\([a-zA-Z0-9_]*\)$T\(.*\)$/mkalias \1 '\2'/" < /tmp/cb$$.a >>/tmp/cb$$.1 + +echo '# csh aliases' +echo + +$BASH /tmp/cb$$.1 | sed -e 's/\$cwd/\$PWD/g' \ + -e 's/\$term/\$TERM/g' \ + -e 's/\$home/\$HOME/g' \ + -e 's/\$user/\$USER/g' \ + -e 's/\$prompt/\$PS1/g' + +# Next, convert environment variables +echo +echo '# csh environment variables' +echo + +# Would be nice to deal with embedded newlines, e.g. in TERMCAP, but ... +sed -e '/^SHLVL/d' \ + -e '/^PWD/d' \ + -e "s/'/'"\\\\"''"/g \ + -e "s/^\([A-Za-z0-9_]*=\)/export \1'/" \ + -e "s/$/'/" < /tmp/cb$$.e + +# Finally, convert local variables +echo +echo '# csh variables' +echo + +sed -e 's/'"$T"'/=/' \ + -e "s/'/'"\\\\"''"/g \ + -e '/^[A-Za-z0-9_]*=[^(]/{ + s/=/='"'/"' + s/$/'"'/"' + }' < /tmp/cb$$.v | +sed -e '/^argv=/d' -e '/^cwd=/d' -e '/^filec=/d' -e '/^status=/d' \ + -e '/^verbose=/d' \ + -e '/^term=/d' \ + -e '/^home=/d' \ + -e '/^path=/d' \ + -e '/^user=/d' \ + -e '/^shell=/d' \ + -e '/^cdpath=/d' \ + -e '/^mail=/d' \ + -e '/^home=/s//HOME=/' \ + -e '/^prompt=/s//PS1=/' \ + -e '/^histfile=/s//HISTFILE=/' \ + -e '/^history=/s//HISTSIZE=/' \ + -e '/^savehist=$/s//HISTFILESIZE=${HISTSIZE-500}/' \ + -e '/^savehist=/s//HISTFILESIZE=/' \ + -e '/^ignoreeof=$/s/^.*$/set -o ignoreeof # ignoreeof/' \ + -e '/^ignoreeof=/s//IGNOREEOF=/' \ + -e '/^noclobber=/s/^.*$/set -C # noclobber/' \ + -e '/^notify=/s/^.*$/set -b # notify/' \ + -e '/^noglob=/s/^.*$/set -f # noglob/' \ + + +# now some special csh variables converted to bash equivalents +echo +echo '# special csh variables converted to bash equivalents' +echo + +sed -e 's/'"$T"'/=/' < /tmp/cb$$.v | +grep "^cdpath=" | +sed 's/(// + s/ /:/g + s/)// + s/cdpath=/CDPATH=/' + + +sed -e 's/'"$T"'/=/' < /tmp/cb$$.v | +grep "^mail=" | +sed 's/(// + s/ /:/g + s/)// + s/mail=/MAILPATH=/' | +sed -e 's/MAILPATH=\([0-9][0-9][^:]*\)$/MAILCHECK=\1/' \ + -e 's/MAILPATH=\([0-9][0-9][^:]*\):\(.*\)/MAILCHECK=\1 MAILPATH=\2/' + +exit 0 diff --git a/examples/suncmd.termcap b/examples/misc/suncmd.termcap similarity index 100% rename from examples/suncmd.termcap rename to examples/misc/suncmd.termcap diff --git a/examples/scripts.noah/PERMISSION b/examples/scripts.noah/PERMISSION new file mode 100644 index 0000000..f415c48 --- /dev/null +++ b/examples/scripts.noah/PERMISSION @@ -0,0 +1,29 @@ +From friedman@cli.com Thu May 25 12:19:06 1995 +Flags: 10 +Return-Path: friedman@cli.com +Received: from po.cwru.edu (root@po.CWRU.Edu [129.22.4.2]) by odin.INS.CWRU.Edu with ESMTP (8.6.10+cwru/CWRU-2.1-ins) + id MAA08685; Thu, 25 May 1995 12:19:05 -0400 (from friedman@cli.com for ) +Received: from cli.com (cli.com [192.31.85.1]) by po.cwru.edu with SMTP (8.6.10+cwru/CWRU-2.3) + id MAA11299; Thu, 25 May 1995 12:19:00 -0400 (from friedman@cli.com for ) +Received: from tepui.cli.com by cli.com (4.1/SMI-4.1) + id AA27213; Thu, 25 May 95 11:18:25 CDT +Received: by tepui.cli.com (4.1) id AA16031; Thu, 25 May 95 11:18:23 CDT +Message-Id: <9505251618.AA16031@tepui.cli.com> +From: friedman@gnu.ai.mit.edu (Noah Friedman) +To: chet@po.cwru.edu +Subject: Bash scripts +Reply-To: friedman@gnu.ai.mit.edu +In-Reply-To: Thu, 25 May 1995 11:19:59 -0400 +References: <9505251519.AA06424.SM@odin.INS.CWRU.Edu> +Date: Thu, 25 May 95 11:18:21 CST + +>Hi. I snagged some of your bash functions from your home directory on +>the FSF machines (naughty, I know), and I was wondering if you'd let +>me distribute them with bash-2.0. Thanks. + +Sure. I think there's a later copy in +~ftp/friedman/shell-inits/init-4.89.tar.gz. There are also some elisp and +es frobs in that file. + +It should serve as a pretty good example of how to get carried away. :-) + diff --git a/examples/scripts.noah/README b/examples/scripts.noah/README new file mode 100644 index 0000000..a33860b --- /dev/null +++ b/examples/scripts.noah/README @@ -0,0 +1,24 @@ +This collection of scripts was originally written for older versions +of bash by Noah Friedman (friedman@gnu.ai.mit.edu). The conversion +to bash v2 syntax was done by Chet Ramey. + +These scripts are as-is; there is no copyright associated with +any of them. They exist simply as examples of bash scripting. + +Here's a description of what's in this directory: + +aref.bash pseudo-arrays and substring indexing examples +bash.sub.bash library functions used by require.bash +bash_version.bash a function to slice up $BASH_VERSION +meta.bash enable and disable eight-bit readline input +mktmp.bash make a temporary file with a unique name +number.bash a fun hack to translate numerals into english +prompt.bash a way to set PS1 to some predefined strings +remap_keys.bash a front end to `bind' to redo readline bindings +require.bash lisp-like require/provide library functions for bash +send_mail.bash replacement smtp client written in bash +shcat.bash bash replacement for `cat' +source.bash replacement for source that uses current directory +string.bash the string(3) functions at the shell level +stty.bash front-end to stty that changes readline bindings too +y_or_n_p.bash prompt for a yes/no/quit answer diff --git a/examples/scripts.noah/aref.bash b/examples/scripts.noah/aref.bash new file mode 100644 index 0000000..9b221b8 --- /dev/null +++ b/examples/scripts.noah/aref.bash @@ -0,0 +1,44 @@ +# aref.bash --- pseudo-array manipulating routines +# Author: Noah Friedman +# Created 1992-07-01 +# Last modified: 1993-02-03 +# Public domain + +# Conversion to bash v2 syntax done by Chet Ramey + +# Commentary: +# Code: + +#:docstring aref: +# Usage: aref NAME INDEX +# +# In array NAME, access element INDEX (0-origin) +#:end docstring: + +###;;;autoload +function aref () +{ + local name="$1" + local index="$2" + + set -- ${!name} + [ $index -ge 1 ] && shift $index + echo $1 +} + +#:docstring string_aref: +# Usage: aref STRING INDEX +# +# Echo the INDEXth character in STRING (0-origin) on stdout. +#:end docstring: + +###;;;autoload +function string_aref () +{ + local stuff=${1:$2} + echo ${stuff:0:1} +} + +provide aref + +# aref.bash ends here diff --git a/examples/scripts.noah/bash.sub.bash b/examples/scripts.noah/bash.sub.bash new file mode 100644 index 0000000..2504459 --- /dev/null +++ b/examples/scripts.noah/bash.sub.bash @@ -0,0 +1,28 @@ +# bash.sub.bash --- stub for standalone shell scripts using bash library +# Author: Noah Friedman +# Created: 1992-07-13 +# Last modified: 1993-09-29 +# Public domain + +#:docstring bash.sub: +# Standard subroutines for bash scripts wishing to use "require" to load +# libraries. +# +# Usage: In each directory where a bash script that uses this script +# exists, place a copy of this script. Then, at the top of such scripts, +# put the command +# +# source ${0%/*}/bash.sub || exit 1 +# +# Then you can use `require' to load packages. +# +#:end docstring: + +default_FPATH="~friedman/etc/init/bash/functions/lib" + +source "${default_FPATH}/feature" +REQUIRE_FAILURE_FATAL=t + +FPATH="${FPATH-${default_FPATH}}" + +# bash.sub.bash ends here diff --git a/examples/scripts.noah/bash_version.bash b/examples/scripts.noah/bash_version.bash new file mode 100644 index 0000000..4ea737b --- /dev/null +++ b/examples/scripts.noah/bash_version.bash @@ -0,0 +1,42 @@ +# bash_version.bash --- get major and minor components of bash version number +# Author: Noah Friedman +# Created: 1993-01-26 +# Last modified: 1993-01-26 +# Public domain + +# Converted to bash v2 syntax by Chet Ramey + +# Commentary: +# Code: + +#:docstring bash_version: +# Usage: bash_version {major|minor} +# +# Echo the major or minor number of this version of bash on stdout, or +# just echo $BASH_VERSION if no argument is given. +#:end docstring: + +###;;;autoload +function bash_version () +{ + local major minor + + case "$1" in + major) echo "${BASH_VERSION/.*/}" ;; + minor) major="${BASH_VERSION/.*/}" + minor="${BASH_VERSION#${major}.}" + echo "${minor%%.*}" ;; + patchlevel) minor="${BASH_VERSION#*.*.}" + echo "${minor%(*}" ;; + version) minor=${BASH_VERSION/#*.*./} + echo ${BASH_VERSION/%.$minor/} ;; + release) echo ${BASH_VERSION%(*} ;; + build) minor="${BASH_VERSION#*.*.*(}" + echo ${minor%)} ;; + *) echo "${BASH_VERSION}" ;; + esac +} + +provide bash_version + +# bash_version.bash ends here diff --git a/examples/scripts.noah/meta.bash b/examples/scripts.noah/meta.bash new file mode 100644 index 0000000..6121726 --- /dev/null +++ b/examples/scripts.noah/meta.bash @@ -0,0 +1,37 @@ +# meta.bash --- meta key frobnications +# Author: Noah Friedman +# Created: 1992-06-28 +# Last modified: 1993-01-26 +# Public domain + +# Commentary: +# Code: + +#:docstring meta: +# Usage: meta [on|off] +# +# An argument of "on" will make bash use the 8th bit of any input from +# a terminal as a "meta" bit, i.e bash will be able to use a real meta +# key. +# +# An argument of "off" causes bash to disregard the 8th bit, which is +# assumed to be used for parity instead. +#:end docstring: + +function meta () +{ + case "$1" in + on) bind 'set input-meta On' + bind 'set output-meta on' + bind 'set convert-meta off' ;; + off) bind 'set input-meta Off' + bind 'set output-meta off' + bind 'set convert-meta on' ;; + *) echo "Usage: meta [on|off]" 1>&2 ; return 1 ;; + esac + return 0 +} + +provide meta + +# meta.bash ends here diff --git a/examples/scripts.noah/mktmp.bash b/examples/scripts.noah/mktmp.bash new file mode 100644 index 0000000..3ea43ad --- /dev/null +++ b/examples/scripts.noah/mktmp.bash @@ -0,0 +1,66 @@ +# mktmp.bash +# Author: Noah Friedman +# Created: 1993-02-03 +# Last modified: 1993-02-03 +# Public domain + +# Conversion to bash v2 syntax done by Chet Ramey + +# Commentary: +# Code: + +#:docstring mktmp: +# Usage: mktmp [template] {createp} +# +# Generate a unique filename from TEMPLATE by appending a random number to +# the end. +# +# If optional 2nd arg CREATEP is non-null, file will be created atomically +# before returning. This is to avoid the race condition that in between +# the time that the temporary name is returned and the caller uses it, +# someone else creates the file. +#:end docstring: + +###;;;autoload +function mktmp () +{ + local template="$1" + local tmpfile="${template}${RANDOM}" + local createp="$2" + local noclobber_status + + case "$-" in + *C*) noclobber_status=set;; + esac + + if [ "${createp:+set}" = "set" ]; then + # Version which creates file atomically through noclobber test. + set -o noclobber + (> "${tmpfile}") 2> /dev/null + while [ $? -ne 0 ] ; do + # Detect whether file really exists or creation lost because of + # some other permissions problem. If the latter, we don't want + # to loop forever. + if [ ! -e "${tmpfile}" ]; then + # Trying to create file again creates stderr message. + echo -n "mktmp: " 1>&2 + > "${tmpfile}" + return 1 + fi + tmpfile="${template}${RANDOM}" + (> "${tmpfile}") 2> /dev/null + done + test "${noclobber_status}" != "set" && set +o noclobber + else + # Doesn't create file, so it introduces race condition for caller. + while [ -e "${tmpfile}" ]; do + tmpfile="${template}${RANDOM}" + done + fi + + echo "${tmpfile}" +} + +provide mktmp + +# mktmp.bash ends here diff --git a/examples/scripts.noah/number.bash b/examples/scripts.noah/number.bash new file mode 100644 index 0000000..23e58b4 --- /dev/null +++ b/examples/scripts.noah/number.bash @@ -0,0 +1,185 @@ +# number.bash +# Author: Noah Friedman +# Created: 1993-02-22 +# Last modified: 1993-04-01 +# Public domain + +# Conversion to bash v2 syntax done by Chet Ramey + +# Commentary: +# Code: + +#:docstring number: +# Usage: number [number] +# +# Converts decimal integers to english notation. Spaces and commas are +# optional. Numbers 67 digits and larger will overflow this script. +# +# E.g: number 99,000,000,000,000,454 +# => ninety-nine quadrillion four hundred fifty-four +# +#:end docstring: + +function number () +{ + local result + local val1 + local val2 + local val3 + local d1 + local d2 + local d3 + + case "$*" in + *[!0-9,.]* ) + echo "number: invalid character in argument." 1>&2 + return 1 + ;; + *.* ) + echo "number: fractions not supported (yet)." 1>&2 + return 1 + ;; + esac + + result='' + + eval set - "`echo ${1+\"$@\"} | sed -n -e ' + s/[, ]//g;s/^00*/0/g;s/\(.\)\(.\)\(.\)$/\"\1 \2 \3\"/; + :l + /[0-9][0-9][0-9]/{ + s/\([^\" ][^\" ]*\)\([^\" ]\)\([^\" ]\)\([^\" ]\)/\1\"\2 \3 \4\"/g; + t l + } + /^[0-9][0-9][0-9]/s/\([^\" ]\)\([^\" ]\)\([^\" ]\)/\"\1 \2 \3\"/; + /^[0-9][0-9]/s/\([^\" ]\)\([^\" ]\)/\"\1 \2\"/; + /^[0-9]/s/^\([^\" ][^\" ]*\)/\"\1\"/g;s/\"\"/\" \"/g;p;'`" + + while test $# -ne 0 ; do + eval `set - $1; + d3='' d2='' d1='' + case $# in + 1 ) d1=$1 ;; + 2 ) d2=$1 d1=$2 ;; + 3 ) d3=$1 d2=$2 d1=$3 ;; + esac + echo "d3=\"${d3}\" d2=\"${d2}\" d1=\"${d1}\""` + + val1='' val2='' val3='' + + case "${d3}" in + '1' ) val3='one' ;; + '2' ) val3='two' ;; + '3' ) val3='three' ;; + '4' ) val3='four' ;; + '5' ) val3='five' ;; + '6' ) val3='six' ;; + '7' ) val3='seven' ;; + '8' ) val3='eight' ;; + '9' ) val3='nine' ;; + esac + + case "${d2}" in + '1' ) val2='teen' ;; + '2' ) val2='twenty' ;; + '3' ) val2='thirty' ;; + '4' ) val2='forty' ;; + '5' ) val2='fifty' ;; + '6' ) val2='sixty' ;; + '7' ) val2='seventy' ;; + '8' ) val2='eighty' ;; + '9' ) val2='ninety' ;; + esac + + case "${val2}" in + 'teen') + val2='' + case "${d1}" in + '0') val1='ten' ;; + '1') val1='eleven' ;; + '2') val1='twelve' ;; + '3') val1='thirteen' ;; + '4') val1='fourteen' ;; + '5') val1='fifteen' ;; + '6') val1='sixteen' ;; + '7') val1='seventeen' ;; + '8') val1='eighteen' ;; + '9') val1='nineteen' ;; + esac + ;; + 0 ) : ;; + * ) + if test ".${val2}" != '.' -a ".${d1}" != '.0' ; then + val2="${val2}-" + fi + case "${d1}" in + '0') val2="${val2} " ;; + '1') val1='one' ;; + '2') val1='two' ;; + '3') val1='three' ;; + '4') val1='four' ;; + '5') val1='five' ;; + '6') val1='six' ;; + '7') val1='seven' ;; + '8') val1='eight' ;; + '9') val1='nine' ;; + esac + ;; + esac + + if test ".${val3}" != '.' ; then + result="${result}${val3} hundred " + fi + + if test ".${val2}" != '.' ; then + result="${result}${val2}" + fi + + if test ".${val1}" != '.' ; then + result="${result}${val1} " + fi + + if test ".${d1}${d2}${d3}" != '.000' ; then + case $# in + 0 | 1 ) ;; + 2 ) result="${result}thousand " ;; + 3 ) result="${result}million " ;; + 4 ) result="${result}billion " ;; + 5 ) result="${result}trillion " ;; + 6 ) result="${result}quadrillion " ;; + 7 ) result="${result}quintillion " ;; + 8 ) result="${result}sextillion " ;; + 9 ) result="${result}septillion " ;; + 10 ) result="${result}octillion " ;; + 11 ) result="${result}nonillion " ;; + 12 ) result="${result}decillion " ;; + 13 ) result="${result}undecillion " ;; + 14 ) result="${result}duodecillion " ;; + 15 ) result="${result}tredecillion " ;; + 16 ) result="${result}quattuordecillion " ;; + 17 ) result="${result}quindecillion " ;; + 18 ) result="${result}sexdecillion " ;; + 19 ) result="${result}septendecillion " ;; + 20 ) result="${result}octodecillion " ;; + 21 ) result="${result}novemdecillion " ;; + 22 ) result="${result}vigintillion " ;; + * ) + echo "Error: number too large (66 digits max)." 1>&2 + return 1 + ;; + esac + fi + + shift + done + + set - ${result} + case "$*" in + '') set - 'zero' ;; + esac + + echo ${1+"$@"} +} + +provide number + +# number.bash ends here diff --git a/examples/scripts.noah/prompt.bash b/examples/scripts.noah/prompt.bash new file mode 100644 index 0000000..3dc25a9 --- /dev/null +++ b/examples/scripts.noah/prompt.bash @@ -0,0 +1,40 @@ +# prompt.bash +# Author: Noah Friedman +# Created: 1992-01-15 +# Public domain + +# $Id: prompt.bash,v 1.2 1994/10/18 16:34:35 friedman Exp $ + +# Commentary: +# Code: + +#:docstring prompt: +# Usage: prompt [chars] +# +# Various preformatted prompt strings selected by argument. For a +# list of available arguments and corresponding formats, do +# `type prompt'. +#:end docstring: + +###;;;autoload +function prompt () +{ + case "$1" in + d) PS1='$(dirs) \$ ' ;; + n) PS1='\$ ' ;; + hsw) PS1='\h[$SHLVL]: \w \$ ' ;; + hw) PS1='\h: \w \$ ' ;; + sh) PS1='[$SHLVL] \h\$ ' ;; + sw) PS1='[$SHLVL] \w \$ ' ;; + uh) PS1='\u@\h\$ ' ;; + uhsHw) PS1='\u@\h[$SHLVL]:\#: \w \$ ' ;; + uhsw) PS1='\u@\h[$SHLVL]: \w \$ ' ;; + uhw) PS1='\u@\h: \w \$ ' ;; + uw) PS1='(\u) \w \$ ' ;; + w) PS1='\w \$ ' ;; + esac +} + +provide prompt + +# prompt.bash ends here diff --git a/examples/scripts.noah/remap_keys.bash b/examples/scripts.noah/remap_keys.bash new file mode 100644 index 0000000..aa7c463 --- /dev/null +++ b/examples/scripts.noah/remap_keys.bash @@ -0,0 +1,71 @@ +# remap_keybindings.bash +# Author: Noah Friedman +# Created: 1992-01-11 +# Last modified: 1993-02-03 +# Public domain + +# Conversion to bash v2 syntax done by Chet Ramey + +# Commentary: +# Code: + +#:docstring remap_keybindings: +# Usage: remap_keybindings old_function new_function +# +# Clear all readline keybindings associated with OLD_FUNCTION (a Readline +# function) rebinding them to NEW_FUNCTION (`self-insert' by default) +# +# This requires bash version 1.10 or newer, since previous versions did not +# implement the `bind' builtin. +#:end docstring: + +###;;;autoload +function remap_keybindings () +{ + local unbind_function="$1" + local bind_function="${2:-'self-insert'}" + local bind_output + local arg + + # If they're the same thing, the work has already been done. :-) + if [ "${unbind_function}" = "${bind_function}" ]; then + return 0 + fi + + while : ; do + bind_output="$(bind -q ${unbind_function} 2> /dev/null)" + + case "${bind_output}" in + "${unbind_function} can be invoked via"* ) ;; + "" ) return 1 ;; # probably bad argument to bind + *) return 0 ;; # unbound + esac + + # Format of bind_output is like: + # 'quoted-insert can be invoked via "\C-q", "\C-v".' + # 'self-insert can be invoked via " ", "!", """, "$", "%", ...' + set -- ${bind_output} + shift 5 + + for arg in "$@" ; do + # strip off trailing `.' or `,' + arg=${arg%.}; + arg=${arg%,}; + + case ${arg} in + ..) + # bind -q didn't provide whole list of key bindings; jump + # to top loop to get more + continue 2 ; + ;; + *) + bind "${arg}: ${bind_function}" + ;; + esac + done + done +} + +provide remap_keybindings + +# remap_keybindings.bash ends here diff --git a/examples/scripts.noah/require.bash b/examples/scripts.noah/require.bash new file mode 100644 index 0000000..f38040a --- /dev/null +++ b/examples/scripts.noah/require.bash @@ -0,0 +1,182 @@ +# require.bash +# Author: Noah Friedman +# Created: 1992-07-08 +# Last modified: 1993-09-29 +# Public domain + +# Commentary: + +# These functions provide an interface based on the lisp implementation for +# loading libraries when they are needed and eliminating redundant loading. +# The basic idea is that each "package" (or set of routines, even if it is +# only one function) registers itself with a symbol that marks a "feature" +# as being "provided". If later you "require" a given feature, you save +# yourself the trouble of explicitly loading it again. +# +# At the bottom of each package, put a "provide foobar", so when another +# package has a "require foobar", it gets loaded and registered as a +# "feature" that won't need to get loaded again. (See warning below for +# reasons why provide should be put at the end.) +# +# The list of provided features are kept in the `FEATURES' variable, which +# is not exported. Care should be taken not to munge this in the shell. +# The search path comes from a colon-separated `FPATH' variable. It has no +# default value and must be set by the user. +# +# Require uses `fpath_search', which works by scanning all of FPATH for a +# file named the same as the required symbol but with a `.bash' appended to +# the name. If that is found, it is loaded. If it is not, FPATH is +# searched again for a file name the same as the feature (i.e. without any +# extension). Fpath_search may be useful for doing library filename +# lookups in other functions (such as a `load' or `autoload' function). +# +# Warning: Because require ultimately uses the builtin `source' command to +# read in files, it has no way of undoing the commands contained in the +# file if there is an error or if no provide statement appeared (this +# differs from the lisp implementation of require, which normally undoes +# most of the forms that were loaded if the require fails). Therefore, to +# minize the number of problems caused by requiring a faulty package (such +# as syntax errors in the source file) it is better to put the provide at +# the end of the file, rather than at the beginning. + +# Code: + +# Exporting this variable would cause considerable lossage, since none of +# the functions are exported (or at least, they're not guaranteed to be) +export -n FEATURES + +#:docstring : +# Null function. Provided only so that one can put page breaks in source +# files without any ill effects. +#:end docstring: +# +# (\\014 == C-l) +eval "function $(echo -e \\014) () { : }" + + +#:docstring featurep: +# Usage: featurep argument +# +# Returns 0 (true) if argument is a provided feature. Returns 1 (false) +# otherwise. +#:end docstring: + +###;;;autoload +function featurep () +{ + local feature="$1" + + case " ${FEATURES} " in + *" ${feature} "* ) return 0 ;; + esac + + return 1 +} + + +#:docstring provide: +# Usage: provide symbol ... +# +# Register a list of symbols as provided features +#:end docstring: + +###;;;autoload +function provide () +{ + local feature + + for feature in "$@" ; do + if ! featurep "${feature}" ; then + FEATURES="${FEATURES} ${feature}" + fi + done + + return 0 +} + + +#:docstring require: +# Usage: require feature {file} +# +# Load FEATURE if it is not already provided. Note that require does not +# call `provide' to register features. The loaded file must do that +# itself. If the package does not explicitly do a `provide' after being +# loaded, require will complain about the feature not being provided on +# stderr. +# +# Optional argument FILE means to try to load FEATURE from FILE. If no +# file argument is given, require searches through FPATH (see fpath_search) +# for the appropriate file. +# +# If the variable REQUIRE_FAILURE_FATAL is set, require will cause the +# current shell invocation to exit, rather than merely return. This may be +# useful for a shell script that vitally depends on a package. +# +#:end docstring: + +###;;;autoload +function require () +{ + local feature="$1" + local path="$2" + local file + + if ! featurep "${feature}" ; then + file=$(fpath_search "${feature}" "${path}") && source "${file}" + + if ! featurep "${feature}" ; then + echo "require: ${feature}: feature was not provided." 1>&2 + if [ "${REQUIRE_FAILURE_FATAL+set}" = "set" ]; then + exit 1 + fi + return 1 + fi + fi + + return 0 +} + +#:docstring fpath_search: +# Usage: fpath_search filename {path ...} +# +# Search $FPATH for `filename' or, if `path' (a list) is specified, search +# those directories instead of $FPATH. First the path is searched for an +# occurrence of `filename.bash, then a second search is made for just +# `filename'. +#:end docstring: + +###;;;autoload +function fpath_search () +{ + local name="$1" + local path="$2" + local suffix=".bash" + local file + + if [ -z "${path}" ]; then path="${FPATH}"; fi + + for file in "${name}${suffix}" "${name}" ; do + set -- $(IFS=':' + set -- ${path} + for p in "$@" ; do + echo -n "${p:-.} " + done) + + while [ $# -ne 0 ]; do + test -f "${1}/${file}" && { file="${1}/${file}"; break 2 } + shift + done + done + + if [ $# -eq 0 ]; then + echo "fpath_search: ${name}: file not found in fpath" 1>&2 + return 1 + fi + + echo "${file}" + return 0 +} + +provide require + +# require.bash ends here diff --git a/examples/scripts.noah/send_mail.bash b/examples/scripts.noah/send_mail.bash new file mode 100644 index 0000000..24a1220 --- /dev/null +++ b/examples/scripts.noah/send_mail.bash @@ -0,0 +1,140 @@ +# send_mail.bash +# Author: Noah Friedman +# Created: 1992-07-02 +# Public domain + +# Commentary: + +# TODO: implement Fcc headers (see emacs manual) + +# Code: + +#:docstring send_mail: +# Usage: send_mail +# +# This function serves as a simple replacement for sendmail as a client +# interface on those systems where it is not available. It does assume +# that one can talk to an SMTP mailer on port 25 either on the local host +# or on the host specified by the MAILHOST environment variable. If you +# have access to sendmail, it's better to use 'sendmail -t' instead of this +# script (which probably isn't as robust). +# +# Message is read from stdin, and headers are parsed to determine +# recipients. +#:end docstring: + +###;;;autoload +function send_mail () +{ + # Need gawk, since several extensions are taken advantage of (like + # IGNORECASE for regexps). + local awk="${GAWK_LOCATION:-gawk}" + local DefaultFrom="${USER:-${LOGNAME}}" + local From + local To + local Cc + local Bcc + local tmpfile="/tmp/send_mail$$" + + while [ -e "${tmpfile}" ]; do + tmpfile="/tmp/send_mail${RANDOM}" + done + + # Lines consisting only of dots need one more dot appended. SMTP + # servers eat one of the dots (and if only 1 dot appears, it signifies + # the end of the message). + sed '/^\.\.*/s/^\(\.\.*\)$/\1./' > "${tmpfile}" + + # Parse mail headers in message to extract recipients list. + # This doesn't affect what the user sees---it's only used to generate + # the rcpt-to lines for SMTP. + eval $(${awk} -f - "${tmpfile}" <<- '__EOF__' + # Try to extract email address from amidst random data + function parse_address (data) + { + # From: "real name" + # From: "" + if (match(data, /^\"[^\"]*\"[ \t]*<.*>/)) { + data_idx = match(data, /^\"[^\"]*\"[ \t]*.*")) + data = substr(data, 1, RSTART - 1); + return data + } + # From: real name + if (match(data, /<.*>/)) { + data_idx = match(data, /")) + data = substr(data, 1, RSTART - 1); + return data + } + # From: foobar@host (real name) + if (match(data, /\(.*\)/)) { + data_idx = match(data, /\(/); + data = substr(data, 1, RSTART - 1); + return data + } + # (hopefully) From: foobar@host + return data + } + + BEGIN { IGNORECASE = 1; } + + # Blank line signifies end of headers, so we can stop looking. + /^$/ { exit(0) } + + /^from:|^to:|^cc:|^bcc:/ { + header_idx = match($0, /^[^:]*:/) + if (header_idx) { + # Capitalize header name + header_firstchar = toupper(substr($0, RSTART, 1)); + header_rest = tolower(substr($0, RSTART + 1, RLENGTH - 2)); + header = header_firstchar header_rest + + $0 = substr($0, RSTART + RLENGTH + 1); + addresses = "" + # parse addresses + while ($0) { + # Strip leading whitespace + if (idx = match($0, /[ \t]*/)) + $0 = substr($0, RSTART + RLENGTH); + + # Find everything up to a nonquoted comma + # FIXME: doesnt handle quoting yet + if (idx = match($0, /,/)) { + data = substr($0, 1, RSTART); + $0 = substr($0, RSTART + 1); + } else { + data = $0 + $0 = "" + } + addresses = addresses " " parse_address(data) + } + + printf("%s='%s'\n", header, addresses); + } + } + __EOF__) + + # Not sure if an address is *required* after the HELO.. every sendmail + # I tried talking to didn't seem to care. Some sendmails don't care + # if there's a HELO at all. + cat <<- __EOF__ | telnet ${MAILHOST:-localhost} 25 > /dev/null 2>&1 + HELO + mail from: ${From:-${DefaultFrom}} + $(for name in ${To} ${Cc} ${Bcc} ; do + echo "rcpt to: ${name}" + done) + data + $(cat "${tmpfile}") + . + quit + __EOF__ + + rm -f "${tmpfile}" +} + +provide send_mail + +# send_mail.bash ends here diff --git a/examples/scripts.noah/shcat.bash b/examples/scripts.noah/shcat.bash new file mode 100644 index 0000000..5d9e96d --- /dev/null +++ b/examples/scripts.noah/shcat.bash @@ -0,0 +1,49 @@ +# shcat.bash +# Author: Noah Friedman +# Created: 1992-07-17 +# Last modified: 1993-09-29 +# Public domain + +# Conversion to bash v2 syntax done by Chet Ramey + +# Commentary: +# Code: + +#:docstring shcat: +# Usage: shcat {file1} {file2} {...} +# +# Like `cat', only this is all inline bash. +#:end docstring: + +###;;;autoload +function shcat () +{ + local IFS="" + local line + local file + local exitstat=0 + + if [ $# -eq 0 ]; then + while read -r line; do + echo "${line}" + done + return 0 + else + for file in "$@" ; do + if [ -r "${file}" ]; then + while read -r line; do + echo "${line}" + done < "${file}" + else + # This will cause the error to be printed on stderr + < "${file}" + exitstat=1 + fi + done + return ${exitstat} + fi +} + +provide shcat + +# shcat.bash ends here diff --git a/examples/scripts.noah/source.bash b/examples/scripts.noah/source.bash new file mode 100644 index 0000000..2b36489 --- /dev/null +++ b/examples/scripts.noah/source.bash @@ -0,0 +1,63 @@ +# source.bash +# Author: Noah Friedman +# Created: 1992-05-17 +# Last modified: 1993-09-29 +# Public domain + +# Commentary: +# Code: + +#:docstring source: +# Usage: source file ... +# +# Source forces file arguments to be considered in the current directory +# only, unless there is an absolute path starting with `/'. I think it's +# bad that the builtin "source" searches PATH, because PATH normally +# contains directories with binary files that aren't useful for bash to +# read and most people don't put "." first in their path. +# +# This "source" is capable of reading more than one file at a time. Return +# value is number of failed source attempts. +#:end docstring: + +# This function is not hygienic, but there's not much we can do about +# variable name conflicts here. + +###;;;autoload +function source () +{ + local -i _source_failure_count=0 + local _source_file + + for _source_file ; do + # Check first part of each filename. If it's not `/', `./', or + # `../' then prepend "./" to the path to force the builtin `source' + # not to go searching through PATH to find the file. + case "${_source_file}" in + /*|./*|../* ) ;; + * ) _source_file="./${_source_file}" ;; + esac + + builtin source "${_source_file}" || + _source_failure_count="_source_failure_count + 1" + + done + + return ${_source_failure_count} +} + +#:docstring .: +# See "source" +#:end docstring: + +# So that `.' will call function definition of `source' instead of builtin + +###;;;autoload +function . () +{ + source "$@" +} + +provide source + +# source.bash ends here diff --git a/examples/scripts.noah/string.bash b/examples/scripts.noah/string.bash new file mode 100644 index 0000000..38c0af8 --- /dev/null +++ b/examples/scripts.noah/string.bash @@ -0,0 +1,226 @@ +# string.bash --- bash emulation of string(3) library routines +# Author: Noah Friedman +# Created: 1992-07-01 +# Last modified: 1993-09-29 +# Public domain + +# Conversion to bash v2 syntax done by Chet Ramey + +# Commentary: +# Code: + +#:docstring strcat: +# Usage: strcat s1 s2 +# +# Strcat appends the value of variable s2 to variable s1. +# +# Example: +# a="foo" +# b="bar" +# strcat a b +# echo $a +# => foobar +# +#:end docstring: + +###;;;autoload +function strcat () +{ + local s1_val s2_val + + s1_val=${!1} # indirect variable expansion + s2_val=${!2} + eval "$1"=\'"${s1_val}${s2_val}"\' +} + +#:docstring strncat: +# Usage: strncat s1 s2 $n +# +# Line strcat, but strncat appends a maximum of n characters from the value +# of variable s2. It copies fewer if the value of variabl s2 is shorter +# than n characters. Echoes result on stdout. +# +# Example: +# a=foo +# b=barbaz +# strncat a b 3 +# echo $a +# => foobar +# +#:end docstring: + +###;;;autoload +function strncat () +{ + local s1="$1" + local s2="$2" + local -i n="$3" + local s1_val s2_val + + s1_val=${!s1} # indirect variable expansion + s2_val=${!s2} + + if [ ${#s2_val} -gt ${n} ]; then + s2_val=${s2_val:0:$n} # substring extraction + fi + + eval "$s1"=\'"${s1_val}${s2_val}"\' +} + +#:docstring strcmp: +# Usage: strcmp $s1 $s2 +# +# Strcmp compares its arguments and returns an integer less than, equal to, +# or greater than zero, depending on whether string s1 is lexicographically +# less than, equal to, or greater than string s2. +#:end docstring: + +###;;;autoload +function strcmp () +{ + [ "$1" = "$2" ] && return 0 + + [ "${1}" '<' "${2}" ] > /dev/null && return -1 + + return 1 +} + +#:docstring strncmp: +# Usage: strncmp $s1 $s2 $n +# +# Like strcmp, but makes the comparison by examining a maximum of n +# characters (n less than or equal to zero yields equality). +#:end docstring: + +###;;;autoload +function strncmp () +{ + if [ -z "${3}" -o "${3}" -le "0" ]; then + return 0 + fi + + if [ ${3} -ge ${#1} -a ${3} -ge ${#2} ]; then + strcmp "$1" "$2" + return $? + else + s1=${1:0:$3} + s2=${2:0:$3} + strcmp $s1 $s2 + return $? + fi +} + +#:docstring strlen: +# Usage: strlen s +# +# Strlen returns the number of characters in string literal s. +#:end docstring: + +###;;;autoload +function strlen () +{ + eval echo "\${#${1}}" +} + +#:docstring strspn: +# Usage: strspn $s1 $s2 +# +# Strspn returns the length of the maximum initial segment of string s1, +# which consists entirely of characters from string s2. +#:end docstring: + +###;;;autoload +function strspn () +{ + # Unsetting IFS allows whitespace to be handled as normal chars. + local IFS= + local result="${1%%[!${2}]*}" + + echo ${#result} +} + +#:docstring strcspn: +# Usage: strcspn $s1 $s2 +# +# Strcspn returns the length of the maximum initial segment of string s1, +# which consists entirely of characters not from string s2. +#:end docstring: + +###;;;autoload +function strcspn () +{ + # Unsetting IFS allows whitspace to be handled as normal chars. + local IFS= + local result="${1%%[${2}]*}" + + echo ${#result} +} + +#:docstring strstr: +# Usage: strstr s1 s2 +# +# Strstr echoes a substring starting at the first occurrence of string s2 in +# string s1, or nothing if s2 does not occur in the string. If s2 points to +# a string of zero length, strstr echoes s1. +#:end docstring: + +###;;;autoload +function strstr () +{ + # if s2 points to a string of zero length, strstr echoes s1 + [ ${#2} -eq 0 ] && { echo "$1" ; return 0; } + + # strstr echoes nothing if s2 does not occur in s1 + case "$1" in + *$2*) ;; + *) return 1;; + esac + + # use the pattern matching code to strip off the match and everything + # following it + first=${1/$2*/} + + # then strip off the first unmatched portion of the string + echo "${1##$first}" +} + +#:docstring strtok: +# Usage: strtok s1 s2 +# +# Strtok considers the string s1 to consist of a sequence of zero or more +# text tokens separated by spans of one or more characters from the +# separator string s2. The first call (with a non-empty string s1 +# specified) echoes a string consisting of the first token on stdout. The +# function keeps track of its position in the string s1 between separate +# calls, so that subsequent calls made with the first argument an empty +# string will work through the string immediately following that token. In +# this way subsequent calls will work through the string s1 until no tokens +# remain. The separator string s2 may be different from call to call. +# When no token remains in s1, an empty value is echoed on stdout. +#:end docstring: + +###;;;autoload +function strtok () +{ + : +} + +#:docstring strtrunc: +# Usage: strtrunc $n $s1 {$s2} {$...} +# +# Used by many functions like strncmp to truncate arguments for comparison. +# Echoes the first n characters of each string s1 s2 ... on stdout. +#:end docstring: + +###;;;autoload +function strtrunc () +{ + n=$1 ; shift + for z; do + echo "${z:0:$n}" + done +} + +provide string + +# string.bash ends here diff --git a/examples/scripts.noah/stty.bash b/examples/scripts.noah/stty.bash new file mode 100644 index 0000000..611d970 --- /dev/null +++ b/examples/scripts.noah/stty.bash @@ -0,0 +1,64 @@ +# stty.bash +# Author: Noah Friedman +# Created: 1992-01-11 +# Last modified: 1993-09-29 +# Public domain + +# Conversion to bash v2 syntax done by Chet Ramey + +# Commentary: +# Code: + +require remap_keybindings + +#:docstring stty: +# Track changes to certain keybindings with stty, and make those changes +# reflect in bash's readline bindings as well. +# +# This requires bash version 1.10 or newer, since previous versions did not +# implement the `bind' builtin. +#:end docstring: + +###;;;autoload +function stty () +{ + local erase="backward-delete-char" + local kill="unix-line-discard" + local werase="backward-kill-word" + local lnext="quoted-insert" + local readline_function="" + local key="" + local stty_command="" + + while [ $# -gt 0 ]; do + case "$1" in + erase | kill | werase | lnext ) + key=$(echo "${2}" | cat -v | sed 's/\^/\\C-/') + readline_function=$(eval echo \$${1}) + + # Get rid of any current bindings; the whole point of this + # function is to make the distinction between readline + # bindings and particular cbreak characters transparent; old + # readline keybindings shouldn't hang around. + # could use bind -r here instead of binding to self-insert + remap_keybindings "${readline_function}" "self-insert" + + # Bind new key to appropriate readline function + bind "\"${key}\": ${readline_function}" + + stty_command="${stty_command} ${1} ${2}" + shift 2 + ;; + *) + stty_command="${stty_command} ${1}" + shift + ;; + esac + done + + command stty ${stty_command} +} + +provide stty + +# stty.bash ends here diff --git a/examples/scripts.noah/y_or_n_p.bash b/examples/scripts.noah/y_or_n_p.bash new file mode 100644 index 0000000..2674a29 --- /dev/null +++ b/examples/scripts.noah/y_or_n_p.bash @@ -0,0 +1,78 @@ +# y_or_n_p.bash +# Author: Noah Friedman +# Created: 1992-06-18 +# Last modified: 1993-03-01 +# Public domain + +# Conversion to bash v2 syntax done by Chet Ramey + +# Commentary: +# Code: + +#:docstring y_or_n_p: +# Usage: y_or_n_p QUERY +# +# Print QUERY on stderr, then read stdin for a y-or-n response. Actually, +# user may type anything they like, but first character must be a `y', `n', +# `q', or `!', otherwise the question is repeated until such an answer is +# obtained. +# +# If user typed `y', y_or_n_p returns 0. +# +# If user typed `n', y_or_n_p returns 1. +# +# If user typed `!', y_or_n_p returns 2. This is an indication to the +# caller that no more queries should be made. Assume `y' for all the rest. +# +# If user typed `q', y_or_n_p returns 3. This is an indication to the +# caller that no more queries should be made. Assume `n' for all the rest. +# +#:end docstring: + +###;;;autoload +function y_or_n_p () +{ + local ans + + [ ! -t 0 ] && return 1 + + while read -p "$*" -e ans ; do + case "${ans}" in + y* | Y* ) return 0 ;; + n* | N* ) return 1 ;; + \! ) return 2 ;; + q* | Q* ) return 3 ;; + *) echo "Please answer one of \`y', \`n', \`q', or \`"\!"'" 1>&2 ;; + esac + done +} + +#:docstring yes_or_no_p: +# Usage: yes_or_no_p QUERY +# +# Like y_or_n_p, but require a full `yes', `no', `yes!', or `quit' response. +#:end docstring: + +###;;;autoload +function yes_or_no_p () +{ + local ans + + [ ! -t 0 ] && return 3 + + while read -p "$*" -e ans; do + ans="$(echo ${ans} | tr '[A-Z]' '[a-z]')" + + case "${ans}" in + yes ) return 0 ;; + no ) return 1 ;; + yes\! ) return 2 ;; + quit ) return 3 ;; + *) echo "Please answer \`yes', \`no', \`yes"\!"', or \`quit'" 1>&2 ;; + esac + done +} + +provide y_or_n_p + +# y_or_n_p.bash ends here diff --git a/examples/scripts.v2/PERMISSION b/examples/scripts.v2/PERMISSION new file mode 100644 index 0000000..f65e848 --- /dev/null +++ b/examples/scripts.v2/PERMISSION @@ -0,0 +1,59 @@ +From spcecdt@armory.com Wed May 10 10:21:11 1995 +Flags: 10 +Return-Path: spcecdt@armory.com +Received: from po.cwru.edu (root@po.CWRU.Edu [129.22.4.2]) by odin.INS.CWRU.Edu with ESMTP (8.6.10+cwru/CWRU-2.1-ins) + id KAA22876; Wed, 10 May 1995 10:21:10 -0400 (from spcecdt@armory.com for ) +Received: from deepthought.armory.com (mmdf@deepthought.armory.com [192.122.209.42]) by po.cwru.edu with SMTP (8.6.10+cwru/CWRU-2.3) + id BAA16354; Wed, 10 May 1995 01:33:22 -0400 (from spcecdt@armory.com for ) +From: John DuBois +Date: Tue, 9 May 1995 22:33:12 -0700 +In-Reply-To: Chet Ramey + "ksh scripts" (May 9, 1:36pm) +X-Www: http://www.armory.com/~spcecdt/ +X-Mailer: Mail User's Shell (7.2.5 10/14/92) +To: chet@po.cwru.edu +Subject: Re: ksh scripts +Message-ID: <9505092233.aa13001@deepthought.armory.com> + + Sure. The canonical versions are available on ftp.armory.com; you might +want to pick up the latest versions before modifying them. + + John + +On May 9, 1:36pm, Chet Ramey wrote: +} Subject: ksh scripts +} From odin.ins.cwru.edu!chet Tue May 9 10:39:51 1995 +} Received: from odin.INS.CWRU.Edu by deepthought.armory.com id aa22336; +} 9 May 95 10:39 PDT +} Received: (chet@localhost) by odin.INS.CWRU.Edu (8.6.10+cwru/CWRU-2.1-ins) +} id NAA20487; Tue, 9 May 1995 13:39:24 -0400 (from chet) +} Date: Tue, 9 May 1995 13:36:54 -0400 +} From: Chet Ramey +} To: john@armory.com +} Subject: ksh scripts +} Cc: chet@odin.ins.cwru.edu +} Reply-To: chet@po.cwru.edu +} Message-ID: <9505091736.AA20411.SM@odin.INS.CWRU.Edu> +} Read-Receipt-To: chet@po.CWRU.Edu +} MIME-Version: 1.0 +} Content-Type: text/plain; charset=us-ascii +} Status: OR +} +} Hi. I'm the maintainer of bash (the GNU `Bourne Again shell') for +} the FSF. +} +} I picked up a tar file of ksh scripts you wrote from an anon FTP site +} a while back. I'd like your permission to include modified versions +} of some of them in the next major bash distribution (with proper credit +} given, of course). Is it OK if I do that? +} +} Chet Ramey +} +} -- +} ``The lyf so short, the craft so long to lerne.'' - Chaucer +} +} Chet Ramey, Case Western Reserve University Internet: chet@po.CWRU.Edu +}-- End of excerpt from Chet Ramey + + + diff --git a/examples/scripts.v2/README b/examples/scripts.v2/README new file mode 100644 index 0000000..b3d0559 --- /dev/null +++ b/examples/scripts.v2/README @@ -0,0 +1,33 @@ +This collection of scripts was originally written for ksh-88 by +John DuBois . The conversion to bash v2 +syntax was done by Chet Ramey. + +These scripts are as-is; there is no copyright associated with +any of them. They exist simply as examples of bash scripting. + +Here's a description of what's in this directory: + +arc2tarz Convert an "arc" archive to a compressed tar archive. +corename Tell what produced a core file. +fman Fast man replacement. +frcp Copy files using ftp but with rcp-type command line syntax. +lowercase Change filenames to lower case. +ncp A nicer front end for cp (has -i, etc.). +newext Change the extension of a group of files. +nmv A nicer front end for mv (has -i, etc.). +pages Print specified pages from files. +pf A pager front end that handles compressed files. +rename Change the names of files that match a pattern. +repeat Execute a command multiple times. +untar Unarchive a (possibly compressed) tarfile into a directory. +uudec Carefully uudecode multiple files. +uuenc uuencode multiple files. +vtree Print a visual display of a directory tree. +where Show where commands that match a pattern are. + +The following scripts were written or converted by Chet Ramey: + +bashrand Random number generator with upper and lower bounds and optional seed +cdhist cd replacement with a directory stack added +pmtop Poor man's `top' for SunOS 4.x and BSD/OS +shprof Line profiler for bash scripts diff --git a/examples/scripts.v2/arc2tarz b/examples/scripts.v2/arc2tarz new file mode 100644 index 0000000..285bede --- /dev/null +++ b/examples/scripts.v2/arc2tarz @@ -0,0 +1,85 @@ +#! /bin/bash +# +# original from: +# arc2tarz: convert arced file to tarred, compressed form. +# @(#) arc2tarz.ksh 1.0 92/02/16 +# 91/03/28 john h. dubois iii (john@armory.com) +# 92/02/16 added -h option for help +# +# conversion to bash v2 syntax by Chet Ramey + +unset ENV +Usage="Usage: $0 arcfile [-hcg] [ tarzfile ]" + +phelp() +{ +echo "$Usage +arcfile is the name of an arc file to convert to tarred, compressed form. +The file must have a .arc extension, but only the base name needs to be +given. If no output file name is given, it will be created in the current +directory with the name being the arcfile basename followed by .tar.EXT. +If the -c option is given, compress will be used, and EXT will be Z. +The default (also available with -g) is to use gzip, in which case EXT +is gz. If the basename is too long the extension may be truncated. All +uppercase letters in the names of files in the archive are moved to lowercase." +} + +compress=gzip +ext=gz + +while getopts "hcg" opt; do + case "$opt" in + h) phelp; exit 0;; + c) compress=compress; ext=Z;; + g) compress=gzip ; ext=gz ;; + *) echo "$Usage" 1>&2 ; exit 2;; + esac +done + +shift $((OPTIND - 1)) + +if [ $# = 0 ]; then + phelp + exit 0 +fi + +[ -z "$TMP" ] && tmpdir=/tmp/arc2tarz.$$ || tmpdir=$TMP/arc2tarz.$$ + +case "$1" in +*.arc) arcfile=$1 ;; +*) arcfile=$1.arc ;; +esac + +if [ ! -f $arcfile ] || [ ! -r $arcfile ]; then + echo "Could not open arc file \"$arcfile\"." + exit 1 +fi + +case "$arcfile" in +/*) ;; +*) arcfile=$PWD/$arcfile ;; +esac + +basename=${arcfile%.arc} +basename=${basename##*/} +[ $# -lt 2 ] && tarzname=$PWD/$basename.tar.$ext || tarzname=$2 + +trap 'rm -rf $tmpdir $tarzname' 1 2 3 6 15 + +mkdir $tmpdir +cd $tmpdir +echo "unarcing files..." +arc -ie $arcfile + +# lowercase +for f in *; do + new=$(echo $f | tr A-Z a-z) + if [ "$f" != "$new" ]; then + mv $f $new + fi +done + +echo "tarring/compressing files..." +tar cf - * | $compress > $tarzname +cd - +rm -rf $tmpdir diff --git a/examples/scripts.v2/bashrand b/examples/scripts.v2/bashrand new file mode 100644 index 0000000..54260c0 --- /dev/null +++ b/examples/scripts.v2/bashrand @@ -0,0 +1,76 @@ +#! /bin/bash +# bashrand - generate a random number in a specified range with an +# optionally specified ``seed'' value. +# +# Original Author: Peter Turnbull, May 1993 + +usage() +{ + echo "$PROG: usage: $PROG [-s seed] lower-limit upper-limit" >&2 +} + +PROG=${0##*/} + +SEED=$$ # Initialize random-number seed value with PID + +while getopts s: opt +do + case "$opt" in + s) SEED=$OPTARG ;; + *) usage ; exit 2 ;; + esac +done + +shift $((OPTIND - 1)) + +# Process command-line arguments: +case $# in + 2) Lower=$1; Upper=$2 ;; + *) usage ; exit 2 ;; +esac + +# Check that specified values are integers: +expr "$Lower" + 0 >/dev/null 2>&1 || { + echo "$PROG: lower ($Lower) not an integer" >&2 + exit 1 +} + +expr "$Upper" + 0 >/dev/null 2>&1 || { + echo "$PROG: upper ($Upper) not an integer" >&2 + exit 1 +} + +expr "$SEED" + 0 >/dev/null 2>&1 || { + echo "$PROG: seed ($SEED) not an integer" >&2 + exit 1 +} + +# Check that values are in the correct range: +(( $Lower < 0 )) || [ `expr "$Lower" : '.*'` -gt 5 ] && { + echo "$PROG: Lower limit ($Lower) out of range" >&2 + exit 1 +} + +(( $Upper > 32767 )) || [ `expr "$Upper" : '.*'` -gt 5 ] && { + echo "$PROG: Upper limit ($Upper) out of range" >&2; + exit 1 +} + +(( $SEED < 0 )) || (( $SEED > 32767 )) || [ `expr "$SEED" : '.*'` -gt 5 ] && { + echo "$PROG: Seed value ($SEED) out of range (0 to 32767)" >&2 + exit 1 +} + +(( $Upper <= $Lower )) && { + echo "$PROG: upper ($Upper) <= lower value ($Lower)" >&2 + exit 1 +} + +# Seed the random-number generator: +RANDOM=$SEED + +# Compute value, scaled within range: +let rand="$RANDOM % ($Upper - $Lower + 1) + $Lower" + +# Report result: +echo $rand diff --git a/examples/scripts.v2/cdhist.bash b/examples/scripts.v2/cdhist.bash new file mode 100644 index 0000000..39bec88 --- /dev/null +++ b/examples/scripts.v2/cdhist.bash @@ -0,0 +1,176 @@ +#! /bin/bash +# +# cdhist - cd replacement with a directory stack like pushd/popd +# +# usage: cd [-l] [-n] [-] [dir] +# +# options: +# -l print the cd directory stack, one entry per line +# - equivalent to $OLDPWD +# -n cd to nth directory in cd directory stack +# -s cd to first directory in stack matching (substring) `s' +# +# arguments: +# dir cd to dir and push dir onto the cd directory stack +# +# If the new directory is a directory in the stack and the options selected +# it (-n, -s), the new working directory is printed +# +# If the variable CDHISTFILE is set, the cd directory stack is loaded from +# and written to $CDHISTFILE every time `cd' is executed. +# +# Note: I got this off the net somewhere; I don't know the original author +# +# Chet Ramey +# chet@po.cwru.edu + +_cd_print() +{ + echo -e "$@" +} + +cd() +{ + typeset -i cdlen i + typeset t + + if [ $# -eq 0 ] + then + set -- $HOME + fi + + if [ "$CDHISTFILE" -a -r "$CDHISTFILE" ] # if directory history exists + then + typeset CDHIST + i=-1 + while read -r t # read directory history file + do + CDHIST[i=i+1]=$t + done <$CDHISTFILE + fi + + if [ "${CDHIST[0]}" != "$PWD" -a "$PWD" != "" ] + then + _cdins # insert $PWD into cd history + fi + + cdlen=${#CDHIST[*]} # number of elements in history + + case "$@" in + -) # cd to new dir + if [ "$OLDPWD" = "" ] && ((cdlen>1)) + then + '_cdprint' ${CDHIST[1]} + builtin cd ${CDHIST[1]} + pwd + else + builtin cd "$@" + # pwd + fi + ;; + -l) # _cdprint directory list + ((i=cdlen)) + while (((i=i-1)>=0)) + do + num=$i + '_cdprint' "$num ${CDHIST[i]}" + done + return + ;; + -[0-9]|-[0-9][0-9]) # cd to dir in list + if (((i=${1#-})=cdlen)) + then + builtin cd $@ + # pwd + fi + ;; + *) # cd to new dir + builtin cd $@ + # pwd + ;; + esac + + _cdins # insert $PWD into cd history + + if [ "$CDHISTFILE" ] + then + cdlen=${#CDHIST[*]} # number of elements in history + + i=0 + while ((i$CDHISTFILE + fi +} + +_cdins() # insert $PWD into cd history +{ # meant to be called only by cd + typeset -i i + + i=0 + + while (( i < ${#CDHIST[*]} )) # see if dir is already in list + do + if [ "${CDHIST[$i]}" = "$PWD" ] + then + break + fi + ((i=i+1)) + done + + if (( i>22 )) # limit max size of list + then + i=22 + fi + + while (((i=i-1)>=0)) # bump old dirs in list + do + CDHIST[i+1]=${CDHIST[i]} + done + + CDHIST[0]=$PWD # insert new directory in list +} + +# examples +shopt -s expand_aliases + +# go to known place before doing anything +cd / + +echo CDHIST: "${CDHIST[@]}" +for dir in /tmp /bin - -2 -l +do + cd $dir + echo CDHIST: "${CDHIST[@]}" + echo PWD: $PWD + +done + +exit 0 diff --git a/examples/scripts.v2/corename b/examples/scripts.v2/corename new file mode 100644 index 0000000..2b51e5d --- /dev/null +++ b/examples/scripts.v2/corename @@ -0,0 +1,43 @@ +#! /bin/bash +# +# original from: +# @(#) corename.ksh 1.0 93/04/01 +# 92/11/11 john h. dubois iii (john@armory.com) +# 92/02/16 Added help option. +# 92/02/22 Added cd to origdir to fix prob w/multiple relative paths. +# 93/04/01 Added check for whether file exists. +# +# conversion to bash v2 syntax done by Chet Ramey + +# inspired by belal's equivalent utility + +if [ "$1" = -h ]; then + echo \ +"$0: print the names of executables that dumped core. +Usage: $0 [corename ...] +If no corename is given, \"core\" is assumed." + exit 0 +fi + +[ $# = 0 ] && set core +origdir=$PWD +for i; do + cd $origdir + file=${i##*/} + dir=${i%$file} + [ -z "$dir" ] && dir=$origdir/ + if [ ! -f $dir$file ]; then + echo "$dir$file: No such file." + continue + fi + if [ ! -r $dir$file ]; then + echo "$dir$file: Cannot open." + continue + fi + cd $dir + + # the adb output syntax is highly variable. this works on SunOS 4.x + set -- $(adb $file < /dev/null 2>&1 | sed 1q) + name=${7#??} + echo "$i: ${name%??}" +done diff --git a/examples/scripts.v2/fman b/examples/scripts.v2/fman new file mode 100644 index 0000000..c9cf301 --- /dev/null +++ b/examples/scripts.v2/fman @@ -0,0 +1,281 @@ +#! /bin/bash +# +# original from: +# fman: new man program +# @(#) fman.ksh 1.5 94/04/16 +# 91/07/03 john h. dubois iii (john@armory.com) +# 91/07/11 made it unpack man pages if neccessary +# 91/07/16 fixed test for whether man file pattern was expanded +# 92/01/21 made it read /etc/default/man to get section order, +# and only display the first section found. +# 92/02/06 changed name to fman +# 92/02/07 fixed bug in notfound +# 92/02/13 incorporated changes from DOS version +# 92/03/11 changed to use MANPATH from environment if set, +# and search all directories given in MANPATH +# 92/03/15 exec pager or man w/o forking +# 92/05/31 try using index if one exists +# 92/10/01 Added "See also " +# 92/10/18 If PAGER is less, search for name of man page to make it easier +# to find information in man pages for multiple items +# 92/11/11 Make it work for compressed files not listed in index; +# deal with man pages listed in index that don't exist. +# 93/03/30 Fixed bug in MANPATH processing +# 93/06/17 Include paths in "See also:" message if they would be needed +# to get to a man page. Allow MANPATH spec on command line. +# 93/07/09 Added -h and -e options. +# 94/04/16 Added x option. +# +# conversion to bash v2 syntax done by Chet Ramey + +istrue() +{ + test 0 -ne "$1" +} + +isfalse() +{ + test 0 -eq "$1" +} + +# Finds all sections that man page $1 is in and puts them in the the +# global array Sections[]. +# The filename of each page is put in FileNames[] with the same index. +# Global vars used: +# patharr[] MANPATH directories. + +FindSectionsInIndex () +{ + typeset index indexes section mpath page=$1 + typeset -i i=0 NIndex=0 + + for mpath in "${patharr[@]}"; do + if [ -r $mpath/index ]; then + indexes="$indexes $mpath/index" + let NIndex+=1 + fi + done + [ -z "$indexes" ] && return + # Make egrep give filename + [ NIndex -lt 2 ] && indexes="$indexes /dev/null" + # set positional parameters to + # indexfile:searchname pagename section ... + # e.g. + # /usr/man/index:FP_OFF Routines DOS + set -- `egrep "^$page[ ]" $indexes` + while [ $# -gt 2 ]; do + FileNames[i]=${1%%index*}cat$3/$2.$3 + Sections[i]=$3 + shift 3 + let i+=1 + done +} + +# Finds all sections that man page $1 is in by searching each man directory +# in the order given in patharr[], +# and puts them in the the global array Sections[]. +# The filename of each page is put in FileNames[] with the same index. +# Global vars used: +# patharr[] MANPATH directories. +FindSectionsInDirs () +{ + local page=$1 mpath AllPaths Path + typeset -i i + + for mpath in "${patharr[@]}"; do + AllPaths="$AllPaths $mpath/cat[0-9]*/$page.* $mpath/man[0-9]*/$page.*" + done + + i=0 + for Path in $AllPaths; do + istrue $debug && echo Path = $Path + case "$Path" in + *\*) ;; + *) + # Remove compressed-file suffix to make FileNames be the same + # as it is when built by FindSectionsInIndex() + FileNames[i]=${Path%.[zZ]} + Path=${Path%/*} + Sections[i]=${Path##*/*.} + let i+=1 ;; + esac + done +} + +# FindSection: display man page. +# Uses ordarr[] (built from $ORDER) to display the version of the man +# page that occurs first in $ORDER. +# Sections[] gives the sections that a man page was found in. +# If the global variable "exist" is set to 1, nothing is displayed; +# the function instead returns zero if a page is found, nonzero if not. +# The filename of each page is in FileNames[] with the same index. +# Global vars used: +# Sections[], FileNames[], ordarr[] +FindSection () +{ + typeset -i NumPages i foundsec + local section OtherSec filename NPAGER=$PAGER POpt page=$1 Pat + local PageFile + + NumPages=${#Sections[*]} # Number of versions of man page found. + isfalse $NumPages && return 1 + case "$PAGER" in + *less) Popt="-p$page" ;; + esac + + # For each section in ORDER, determine if any man page was found in + # that section + for section in "${ordarr[@]}"; do + i=0 + foundsec=0 + while [ $i -lt $NumPages ]; do + if [ "${Sections[i]}" = $section ]; then + # Found a man page from this section of ORDER + filename=${FileNames[i]} + if [ -z "$PageFile" ]; then + PageFile=$filename + else + if istrue $foundsec; then + OtherSec="$OtherSec$page(${filename%/*/*} $section) " + else + OtherSec="$OtherSec$page($section) " + fi + fi + foundsec=1 + istrue $exist && return + fi + let i+=1 + done + done + # No pages with the specified section found. + [ -z "$PageFile" ] && return 1 + # Return if all we want to know is whether the man page exists. + [ "$exist" = 1 ] && return 0 + if [ -z "$OtherSec" ]; then + NPAGER="exec $PAGER" + fi + if [ -r $PageFile ]; then + $NPAGER $POpt $PageFile + elif [ -r $PageFile.z ]; then + pcat $PageFile.z | $NPAGER $POpt + elif [ -r $PageFile.Z ]; then + zcat $PageFile.Z | $NPAGER $POpt + elif [ -f $PageFile.gz ]; then + gzip -dc $PageFile.gz | $NPAGER $POpt + else + echo "$PageFile: cannot open." 1>&2 + OtherSec= + unset Sections[i] + let i+=1 + continue + fi + echo "See also $OtherSec" + exit 0 +} + +phelp() +{ +echo "$name: print man pages. +$name locates and prints the specified manual pages from the online UNIX +documentation. +$Usage +Options: +-e: Determine whether the specified man page exists. Nothing is printed; + $0 exits with a zero status if the page exists and a nonzero status if + it does not. +-h: Print this help." +} + +# main program + +typeset -i exist=0 debug=0 + +name=${0##*/} +Usage="Usage: $name [-eh] [[manpath] section] command-name" + +while getopts :hex opt; do + case $opt in + h) phelp; exit 0;; + e) exist=1 ;; + x) debug=1 ;; + +?) echo "$name: options should not be preceded by a '+'." 1>&2; exit 2;; + ?) + echo "$name: $OPTARG: bad option. Use -h for help." 1>&2 ; exit 2 ;; + esac +done + +# remove args that were options +shift $((OPTIND-1)) + +if [ $# -lt 1 ]; then + echo -e "$Usage\nUse -h for help." 1>&2 + exit +fi + +P=$PAGER +O=1:n:l:6:8:2:3:4:5:7:p:o +T=$TERM +M=${MANPATH:-/usr/local/man:/usr/man} +[ -f /etc/default/man ] && . /etc/default/man +[ -n "$P" ] && PAGER=$P +[ -n "$O" ] && ORDER=$O +[ -n "$T" ] && TERM=$T +[ -n "$M" ] && MANPATH=$M + +case $# in +0) echo "No man page specified." ; exit 1;; +1) page=$1;; +2) ORDER=$(echo $1 | tr a-z A-Z) ; page=$2;; +3) MANPATH=$1 + [ -n "$2" ] && ORDER=$(echo $2 | tr a-z A-Z) + page=$3;; +*) echo "Too many arguments."; exit 1;; +esac + +aargs=("$@") +[ ! -t 0 ] && PAGER=cat + +OIFS=$IFS +IFS=: +patharr=($MANPATH) +i=0 +for d in $MANPATH; do + for sec in $ORDER; do + ordarr[i]=$d/cat${sec} + let i+=1 + ordarr[i]=$d/man${sec} + let i+=1 + done +done +IFS=$OIFS + +istrue $debug && echo patharr = "${patharr[@]}" + +# if less or more is being used, remove multiple blank lines +export LESS="-s $LESS" +export MORE="-s $MORE" + +# Try using index +FindSectionsInIndex "$page" +# Exit 0 if a page was found and we're just testing for existence. +FindSection "$page" && exit 0 + +# Try searching directories +unset Sections[*] +FindSectionsInDirs "$page" +FindSection "$page" && exit 0 + +istrue $exist && exit 1 + +# Try using man +# If using more or less, make man run faster by letting more or less compress +# multiple blank lines instead of rmb +#case "$PAGER" in +#*more|*less) manopt=-b;; +#esac + +#cmd=(man $manopt -p$PAGER "${aargs[@]}") +export PAGER +cmd=(man $manopt "${aargs[@]}") +istrue $debug && echo "$name: running ${cmd[*]}" 1>&2 +exec "${cmd[@]}" diff --git a/examples/scripts.v2/frcp b/examples/scripts.v2/frcp new file mode 100755 index 0000000..08028e1 --- /dev/null +++ b/examples/scripts.v2/frcp @@ -0,0 +1,288 @@ +#! /bin/bash +# +# original from: +# +# @(#) frcp.ksh 2.2 93/11/14 +# 92/06/29 john h. dubois iii (john@armory.com) +# 92/10/14 Cleaned up, improved, added -d and -r options +# 92/11/11 Made work with a dest of '.' +# 93/07/09 Added -l and -n options, & login as anonymous if no .netrc entry +# 93/11/14 Use either passwd or password in .netrc, since ftp does. +# +# conversion to bash v2 syntax by Chet Ramey +# +# frcp: ftp front end with rcp-like syntax. +# Note: requires any machine names given to be listed with +# user and password in .netrc. If not, anonymous FTP is +# done. +# +# full path to ftp binary +if [ -x /usr/bin/ftp ]; then + FTP=/usr/bin/ftp; +elif [ -x /usr/ucb/ftp ]; then + FTP=/usr/ucb/ftp +else + FTP=ftp +fi + +istrue() +{ + test 0 -ne "$1" +} +isfalse() +{ + test 0 -eq "$1" +} + +# For each filename given, put the filename in filename[n] +# and the machine it is on in machine[n]. +function SplitNames { + typeset file + typeset -i i=1 + + unset filename[*] machine[*] + for file; do + case "$file" in + *:*) machine[i]=${file%%:*} ;; + *) machine[i]=$LocalMach ;; + esac + filename[i]=${file#*:} + let i+=1 + done +} + +function verboseprint { + echo "$@" + echo "$@" 1>&2 +} + +function MakeDir { + OFS=$IFS + local IFS=/ dir component + + case "$1" in + /*) ;; + *) dir=. + esac + set -- $1 + IFS=$OFS + for component; do + dir=$dir/$component + if [ ! -d "$dir" ]; then + if mkdir "$dir"; then :; else + echo "Could not make directory $dir." >&2 + return 1 + fi + fi + done + return 0 +} + +lastisdot () +{ + case "$1" in + */.|*/..) return 0;; + *) return 1;; + esac +} + +# CopyFiles: issue ftp(TC) commands to copy files. +# Usage: CopyFiles [sourcemachine:]sourcepath ... [destmachine:]destpath +# Global vars: +# Uses LocalMach (should be name of local machine) +# Sets global arrs machine[]/filename[] +function CopyFiles { + unset machine[*] filename[*] + + SplitNames "$@" # split names into filename[1..n] and machine[1..n] + + local DestMach=${machine[$#]} # Machine to copy files to + local DestPath=${filename[$#]} # Destination file/dir + + unset machine[$#] filename[$#] + + [ -z "$DestPath" ] && DestPath=. # dest was given as machine: + + # Try to determine if destination should be a directory + # so that it can be forced to be a directory. + + case "$DestPath" in + */) ;; # don't add / if trailing / already present + *) if [ $# -gt 2 ] || # if more than two args given, last must be a dir + # If dest in on local machine, check whether it is a directory + [ $DestMach = $LocalMach -a -d $DestPath ] || + # If dest ends with . or .., it is a directory + lastisdot "$DestPath" + then + DestPath=$DestPath/ + fi ;; + esac + + # If one of the above tests made us think dest is a directory, + # but it isn't, complain + case "$DestPath" in + */) if [ "$DestMach" = "$LocalMach" ] && [ ! -d "$DestPath" ]; then + echo "Destination is not a directory." 1>&2 + exit 1 + fi ;; + esac + + DoCopy "$DestMach" "$DestPath" +} + +# Usage: OpenMachine machine-name +# Emits login sequence or doesn't, depending on .netrc file and global +# variables anon and noanon +OpenMachine () +{ + local machine=$1 netrc=$HOME/.netrc user= password= + + if isfalse $anon && [ -r $netrc ]; then + set -- $(gawk ' + /machine (.* )?'"$machine"'($| )/,/^ *$/ { + Fields[$1] = $2 + if ("passwd" in Fields) + Fields["password"] = Fields["passwd"] + if ("login" in Fields && "password" in Fields) { + print Fields["login"] " " Fields["password"] + exit + } + } + ' $netrc ) + user=$1 + password=$2 + fi + if [ -z "$password" ]; then + if istrue $noanon; then + echo "No .netrc entry for machine $machine" 1>&2 + exit 1 + fi + user=anonymous + password=$USER@$LocalMach + fi + verboseprint open $machine + echo user $user "*******" 1>&2 + echo user $user $password +} + +# Usage: DoCopy destination-machine destination-path +# Copies the files in global arrs machine[]/filename[] to the given dest +# Global vars: +# Uses machine[], filename[], LocalMach, check +DoCopy () +{ + local DestMach=$1 + local DestPath=$2 + local OpenMach # Machine that connection is currently open to + local OWD=$PWD SourceMach SourceFile + local FileName + typeset -i i=1 + + while [ $i -le ${#machine[*]} ]; do + istrue $check && verboseprint "runique" + + SourceMach=${machine[i]} + SourceFile=${filename[i]} + + DestFile=$DestPath + # if DestPath is a dir, + # add source filename to it without source path + case "$DestFile" in + */) DestFile=$DestFile${SourceFile##*/} ;; + esac + + if [ $SourceMach = $LocalMach ]; then + if [ $DestMach != "$OpenMach" ]; then + OpenMachine $DestMach + OpenMach=$DestMach + fi + verboseprint put $SourceFile $DestFile + elif [ $DestMach = $LocalMach ]; then + if istrue $check && [ -f "$DestFile" ]; then + echo "$DestFile already exists." 1>&2 + continue + fi + # If destination is on local machine, + # the dest will be a full dir/filename + if istrue $createdirs; then + MakeDir "${DestFile%/*}" || continue + fi + if [ $SourceMach != "$OpenMach" ]; then + OpenMachine $SourceMach + OpenMach=$SourceMach + fi + # If source filename has wildcards ([, ], *, ?) do an mget + case "$SourceFile" in + \[*\]|*\**|*\?*) + verboseprint lcd "$DestFile" + verboseprint mget "$SourceFile" + verboseprint lcd $OWD ;; + *) verboseprint get "$SourceFile" "$DestFile" ;; + esac + else + echo "Neither source machine \"$SourceMach\" "\ +"nor destination machine \"$DestMach\" is local." 1>&2 + fi + let i+=1 + done +} + +# Start of main program +name=${0##*/} + +if [ "$1" = -h ]; then + echo \ +"$name: do ftp transfers using rcp-style parameters. +Usage: $name or $name [ ...] +At least one of and must be the local system. +A remote filename is given as machinename:filename +If remote filenames contain wildcards, they will be globbed on the remote +machine. Make sure they are quoted when $name is invoked. +If the invoking user's .netrc file (see ftp(TC)) contains an entry for the +remote system with a login and password supplied, $name will log in using +the given login and password. If not, $name will login in as user +anonymous and with the user@localsystem as the password. +Options: +-c: check: do not overwrite files. +-d: create directories as needed. +-f: force: overwrite files (default). +-h: print this help. +-l: fail if there is no entry with login and password for the remote system, + instead of logging in as anonymous. +-n: log in as anonymous even if there is an entry for the remote system in + the user's .netrc file. +-r: read source/dest filename pairs from the standard input, + one pair per line, and copy files accordingly." + exit 0 +fi + +typeset -i check=0 createdirs=0 readinput=0 anon=0 noanon=0 + +while getopts :cdflnr Option +do + case "$Option" in + c) check=1;; + d) createdirs=1;; + f) check=0;; + l) noanon=1;; + n) anon=1;; + r) readinput=1;; + \?) echo "$OPTARG: invalid option."; exit 1;; + esac +done + +shift $((OPTIND-1)) + +LocalMach=`hostname` + +if istrue $readinput; then + while read line; do + CopyFiles $line + done | $FTP -nv +else + if [ $# -lt 2 ]; then + echo "$name: Not enough arguments. Use -h for help." 1>&2 + exit + fi + CopyFiles "$@" | $FTP -nv +fi diff --git a/examples/scripts.v2/lowercase b/examples/scripts.v2/lowercase new file mode 100644 index 0000000..fd2ec5d --- /dev/null +++ b/examples/scripts.v2/lowercase @@ -0,0 +1,44 @@ +#! /bin/bash +# +# original from +# @(#) lowercase.ksh 1.0 92/10/08 +# 92/10/08 john h. dubois iii (john@armory.com) +# +# conversion to bash v2 syntax done by Chet Ramey + +Usage="Usage: $name file ..." +phelp() +{ +echo "$name: change filenames to lower case. +$Usage +Each file is moved to a name with the same directory component, if any, +and with a filename component that is the same as the original but with +any upper case letters changed to lower case." +} + +name=${0##*/} + +while getopts "h" opt; do + case "$opt" in + h) phelp; exit 0;; + *) echo "$Usage" 1>&2; exit 2;; + esac +done + +shift $((OPTIND - 1)) + +for file; do + filename=${file##*/} + case "$file" in + */*) dirname=${file%/*} ;; + *) dirname=. ;; + esac + nf=$(echo $filename | tr A-Z a-z) + newname="${dirname}/${nf}" + if [ "$nf" != "$filename" ]; then + mv "$file" "$newname" + echo "$0: $file -> $newname" + else + echo "$0: $file not changed." + fi +done diff --git a/examples/scripts.v2/ncp b/examples/scripts.v2/ncp new file mode 100644 index 0000000..c91ba64 --- /dev/null +++ b/examples/scripts.v2/ncp @@ -0,0 +1,187 @@ +#! /bin/bash +# +# original from: +# @(#) ncp.ksh,nmv.ksh 1.1 94/07/23 +# 92/01/18 john h. dubois iii (john@armory.com) +# 92/01/31 added check for no args left after shifts +# 92/02/17 added help +# 92/02/25 remove path component from filename before tacking it onto dest. +# 92/03/15 exec mv or cp +# 93/07/13 Added -i +# 93/09/29 Made abort if file exists optional. +# 93/11/19 Exit before invoking mv if no files to move +# 94/01/03 Added o option +# 94/04/13 Added x option. +# Fixed appending of source filename, broken by earlier change. +# 94/07/23 Append only the filename part of the source path. +# +# conversion to bash v2 syntax done by Chet Ramey + +false() +{ + return 1 +} + +true() +{ + return 0 +} + +phelp() +{ +echo "$name: do a $cmd with extra checking and options. +$Usage +$name is used as a front end for $cmd to get the [icfo] options, and so +that a trailing / will force the last component of the path to be +interpreted as a directory, so that $name foo bar/ will fail if bar is +not an existing directory, instead of changing the name of foo to bar. +Effectively, $name foo bar/ is short for $name foo bar/foo +Options: +-h prints this help. +-c checks first for the existence of each file, and fails if it exists. +-i is like -c except that if the file exists and stdin and stdout are a + tty, a query is printed and a reply is read; a file is overwritten only + if the reply begins with 'y'. +-f unsets -c and -i (in case $cmd is aliased to $name). +-o (overwrite only) checks that the named file(s) exist and fails for any + that do not. It is the complement of the -c option. +Whichever of [cifo] comes later on the command line determines the behaviour. +Any of these options must come before any standard $cmd options." +} + +# interactive: Attempt to overwrite file should result in interactive +# query rather than automatic failure. +# noover: Do not overwrite files (if interactive is true, query, else fail) +# overwrite: Only overwriting is allowed, not creation of new files. +# debug: Print debugging info. +typeset interactive=false noover=false overwrite=false debug=false +name=${0##*/} + +case "$name" in +ncp|nmv) cmd=/bin/${name#?} ;; +*) echo "$name: Must be invoked as ncp or nmv." 1>&2 ; exit 2;; +esac + +Usage="Usage: $name [-cfhio] $cmd-cmd-line" + +while getopts :cfhiox opt; do + case $opt in + h) phelp; exit 0;; + x) debug=true ;; + c) noover=true ;; + i) noover=true ; interactive=true ;; + f) noover=false ; interactive=false ;; + o) overwrite=true ; noover=false ; interactive=false;; + +?) echo "$name: options should not be preceded by a '+'." 1>&2; exit 2;; + ?) echo "$name: $OPTARG: bad option. Use -h for help." 1>&2 ; exit 2;; + esac +done + +# remove args that were options +shift $((OPTIND - 1)) + +if [ $# -lt 2 ]; then + echo -e "$Usage\nUse -h for help." + exit +fi + +Check() +{ + if [ ! -f "$1" ] && $overwrite; then + echo "$name: $1: File does not exist." 1>&2 + return 1 + elif [ -f "$1" ] && $noover; then + if [ $interactive = false ] || [ ! -t 0 ] || [ ! -t 1 ]; then + echo "$name: $1: File exists." 1>&2 + return 1 + else + while :; do + echo -n \ +"$name: $1: File exists. Overwrite? (y)es/(n)o/(a)bort/(Y)es for all: " 1>&2 + read reply + case "$reply" in + y*) + echo "$name: Overwriting $1." + return 0 + ;; + Y*) + echo "$name: Overwriting $1." + interactive=false + noover=false + return 0 + ;; + [nN]*) + echo "$name: Skipping $2." + return 1 + ;; + [aA]*) + echo "$name: Aborting." + exit 1 + ;; + *) + echo "$name: Invalid response." 1>&2 + ;; + esac + done + fi + else + return 0 + fi +} + +# i is the index of the filename being examined +# lastarg is the index of the last filename before the dest directory name +typeset -i i=0 lastarg=$(($#-1)) + +# Sets argv[0..$#-1] +argv=("$@") +$debug && echo argv = "${argv[@]}" 1>&2 +dest=${argv[lastarg]} + +if $debug; then + echo \ +"interactive=$interactive noover=$noover overwrite=$overwrite debug=$debug +lastarg=$lastarg dest=$dest name=$name cmd=$cmd +files=$*" 1>&2 +fi + +if $noover || $overwrite; then + $debug && echo "checking for existance of directories..." 1>&2 + # If the destination is not intended to be a directory... + if [ $# -eq 2 ] && [ ! -d "$dest" ]; then + Check "$dest" "$1" || exit 0 # No files to copy + else + while [ $i -lt $lastarg ]; do + Check "$dest/${argv[i]##*/}" "${argv[i]}" || unset argv[i] + let i+=1 + done + fi +fi + +[ ${#argv[@]} -lt 2 ] && exit 0 + +# If only 2 args are given, mv/cp will not insist that the destination +# be a directory, which we want if the destination ends in "/" or if +# the original number of args was >2. +# $# is still the original number of args. +# Tack the file name onto the destination to force this behaviour. + +lastisslash() +{ + case "$1" in + */) return 0;; + *) return 1;; + esac +} + +if [ ${#argv[@]} = 2 ] && { lastisslash "$2" || [ $# -gt 2 ]; }; then + $debug && echo "Appending filename." 1>&2 + # Don't know which element of argv[] holds the source filename, + # since may have started with more than 1 source file & had some unset. + # So, compact args to make it easy to find the set one. + argv=("${argv[@]}") + argv[1]="${argv[1]}/${argv[0]##*/}" +fi + +$debug && echo "Executing command: $cmd ${argv[@]}" 1>&2 +exec $cmd "${argv[@]}" diff --git a/examples/scripts.v2/newext b/examples/scripts.v2/newext new file mode 100644 index 0000000..37645bd --- /dev/null +++ b/examples/scripts.v2/newext @@ -0,0 +1,64 @@ +#! /bin/bash +# +# original from: +# newext: change filename extension +# @(#) newext.sh 1.1 93/04/13 +# 90/06/06 john h. dubois iii (john@armory.com) +# 90/11/14 changed ksh-specific code to hybrid: if running under Bourne, +# uses expr instead of ksh builtin ops. Removed SYSV specific code. +# 91/08/06 added -t option +# 92/11/06 made earlier code actually work! +# 93/04/13 If no filenames given, act on files in current dir +# +# conversion to bash v2 syntax by Chet Ramey + +usage="Usage: newext [-th] [filename ...]" + +phelp() +{ +echo "$usage +Rename all given files that end in oldext with newext replacing oldext. +If no filenames are given, all files in the current directory that end +in oldext are acted on (no filename is equivalent to '*'). +Options: +-h: Print this help. +-t: Test: No action is taken except to print the mv commands that would +be executed if -t was not given." +} + +while getopts "th" opt; do + case "$opt" in + t) echo=echo;; + h) phelp; exit 0;; + *) echo "$usage" 1>&2; exit 2;; + esac +done + +shift $((OPTIND - 1)) + +oldext=$1 +newext=$2 + +case $# in +[01]) echo -e "$usage\nUse -h for help." 1>&2; exit 2;; +2) shift ; shift; set -- *;; +*) shift ; shift;; +esac + +found= + +for file +do + case "$file" in + *$oldext) + newname="${file%$oldext}$newext" + $echo mv "$file" "$newname" + found=true;; + esac +done + +if [ -z "$found" ]; then + echo "No files ending in \"$oldext\"." + exit 1 +fi +exit 0 diff --git a/examples/scripts.v2/nmv b/examples/scripts.v2/nmv new file mode 100644 index 0000000..c91ba64 --- /dev/null +++ b/examples/scripts.v2/nmv @@ -0,0 +1,187 @@ +#! /bin/bash +# +# original from: +# @(#) ncp.ksh,nmv.ksh 1.1 94/07/23 +# 92/01/18 john h. dubois iii (john@armory.com) +# 92/01/31 added check for no args left after shifts +# 92/02/17 added help +# 92/02/25 remove path component from filename before tacking it onto dest. +# 92/03/15 exec mv or cp +# 93/07/13 Added -i +# 93/09/29 Made abort if file exists optional. +# 93/11/19 Exit before invoking mv if no files to move +# 94/01/03 Added o option +# 94/04/13 Added x option. +# Fixed appending of source filename, broken by earlier change. +# 94/07/23 Append only the filename part of the source path. +# +# conversion to bash v2 syntax done by Chet Ramey + +false() +{ + return 1 +} + +true() +{ + return 0 +} + +phelp() +{ +echo "$name: do a $cmd with extra checking and options. +$Usage +$name is used as a front end for $cmd to get the [icfo] options, and so +that a trailing / will force the last component of the path to be +interpreted as a directory, so that $name foo bar/ will fail if bar is +not an existing directory, instead of changing the name of foo to bar. +Effectively, $name foo bar/ is short for $name foo bar/foo +Options: +-h prints this help. +-c checks first for the existence of each file, and fails if it exists. +-i is like -c except that if the file exists and stdin and stdout are a + tty, a query is printed and a reply is read; a file is overwritten only + if the reply begins with 'y'. +-f unsets -c and -i (in case $cmd is aliased to $name). +-o (overwrite only) checks that the named file(s) exist and fails for any + that do not. It is the complement of the -c option. +Whichever of [cifo] comes later on the command line determines the behaviour. +Any of these options must come before any standard $cmd options." +} + +# interactive: Attempt to overwrite file should result in interactive +# query rather than automatic failure. +# noover: Do not overwrite files (if interactive is true, query, else fail) +# overwrite: Only overwriting is allowed, not creation of new files. +# debug: Print debugging info. +typeset interactive=false noover=false overwrite=false debug=false +name=${0##*/} + +case "$name" in +ncp|nmv) cmd=/bin/${name#?} ;; +*) echo "$name: Must be invoked as ncp or nmv." 1>&2 ; exit 2;; +esac + +Usage="Usage: $name [-cfhio] $cmd-cmd-line" + +while getopts :cfhiox opt; do + case $opt in + h) phelp; exit 0;; + x) debug=true ;; + c) noover=true ;; + i) noover=true ; interactive=true ;; + f) noover=false ; interactive=false ;; + o) overwrite=true ; noover=false ; interactive=false;; + +?) echo "$name: options should not be preceded by a '+'." 1>&2; exit 2;; + ?) echo "$name: $OPTARG: bad option. Use -h for help." 1>&2 ; exit 2;; + esac +done + +# remove args that were options +shift $((OPTIND - 1)) + +if [ $# -lt 2 ]; then + echo -e "$Usage\nUse -h for help." + exit +fi + +Check() +{ + if [ ! -f "$1" ] && $overwrite; then + echo "$name: $1: File does not exist." 1>&2 + return 1 + elif [ -f "$1" ] && $noover; then + if [ $interactive = false ] || [ ! -t 0 ] || [ ! -t 1 ]; then + echo "$name: $1: File exists." 1>&2 + return 1 + else + while :; do + echo -n \ +"$name: $1: File exists. Overwrite? (y)es/(n)o/(a)bort/(Y)es for all: " 1>&2 + read reply + case "$reply" in + y*) + echo "$name: Overwriting $1." + return 0 + ;; + Y*) + echo "$name: Overwriting $1." + interactive=false + noover=false + return 0 + ;; + [nN]*) + echo "$name: Skipping $2." + return 1 + ;; + [aA]*) + echo "$name: Aborting." + exit 1 + ;; + *) + echo "$name: Invalid response." 1>&2 + ;; + esac + done + fi + else + return 0 + fi +} + +# i is the index of the filename being examined +# lastarg is the index of the last filename before the dest directory name +typeset -i i=0 lastarg=$(($#-1)) + +# Sets argv[0..$#-1] +argv=("$@") +$debug && echo argv = "${argv[@]}" 1>&2 +dest=${argv[lastarg]} + +if $debug; then + echo \ +"interactive=$interactive noover=$noover overwrite=$overwrite debug=$debug +lastarg=$lastarg dest=$dest name=$name cmd=$cmd +files=$*" 1>&2 +fi + +if $noover || $overwrite; then + $debug && echo "checking for existance of directories..." 1>&2 + # If the destination is not intended to be a directory... + if [ $# -eq 2 ] && [ ! -d "$dest" ]; then + Check "$dest" "$1" || exit 0 # No files to copy + else + while [ $i -lt $lastarg ]; do + Check "$dest/${argv[i]##*/}" "${argv[i]}" || unset argv[i] + let i+=1 + done + fi +fi + +[ ${#argv[@]} -lt 2 ] && exit 0 + +# If only 2 args are given, mv/cp will not insist that the destination +# be a directory, which we want if the destination ends in "/" or if +# the original number of args was >2. +# $# is still the original number of args. +# Tack the file name onto the destination to force this behaviour. + +lastisslash() +{ + case "$1" in + */) return 0;; + *) return 1;; + esac +} + +if [ ${#argv[@]} = 2 ] && { lastisslash "$2" || [ $# -gt 2 ]; }; then + $debug && echo "Appending filename." 1>&2 + # Don't know which element of argv[] holds the source filename, + # since may have started with more than 1 source file & had some unset. + # So, compact args to make it easy to find the set one. + argv=("${argv[@]}") + argv[1]="${argv[1]}/${argv[0]##*/}" +fi + +$debug && echo "Executing command: $cmd ${argv[@]}" 1>&2 +exec $cmd "${argv[@]}" diff --git a/examples/scripts.v2/pages b/examples/scripts.v2/pages new file mode 100644 index 0000000..66ebc5f --- /dev/null +++ b/examples/scripts.v2/pages @@ -0,0 +1,187 @@ +#! /bin/bash +# +# original from: +# @(#) pages.sh 1.0 92/09/26 +# 92/09/05 John H. DuBois III (jhdiii@armory.com) +# 92/09/26 Added help +# +# conversion to bash v2 syntax by Chet Ramey + +Usage="$0 [-h] [-n lines/page] page-ranges [file ...]" + +usage() +{ + echo "$Usage" 1>&2 +} + +phelp() +{ +echo "$0: print selected pages. +Usage: $Usage + +If no file names are given, the standard input is read. + +The input is grouped into pages and a selected subset of them is printed. +Formfeeds are acted on correctly. + +If the output device does automatic line wrap, lines that longer than +the width of the output device will result in incorrect output. +The first non-option argument is a list of pages to print. + +Pages are given as a list of ranges separated by commas. +A range is either one number, two numbers separted by a dash, +or one number followed by a dash. A range consisting of one +number followed by a dash extends to the end of the document. + +Options: +-n sets the number of lines per page to n. The default is 66." +} + +while getopts "n:h" opt; do + case "$opt" in + n) LinesPerPage=$OPTARG;; + h) phelp; exit 0;; + *) usage; exit 2;; + esac +done + +shift $(($OPTIND - 1)) + +if [ $# -eq 0 ]; then + echo $0: no page ranges given. 1>&2 + usage + exit 1 +fi + +PageList=$1 +shift + +gawk " +BEGIN { + PageList = \"$PageList\"; LinesPerPage = \"$LinesPerPage\""' + if (LinesPerPage == "") + LinesPerPage = 66 + else + if (LinesPerPage !~ "[1-9][0-9]*") + ErrExit("Bad value for lines per page: " LinesPerPage) + LinesPerPage += 0 + NumRanges = split(PageList,Ranges,",") + for (i = 1; i <= NumRanges; i++) { + if ((StartRange = EndRange = Ranges[i]) !~ "^[0-9]+(-([0-9]+)?)?$") + ErrExit("Bad range \"" StartRange "\"") + sub("-.*","",StartRange) + sub(".*-","",EndRange) + if (EndRange == "") + EndRange = 2 ^ 30 + # Force StartRange and EndRange to be numeric values + if ((StartRange += 0) == 0 || (EndRange += 0) == 0) + ErrExit("Invalid page number \"0\" in range " Ranges[i]) + if (StartRange > EndRange) + ErrExit("Start page comes after end page in range " Ranges[i]) + TmpRangeStarts[i] = StartRange + TmpRangeEnds[i] = EndRange + } + + # Sort ranges + qsort(TmpRangeStarts,k) + RangeEnds[0] = 0 + for (i = 1; i <= NumRanges; i++) { + RangeEnds[i] = TmpRangeEnds[k[i]] + if ((RangeStarts[i] = TmpRangeStarts[k[i]]) <= RangeEnds[i - 1]) + ErrExit("Overlapping ranges: " Ranges[k[i]] "," Ranges[k[i - 1]]) + } + + RangeNum = LineNum = PageNum = 1 + InRange = In(PageNum,RangeStarts[RangeNum],RangeEnds[RangeNum]) + FS = "\014" +} + +{ + if (LineNum > LinesPerPage) + NewPage() + if (InRange) + printf "%s",$1 + # Deal with formfeeds + for (i = 2; i <= NF; i++) { + if (InRange) + printf "\014" + NewPage() + if (InRange) + printf "%s",$i + } + if (InRange) + print "" + LineNum++ +} + +function NewPage() { + PageNum++ + LineNum = 1 + # At the start of each page, check whether we are in a print range + WereInRange = InRange + InRange = In(PageNum,RangeStarts[RangeNum],RangeEnds[RangeNum]) + # If last page was in range and we no longer are, move to next range + if (WereInRange && !InRange && ++RangeNum > NumRanges) + exit +} + +function In(a,Min,Max) { + return (Min <= a && a <= Max) +} + +function ErrExit(S) { + print S > "/dev/stderr" + Err = 1 + exit 1 +} + +# Arr is an array of values with arbitrary indices. +# Array k is returned with numeric indices 1..n. +# The values in k are the indices of array arr, +# ordered so that if array arr is stepped through +# in the order arr[k[1]] .. arr[k[n]], it will be stepped +# through in order of the values of its elements. +# The return value is the number of elements in the array (n). +function qsort(arr,k, ArrInd,end) { + end = 0 + for (ArrInd in arr) + k[++end] = ArrInd; + qsortseg(arr,k,1,end); + return end +} + +function qsortseg(arr,k,start,end, left,right,sepval,tmp,tmpe,tmps) { + # handle two-element case explicitely for a tiny speedup + if ((end - start) == 1) { + if (arr[tmps = k[start]] > arr[tmpe = k[end]]) { + k[start] = tmpe + k[end] = tmps + } + return + } + left = start; + right = end; + sepval = arr[k[int((left + right) / 2)]] + # Make every element <= sepval be to the left of every element > sepval + while (left < right) { + while (arr[k[left]] < sepval) + left++ + while (arr[k[right]] > sepval) + right-- + if (left < right) { + tmp = k[left] + k[left++] = k[right] + k[right--] = tmp + } + } + if (left == right) + if (arr[k[left]] < sepval) + left++ + else + right-- + if (start < right) + qsortseg(arr,k,start,right) + if (left < end) + qsortseg(arr,k,left,end) +} +' "$@" diff --git a/examples/scripts.v2/pf b/examples/scripts.v2/pf new file mode 100644 index 0000000..ab6cd2c --- /dev/null +++ b/examples/scripts.v2/pf @@ -0,0 +1,127 @@ +#! /bin/bash +# +# original from: +# +# @(#) p.ksh 1.1 93/11/09 +# p: page compressed & plain files in the order given +# 92/01/23 john h. dubois iii (john@armory.com) +# 92/02/14 changed incorrect zpack to pcat +# 92/02/16 added help +# 92/10/11 search for file.Z and file.z if file not found +# 92/10/18 pass options to pager +# 93/11/09 Understand gzipped files too +# Wait after printing message about unreadable files +# Make less prompt include name of file being uncompressed +# +# conversion to bash v2 by Chet Ramey; renamed to pf +# +DefPager=/local/bin/less + +istrue() +{ + test 0 -ne "$1" +} + +warn() +{ + echo "$@" 1>&2 +} + +if [ "$1" = -h ]; then + echo \ +"$0: page a file. +Usage: $0 [pager-option ...] [filename ...] +Files are paged by the program specified in the user's PAGER +environment variable, or by $DefPager if PAGER is not set. +If no filename is given, text to page is read from the standard input. +If filenames are given, they are either paged directly, or unpacked/ +uncompressed and then paged. Files are assumed to be in packed, compressed, +or gzipped format if the filename ends in .Z, .z, or .gz respectively. +If a filename that does not end in .Z, .z, or .gz is not found, it is +searched for with one of those extensions attached. +Each group of plain files is paged by a single instance of the pager. +Each packed or compressed file is paged by a separate instance of the +pager. +Initial arguments beginning with + or - are taken to be pager options and +are passed to each instance of the pager. +If a pager option takes a value it should be given with the option as a +single argument (with no space between the option and the value)." + exit 0 +fi + +# Get pager options +while [ $# -gt 0 ]; do + case "$1" in + -*|+*) Opts="$Opts $1" ; shift;; + *) break;; + esac +done + +[ -z "$PAGER" ] && PAGER=$DefPager + +# Read from stdin +[ $# = 0 ] && exec $PAGER $Opts + +typeset -i filenum=0 badfile=0 + +for file; do + if [ ! -r "$file" ]; then + case "$file" in + *.[Zz]|*.gz) + # Check if user specified a compressed file without giving its extension + for ext in Z z gz; do + if [ -r "$file.$ext" ]; then + file="$file.$ext" + break + fi + done;; + esac + fi + if [ ! -r "$file" ]; then + warn "$file: cannot read." + badfile=1 + else + files[filenum]=$file + let filenum+=1 + fi +done + +if istrue $badfile && [ $filenum -gt 0 ]; then + echo -n "Press return to continue..." 1>&2 + read +fi + +unset plain + +for file in "${files[@]}"; do + case "$file" in + *.[zZ]|*.gz) + set -- Z zcat z pcat gz gzcat + # Find correct uncompression program + while [ $# -gt 0 ]; do + case "$file" in + *.$1) + # Page any uncompressed files so that they will be read + # in the correct order + [ ${#plain[@]} -gt 0 ] && $PAGER $Opts "${plain[@]}" + unset plain[*] + # If page is less, set the prompt to include the name of + # the file being uncompressed. Escape the . in the extension + # because less treats is specially in prompts (other dots + # in filenames will still be mucked with). + case "$PAGER" in + *less) Prompt="-P[${file%.$1}\\.$1] (%pb\\%)" ;; + *) unset Prompt ;; + esac + $2 "$file" | $PAGER "$Prompt" $Opts + break + esac + shift 2 + done + ;; + *) plain[${#plain[@]}]=$file;; + esac +done + +# Page any uncompressed files that haven't been paged yet +[ ${#plain[@]} -gt 0 ] && exec $PAGER $Opts "${plain[@]}" diff --git a/examples/scripts.v2/pmtop b/examples/scripts.v2/pmtop new file mode 100644 index 0000000..9344d90 --- /dev/null +++ b/examples/scripts.v2/pmtop @@ -0,0 +1,25 @@ +#! /bin/bash +# +# pmtop - poor man's `top' for SunOS 4.x +# + +CLEAR=clear # could also be 'tput clear' +HEADER="USER PID %CPU %MEM SZ RSS TT STAT START TIME COMMAND" + +if [ -n "$LINES" ]; then + SS=$(( $LINES - 2 )) +else + SS=20 +fi + +while : +do + $CLEAR + echo "$HEADER" + ps -aux | sort -nr +2 | sed ${SS}q + sleep 5 +done + +exit 0 + + diff --git a/examples/scripts.v2/rename b/examples/scripts.v2/rename new file mode 100644 index 0000000..0c9bf1f --- /dev/null +++ b/examples/scripts.v2/rename @@ -0,0 +1,122 @@ +#! /bin/bash +# +# original from: +# @(#) rename.ksh 1.1 94/05/10 +# 90/06/01 John DuBois (spcecdt@armory.com) +# 91/02/25 Improved help info +# 92/06/07 remove quotes from around shell pattern as required by new ksh +# 94/05/10 Exit if no globbing chars given. +# +# conversion to bash v2 syntax by Chet Ramey + +phelp() +{ +echo "$usage +All files that match oldpattern will be renamed with the +filename components that match the constant parts of oldpattern +changed to the corresponding constant parts of newpattern. +The components of the filename that match variable parts of +oldpattern will be preserved. Variable parts in oldpattern +must occur in the same order in newpattern. Variables parts +can be '?' and '*'. +Example: +rename \"/tmp/foo*.ba.?\" \"/tmp/new*x?\" +All files in /tmp that match foo*.ba.? will have the \"foo\" part +replaced by \"new\" and the \".ba.\" part replaced by \"x\"." +} + +usage="usage: $name [-htv] oldpattern newpattern" +name=${0##/} + +while getopts "htv" opt; do + case "$opt" in + t) tell=true;; + v) verbose=true;; + h) phelp; exit 0;; + *) echo "$name: $usage" 1>&2; exit 2;; + esac +done +shift $((OPTIND - 1)) + +if [ $# -lt 2 ]; then + phelp + exit 2 +fi + +oldpat=$1 +newpat=$2 + +set $1 +if [ ! -a "$1" ]; then + echo "$name: no files match $oldpat." + exit 1 +fi + +typeset -i i=1 j + +# Example oldpat: foo*.a +# Example newpat: bar*.b + +# Examples given for first iteration (in the example, the only interation) +while :; do + case "$oldpat" in + *[\*\?]*) ;; + *) break;; + esac + + # Get leftmost globbing pattern in oldpat + pat=${oldpat#*[\*\?]} # pat=.a + pat=${oldpat%%"$pat"} # pat=foo* + pat=${pat##*[!\?\*]} # pat=* + # Find parts before & after pattern + oldpre[i]=${oldpat%%"$pat"*} # oldpre[1]=foo + oldsuf[i]=${oldpat#*"$pat"} # oldsuf[1]=.a + newpre[i]=${newpat%%"$pat"*} # newpre[1]=bar + # Get rid of processed part of patterns + oldpat=${oldpat#${oldpre[i]}"$pat"} # oldpat=.a + newpat=${newpat#${newpre[i]}"$pat"} # newpat=.b + let i=i+1 +done + +if [ $i -eq 1 ]; then + print -u2 "No globbing chars in pattern." + exit 1 +fi + +oldpre[i]=${oldpat%%"$pat"*} # oldpre[2]=.a +oldsuf[i]=${oldpat#*"$pat"} # oldsuf[2]=.a +newpre[i]=${newpat%%"$pat"*} # newpre[2]=.b + +if [ -n "$verbose" ]; then + j=1 + while let "j < i"; do + echo \ +"Old prefix: ${oldpre[j]} Old suffix: ${oldsuf[j]} New prefix: ${newpre[j]}" + let j=j+1 + done +fi + +# Example file: foox.a + +for file; do + j=1 + origname=$file # origname=foox.a + newfile= + while let "j <= i"; do + # Peel off a prefix interation 1 2 + file=${file#${oldpre[j]}} # file=x.a file= + # Save the part of this prefix that is to be retained + const=${file%${oldsuf[j]}} # const=x const= + newfile=$newfile${newpre[j]}$const # newfile=barx newfile=barx.b + file=${file#$const} # file=.a file=.a + let j=j+1 + done + if [ -n "$tell" ]; then + echo "Would move \"$origname\" to \"$newfile\"." + else + if [ -n "$verbose" ]; then + echo "Moving \"$origname\" to \"$newfile\"." + fi + mv $origname $newfile + fi +done diff --git a/examples/scripts.v2/repeat b/examples/scripts.v2/repeat new file mode 100644 index 0000000..7e76007 --- /dev/null +++ b/examples/scripts.v2/repeat @@ -0,0 +1,119 @@ +#! /bin/bash +# +# original from: +# repeat: repeat a command. +# @(#) repeat.ksh 1.1 93/06/03 +# 90/05 john h. dubois iii (john@armory.com) +# 90/11 added help +# 93/06/03 Added s, h, p, and v options +# +# conversion to bash v2 syntax done by Chet Ramey + +istrue() +{ + test 0 -ne "$1" +} + +isfalse() +{ + test 0 -eq "$1" +} + +phelp() +{ +echo "$name: repeatedly execute a command line. +$Usage +commandline is executed once for each integer from startcount through endcount +inclusive. The default for startcount is 1 if a positive endcount or no +endcount is given, and -1 if a negative endcount is given. A count +parameter consisting of a single number is taken to be an endcount. If +only an endcount is given and it is positive, commandline is executed +endcount times. endcount may be less than startcount. If no endcount is +given (e.g. a count parameter of \"10-\"), commandline execution repeats +indefinitely with the iteration variable incrementing in a positive +direction. A count parameter of consisting of \"-\" will repeat +indefinitely starting with 1. + +Note that quoting and variables in commandline are interpreted twice, once +when it is passed to the repeat command, and once when it is actually executed. + +The iteration variable is \"count\". If \$count is used in commandline, make +sure it is quoted with ' or \. + +Options: +-h: Print this help. +-p: Print value of iteration variable on stderr before each iteration. +-s : sleep for seconds after each iteration except the last. +-v: Print start and end values before beginning." +} + +name=${0##*/} +Usage="Usage: repeat [-hpv] [-s ] [[startcount]-][endcount] command [arg ...]" + +typeset -i count=1 forever=0 sleep=0 print=0 verbose=0 + +while getopts :0123456789hpvs: opt; do + case $opt in + h) phelp; exit 0;; + s) sleep=$OPTARG || exit 1;; + p) print=1;; + v)verbose=1;; + [0-9]) break;; + +?) echo "$name: options should not be preceded by a '+'." 1>&2; exit 2;; + ?) echo "$name: $OPTARG: bad option. Use -h for help." 1>&2; exit 2;; + esac +done + +# remove args that were options +shift $((OPTIND-1)) + +if [ $# -lt 2 ]; then + echo -e "$Usage\nUse -h for help." 1>&2 + exit 2 +fi + +case "$1" in +-[0-9]*-|[0-9]*-) + # Start value only + count=${1%-} + forever=1 + ;; +-[0-9]*-[0-9]*|[0-9]*-[0-9]*) + # Start and end value + s=${1%-} + end=${s##[0-9]*-} + count=${s%-$end} + ;; +-[0-9]*|[0-9]*) + end=$1 + case "$end" in + -\*) count=-1;; + esac + ;; +-) + forever=1 + ;; +*) + echo "$name: bad count parameter: $1" 1>&2 + exit 1 + ;; +esac + +shift + +[ -z "$end" -o $count -le "$end" ] && increment=1 || increment=-1 + +istrue $verbose && echo "start=$count end=$end" 1>&2 + +# Need to do this here so that up to this point, -0 will keep the leading - +# and end will not be 0 if no value assigned +typeset -i end + +let end+=increment # make loop inclusive of original endcount + +while istrue $forever || [ $count -ne $end ]; do + istrue $print && echo $count 1>&2 + eval "$@" + istrue $sleep && sleep $sleep + let count+=increment +done diff --git a/examples/scripts.v2/shprof b/examples/scripts.v2/shprof new file mode 100644 index 0000000..73a1bb9 --- /dev/null +++ b/examples/scripts.v2/shprof @@ -0,0 +1,66 @@ +#! /bin/bash +# +# shprof - a line profiler for shell scripts +# +# adapted from a similar program included in `The New KornShell' by +# Bolsky and Korn and posted to usenet by bsh20858@challenger.fhda.edu +# +# converted to bash v2 syntax by Chet Ramey +# +TMPFILE=${TMP:-/tmp}/shprof$$ + +trap 'rm -f $TMPFILE' EXIT + +errexit() +{ + echo $0: "$@" >&2 + exit 1 +} + +# create script with profiling enabled +cat > $TMPFILE <<- \_EOF_ + declare -a _line + _profend() + { + case "$1" in + /*|./*) file="$1" ;; + *) file=$(type -path "$1") ;; + esac + + echo "*** line profile for $file ***" + i=1; + while read -r && [ $i -le $NLINE ]; do + count=${_line[$i]} + if [ "$count" -gt 0 ]; then + echo "[$count] $i: $REPLY" + fi + i=$((i + 1)) + done <$file +_EOF_ +# make the profiling script remove itself after printing line stats +echo "rm -f $TMPFILE" >> $TMPFILE +cat >> $TMPFILE <<- \_EOF_ + } + _command=$1 + shift + i=1 + NLINE=$(wc -l < "$_command") + while [ $i -le $NLINE ]; do + _line[$i]=0 + i=$((i + 1)) + done + unset i + trap "_profend ${_command}" EXIT + trap '_line[$LINENO]=$((${_line[$LINENO]} + 1))' DEBUG + LINENO=0 +_EOF_ + +case "$1" in +/*|./*) file=$1 ;; +*) file=$((type -path "$1")) ;; +esac + +cat "${file-$1}" >> $TMPFILE || errexit "${1}: cannot open" +chmod +x $TMPFILE + +exec -a "$file" $TMPFILE "$@" diff --git a/examples/scripts.v2/untar b/examples/scripts.v2/untar new file mode 100644 index 0000000..1ba6b6b --- /dev/null +++ b/examples/scripts.v2/untar @@ -0,0 +1,80 @@ +#! /bin/bash +# +# original from: +# @(#) untar.ksh 1.0 93/11/10 +# 92/10/08 john h. dubois iii (john@armory.com) +# 92/10/31 make it actually work if archive isn't in current dir! +# 93/11/10 Added pack and gzip archive support +# +# conversion to bash v2 syntax done by Chet Ramey + +phelp() +{ +echo \ +"$name: extract tar archives into directories, uncompressing if neccessary. +Usage: $name archive[.tar[.[Z|gz]]] .. +If an archive name given does not end in .tar, .tar.Z, or .tar.gz, it is +searched for first with .tar added, then .tar.Z, and then .tar.gz added. +The real filename must end in either .tar, .tar.Z, or .tar.gz. A +directory with the name of the archive is created in the current directory +(not necessarily the directory that the archive is in) if it does not +exist, and the the contents of the archive are extracted into it. +Absolute pathnames in tarfiles are suppressed." +} + +if [ $# -eq 0 ]; then + phelp + exit 1 +fi + +name=${0##/} +OWD=$PWD + +for file; do + cd $OWD + case "$file" in + *.tar.Z) ArchiveName=${file%%.tar.Z} zcat=zcat;; + *.tar.z) ArchiveName=${file%%.tar.z} zcat=pcat;; + *.tar.gz) ArchiveName=${file%%.tar.gz} zcat=gzcat;; + *) ArchiveName=$file + for ext in "" .Z .z .gz; do + if [ -f "$file.tar$ext" ]; then + file="$file.tar$ext" + break + fi + done + if [ ! -f "$file" ]; then + echo "$file: cannot find archive." 1>&2 + continue + fi + ;; + esac + if [ ! -r "$file" ]; then + echo "$file: cannot read." >&2 + continue + fi + DirName=${ArchiveName##*/} + [ -d "$DirName" ] || { + mkdir "$DirName" || { + echo "$DirName: could not make archive directory." 1>&2 + continue + } + } + + cd $DirName || { + echo "$name: cannot cd to $DirName" 1>&2 + continue + } + + case "$file" in + /*) ;; + *) file=$OWD/$file ;; + esac + + echo "Extracting archive $file into directory $DirName..." + case "$file" in + *.tar.Z|*.tar.z|*.tar.gz) $zcat $file | tar xvf -;; + *.tar) tar xvf $file;; + esac + echo "Done extracting archive $file into directory $DirName." +done diff --git a/examples/scripts.v2/uudec b/examples/scripts.v2/uudec new file mode 100644 index 0000000..7984058 --- /dev/null +++ b/examples/scripts.v2/uudec @@ -0,0 +1,45 @@ +: +# @(#) uudec.sh 1.0 93/11/22 +# 92/08/04 john@armory.com (John H. DuBois III) +# 93/11/22 Added help. + +isfalse() +{ + test 0 -eq "$1" +} + +phelp() +{ +"$name: process uuencoded files. +Usage: uudec [-h] filename ... +Options: +-h: Print this help." +} + +name=${0##*/} + +typeset -i force=0 + +while getopts "hf" opt; do + case "$opt" in + h) phelp; exit 0;; + f) force=1;; + *) echo "$Usage" 1>&2; exit 2;; + esac +done + +shift $((OPTIND - 1)) + +for file; do + echo "$file" + while read b mode filename && [ "$b" != begin ]; do :; done < "$file" + if [ "$b" = begin ]; then + if [ -f "$filename" ] && isfalse $force; then + echo "Output file \"$filename\" exists. Not written." + else + uudecode "$file" + fi + else + echo "No begin line." + fi +done diff --git a/examples/scripts.v2/uuenc b/examples/scripts.v2/uuenc new file mode 100644 index 0000000..480aa48 --- /dev/null +++ b/examples/scripts.v2/uuenc @@ -0,0 +1,69 @@ +#! /bin/bash +# +# original from: +# @(#) uuenc.ksh 1.0 93/09/18 +# 93/09/18 john h. dubois iii (john@armory.com) +# +# conversion to bash v2 syntax by Chet Ramey + +istrue() +{ + test 0 -ne "$1" +} + +isfalse() +{ + test 0 -eq "$1" +} + +phelp() +{ +echo "$name: uuencode files. +$Usage +For each filename given, $name uuencodes the file, using the final +component of the file's path as the stored filename in the uuencoded +archive and, with a .${SUF} appended, as the name to store the archive in. +Example: +$name /tmp/foo +The file /tmp/foo is uuencoded, with \"foo\" stored as the name to uudecode +the file into, and the output is stored in a file in the current directory +with the name \"foo.${SUF}\". +Options: +-f: Normally, if the file the output would be stored in already exists, + it is not overwritten and an error message is printed. If -f (force) + is given, it is silently overwritten. +-h: Print this help." +} + +name=${0##*/} +Usage="Usage: $name [-hf] ..." +typeset -i force=0 + +SUF=uu + +while getopts :hf opt; do + case $opt in + h) phelp; exit 0;; + f) force=1;; + +?) echo "$name: options should not be preceded by a '+'." 1>&2 ; exit 2;; + ?) echo "$name: $OPTARG: bad option. Use -h for help." 1>&2 ; exit 2;; + esac +done + +# remove args that were options +shift $((OPTIND - 1)) + +if [ $# -lt 1 ]; then + echo "$Usage\nUse -h for help." 1>&2 + exit +fi + +for file; do + tail=${file##*/} + out="$tail.${SUF}" + if isfalse $force && [ -a "$out" ]; then + echo "$name: $out: file exists. Use -f to overwrite." 1>&2 + else + uuencode $file $tail > $out + fi +done diff --git a/examples/scripts.v2/vtree b/examples/scripts.v2/vtree new file mode 100644 index 0000000..60583b0 --- /dev/null +++ b/examples/scripts.v2/vtree @@ -0,0 +1,137 @@ +#! /bin/bash +# +# original from: +# vtree: visual directory tree +# @(#) vtree.sh 1.1 91/07/01 +# 90/04 john h. dubois iii (john@armory.com) +# 91/07/01 fixed bug that caused problems when dir given on command line, +# added some info to help, changed to 4-space indenting +# +# conversion to bash v2 syntax done by Chet Ramey +# +help=\ +"Syntax: vtree [startdir] [namelen=#] [linelen=#] +If startdir is not specified, tree will start at current dir. + +namelen specifies the minimum number of characters of a directory name that +are guaranteed to be printed. +This is a tradeoff between the number of tree levels that can fit on a +screen line and the number of chars of each dir name that can be printed. +In most cases it will be possible to print more than namelen characters of +the name (a name up to namelen+1 chars will always be printed in full), +but in some cases truncation down to namelen chars will occur. +If truncation occurs, a '>' is printed at the end of the name. +namelen=8 (the default) typically causes about 5 dirs/1000 to be truncated. +namelen=7 typically causes about 10 dirs/1000 to be truncated. +namelen=8 will allow 6 full length dirs to be printed in 79 columns. +namelen=7 will allow 7 full length dirs to be printed in 79 columns; + +linelen specifies the maximum number of characters to print on one screen +line. All characters beyond this are truncated. The default is 1024. +To avoid line wrap on an 80 column terminal with autowrap, use linelen=79. +" + +for i in "$@"; do + case $i in + -h) echo "$help"; exit;; + *=*) + vars="$vars $i" + ;; + *) + if [ ! -x $i -o ! -d $i ]; then # arg must be a dir and executable + echo "$i: directory not accessible." + exit + fi + cd $i + ;; + esac + shift +done + +pwd # print path of root of tree + +# find all directories depth first; ignore permission errors +find . -type d -print 2> /dev/null | \ +gawk -F/ ' + +# Do this block for NR == 1 instead of BEGIN because command line var +# assignments are not done until after BEGIN block is executed. +NR == 1 { + if (namelen) + MaxLen = namelen; + else + MaxLen = 8; + if (!linelen) + linelen = 1024 + HSpace = substr(" ",1,MaxLen); # used to indent tree + n = 0; # number of dirs found on one major branch +} + +$0 != "." { # do for every line produced by find except tree root dir + if (NF == 2 && n > 0) # print major branch whenever a new one starts + list(); + Depth[n] = NF - 1; # record depth and name of dir + Name[n++] = $NF; +} + +END { + list() # print last major branch +} + +function list() { + Line = Name[0]; # initialize first line of branch to be branch base + for (i = 1; i < n; i++) { # for each name in major branch + if (Depth[i] == Depth[i-1] + 1) + AddHLink(); # if moving deeper into branch, use same line + else { + print substr(Line,1,linelen); # last line is done; print it + Line = ""; # start new line + # print indentation, vert links, and vert/horiz links + for (d = 1; d < Depth[i] - 1; d++) # for each level of indentation + # if a vert. link has been established for this level + if (VLink[d]) + Line = Line HSpace " | "; + else # print empty indentation + Line = Line HSpace " "; + # Print last part of vert. link + if (VLink[d] == i) { + VLink[d] = 0; # mark level for no vert link + Line = Line HSpace " \\--"; + } + else + Line = Line HSpace " |--"; + } + Line = Line Name[i]; # Add dir name to line + } + print substr(Line,1,linelen); # print last line of major branch + n = 0; # reset name counter +} + +function AddHLink() { + NDepth = Depth[i]; # Depth of this name + VLink[NDepth - 1] = 0; + # search until a name found at a level less than this one + for (j = i + 1; j < n && Depth[j] >= NDepth; j++) + # keep track of last name that VLink should connect to + if (Depth[j] == NDepth) + VLink[NDepth - 1] = j; + if (VLink[NDepth - 1]) { + NLine = substr(Line,1,(NDepth - 2) * (MaxLen + 4) + MaxLen + 1); + if (length(NLine) < length(Line)) + Line = substr(NLine,1,length(NLine) - 1) ">" + else + Line = NLine; + Line = Line substr("--------------+--", + 18 - ((NDepth - 1) * (MaxLen + 4) - length(Line))); + } + else { + NLine = substr(Line,1,(NDepth - 2) * (MaxLen + 4) + MaxLen + 3); + if (length(NLine) < length(Line)) + Line = substr(NLine,1,length(NLine) - 1) ">" + else + Line = NLine; + Line = Line substr("-----------------", + 1,(NDepth - 1) * (MaxLen + 4) - length(Line)); + } +} +' $vars diff --git a/examples/scripts.v2/where b/examples/scripts.v2/where new file mode 100644 index 0000000..7a1dbde --- /dev/null +++ b/examples/scripts.v2/where @@ -0,0 +1,111 @@ +#! /bin/bash +# +# original from: +# @(#) where.ksh 1.1 94/07/11 +# 91/01/12 john h. dubois iii (john@armory.com) +# 92/08/10 Only print executable *files*. +# 92/10/06 Print err msg if no match found. +# 92/11/27 Added implicit * +# 93/07/23 Print help only if -h is given. +# 94/01/01 Added -x option +# 94/07/11 Don't bother with eval +# +# conversion to bash v2 syntax done by Chet Ramey + +name=${0##*/} +Usage="Usage: $name [-hx] 'pattern' ..." +typeset -i exact=0 + +phelp() +{ +echo "$name: find executable files in PATH that match patterns. +$Usage +$name searches each directory specified in the PATH environment variable +for executable files that match the specified patterns. Patterns are +given as Korn shell filename patterns. They are surrounded by implicit +'*' characters, so that \"foo\" will match any executble file whose name +contains contains \"foo\". This can be overridden by using '^' and '$' to +force a match to start at the beginning and end at the end of a filename +respectively. Characters that are special to the shell must generally +be protected from the shell by surrounding them with quotes. +Examples: +$name foo +lists all executable files in PATH that contain foo. +$name '^b*sh$' +lists all executable files in PATH that start with b and end with sh. +An error message is printed if a no matching file is found for a pattern. +Options: +-h: Print this help. +-x: Find exact matches only; equivalent to putting ^ and $ at the start + and end of each pattern." +} + +istrue() +{ + test 0 -ne "$1" +} + +isfalse() +{ + test 0 -eq "$1" +} + +while getopts "xh" opt; do + case "$opt" in + x) exact=1;; + h) phelp ; exit 0;; + *) echo -e "$Usage\nUse -h for help." 1>&2; exit 2;; + esac +done + +shift $((OPTIND-1)) + +set +f # make sure filename globbing is on +Args=("$@") # save args + +OIFS=$IFS +IFS=: # Make PATH be split on : +Paths=($PATH) +IFS=$OIFS + +for arg in "${Args[@]}"; do + + # get rid of leading ^ + if istrue $exact; then + arg=${arg} + else + case "$arg" in + ^*) arg=${arg#?};; + *) arg="*$arg" ;; # Pattern is not anchored at start + esac + fi + + # get rid of trailing $ + if istrue $exact; then + arg="$arg" + else + case "$arg" in + *\$) arg=${arg%?} ;; + *) arg="$arg*" ;; + esac + fi + + found=0 # Pattern not found yet + Patterns= + # Make a pattern for each element of PATH + for PathElem in "${Paths[@]}"; do + [ -z "$PathElem" ] && PathElem=. + Patterns="$Patterns $PathElem/$arg" + done + + # Find all pattern matches that are executable regular files. + for file in $Patterns; do + if [ -x "$file" ] && [ -f "$file" ]; then + echo "$file" + found=1 + fi + done + if [ $found = 0 ]; then + echo "$arg: not found." 1>&2 + fi +done diff --git a/examples/scripts/bcsh.sh b/examples/scripts/bcsh.sh old mode 100644 new mode 100755 diff --git a/support/inpath b/examples/scripts/inpath similarity index 100% rename from support/inpath rename to examples/scripts/inpath diff --git a/examples/scripts/nohup.bash b/examples/scripts/nohup.bash new file mode 100644 index 0000000..3781293 --- /dev/null +++ b/examples/scripts/nohup.bash @@ -0,0 +1,51 @@ +# +# BASH VERSION OF nohup COMMAND +# +ctype() +{ + path=$(builtin type -p $cmd | sed 1q) + if [ -n "$path" ]; then + echo "$path" + return 0 + else + case "$cmd" in + */*) [ -x "$cmd ] && { echo "$cmd" ; return 0; } ;; + *) case "$(builtin type -t $cmd)" in + "") return 1;; + *) echo "$cmd" ; return 0;; + esac ;; + esac + fi + return 1 +} + +trap '' HUP # ignore hangup +command=$(ctype "$1") +oldmask=$(umask) +umask u=rw,og= # default mode for nohup.out +exec 0< /dev/null # disconnect input +if [ -t 1 ]; then # redirect output if necessary + if [ -w . ]; then + echo 'Sending output to nohup.out' + exec >> nohup.out + else echo "Sending output to $HOME/nohup.out" + exec >> $HOME/nohup.out + fi +fi + +umask "$oldmask" + +# direct unit 2 to a file +if [ -t 2 ]; then + exec 2>&1 +fi + +# run the command +case $command in +*/*) exec "$@" + ;; +time) eval "$@" + ;; +*) "$@" + ;; +esac diff --git a/examples/scripts/precedence b/examples/scripts/precedence old mode 100644 new mode 100755 diff --git a/examples/scripts/scrollbar b/examples/scripts/scrollbar new file mode 100755 index 0000000..c177179 --- /dev/null +++ b/examples/scripts/scrollbar @@ -0,0 +1,25 @@ +#!/bin/bash +# +# scrollbar - display scrolling text +# +# usage: scrollbar args +# +# A cute hack originally from Heiner Steven +# +# converted from ksh syntax to bash v2 syntax by Chet Ramey + +WIDTH=${COLUMNS:-80} + +[ $# -lt 1 ] && set -- TESTING + +# Posix.2 compatible printf command or bash loadable builtin +# in examples/loadables/printf +Text=$(printf "%-${WIDTH}s" "$*") +Text=$(echo "$Text" | tr ' ' '_') + +while : +do + printf "%-.${WIDTH}s\r" "$Text" + LastC=$(expr "$Text" : '.*\(.\)$') + Text=$(printf "%-.${WIDTH}s" "$LastC$Text") +done diff --git a/examples/scripts/vtree2 b/examples/scripts/vtree2 new file mode 100755 index 0000000..27649a1 --- /dev/null +++ b/examples/scripts/vtree2 @@ -0,0 +1,42 @@ +#!/bin/bash +# +# vtree - make a tree printout of the specified directory, with disk usage +# in 1k blocks +# +# usage: vtree [-a] [dir] +# +# Original posted to Usenet sometime in February, 1996 +# +usage() +{ + echo "vtree: usage: vtree [-a] [dir]" >&2 +} + +while getopts a opt +do + case "$opt" in + a) andfiles=-a ;; + *) usage ; exit 2 ;; + esac +done + +shift $((OPTIND - 1)) + +export BLOCKSIZE=1k # 4.4 BSD systems need this + +[ $# -eq 0 ] && set . + +while [ $# -gt 0 ] +do + cd "$1" || { shift; [ $# -ge 1 ] && echo >&2; continue; } + echo -n "$PWD" + + du $andfiles | sort +1f | sed \ + 's/\([^ ]*\) \(.*\)/\2 (\1)/ + '"s#^$1##"' + s#[^/]*/\([^/]*\)$#|____\1# + s#[^/]*/#| #g' + + [ $# -gt 1 ] && echo + shift +done diff --git a/examples/scripts/zprintf b/examples/scripts/zprintf new file mode 100755 index 0000000..5e2e3ad --- /dev/null +++ b/examples/scripts/zprintf @@ -0,0 +1,26 @@ +#! /bin/bash +# +# zprintf - function that calls gawk to do printf for those systems that +# don't have a printf executable +# +# The format and arguments can have trailing commas, just like gawk +# +# example: +# zprintf 'Eat %x %x and suck %x!\n' 57005 48879 64206 +# +# Chet Ramey +# chet@po.cwru.edu + +[ $# -lt 1 ] && { + echo "zprintf: usage: zprintf format [args ...]" >&2 + exit 2 +} + +fmt="${1%,}" +shift + +for a in "$@"; do + args="$args,\"${a%,}\"" +done + +gawk "BEGIN { printf \"$fmt\" $args }" diff --git a/examples/startup-files/Bash_aliases b/examples/startup-files/Bash_aliases index 012ad5c..bb9c01e 100644 --- a/examples/startup-files/Bash_aliases +++ b/examples/startup-files/Bash_aliases @@ -13,7 +13,6 @@ alias j="jobs -l" alias l="ls -l " alias ll="ls -l" alias ls="ls -F" -alias term='set noglob; eval `tset -Q -s `' alias pu="pushd" alias po="popd" @@ -53,11 +52,12 @@ seq () { local lower upper output; lower=$1 upper=$2; + + if [ $lower -ge $upper ]; then return; fi while [ $lower -le $upper ]; do - output="$output $lower"; - lower=$[ $lower + 1 ]; - done; - echo $output + echo -n "$lower " + lower=$(($lower + 1)) + done + echo "$lower" } - diff --git a/examples/startup-files/Bash_profile b/examples/startup-files/Bash_profile index b1b24c0..141e8df 100644 --- a/examples/startup-files/Bash_profile +++ b/examples/startup-files/Bash_profile @@ -2,9 +2,9 @@ # default_dir=/usr/local/lib/ -if [ "$PS1" ]; then - PS1='\u@\h(\#)$ ' - ignoreeof=3 +if [ -n "$PS1" ]; then + PS1='\u@\h(\#)\$ ' + IGNOREEOF=3 fi LOGIN_SHELL=true @@ -12,9 +12,7 @@ LOGIN_SHELL=true # If the user has her own init file, then use that one, else use the # canonical one. if [ -f ~/.bashrc ]; then - source ~/.bashrc -else if [ -f ${default_dir}Bashrc ]; then - source ${default_dir}Bashrc; - fi + . ~/.bashrc +elif [ -f ${default_dir}Bashrc ]; then + . ${default_dir}Bashrc; fi - diff --git a/examples/startup-files/Bashrc b/examples/startup-files/Bashrc index 935bff8..efe7d88 100644 --- a/examples/startup-files/Bashrc +++ b/examples/startup-files/Bashrc @@ -16,57 +16,55 @@ X11=/usr/bin/X11 UTIL_PATH=$GNU:$X11 STANDARD_PATH=/usr/local/bin:/usr/ucb:/bin:/usr/bin:/usr/etc:/etc:/usr/games -if [ "$HOSTTYPE" = "sony" ]; then STANDARD_PATH=STANDARD_PATH:/usr/sony/bin; fi if [ -d $HOME/bin/$HOSTTYPE ]; then - MY_PATH=$HOME/bin/$HOSTTYPE + MY_PATH=$HOME/bin/$HOSTTYPE fi if [ -d $HOME/bin ]; then - MY_PATH=$MY_PATH:$HOME/bin + MY_PATH=$MY_PATH:$HOME/bin fi if [ -d /usr/hosts ]; then - STANDARD_PATH=$STANDARD_PATH:/usr/hosts + STANDARD_PATH=$STANDARD_PATH:/usr/hosts fi PATH=.:$MY_PATH:$UTIL_PATH:$STANDARD_PATH -# If running interactively, then: -if [ "$PS1" ]; then +# If not running interactively, then return +if [ -z "$PS1" ]; then + return +fi - # Set ignoreeof if you don't want EOF as the sole input to the shell to - # immediately signal a quit condition. This only happens at the start - # of a line if the line is empty, and you haven't just deleted a character - # with C-d. I turn this on in ~/.bash_profile so that only login shells - # have the right to be obnoxious. - # ignoreeof= +# Set ignoreeof if you don't want EOF as the sole input to the shell to +# immediately signal a quit condition. This only happens at the start +# of a line if the line is empty, and you haven't just deleted a character +# with C-d. I turn this on in ~/.bash_profile so that only login shells +# have the right to be obnoxious. +# set -o ignoreeof - # Set auto_resume if you want to resume on "emacs", as well as on - # "%emacs". - auto_resume= +# Set auto_resume if you want to resume on "emacs", as well as on +# "%emacs". +auto_resume=exact - # Set notify if you want to be asynchronously notified about background - # job completion. - notify= +# Set notify if you want to be asynchronously notified about background +# job completion. +set -o notify - # Make it so that failed `exec' commands don't flush this shell. - no_exit_on_failed_exec= +# Make it so that failed `exec' commands don't flush this shell. +shopt -s execfail - if [ ! "$LOGIN_SHELL" ]; then - PS1="\u@\h\$ " - fi +if [ -z "$LOGIN_SHELL" ]; then + PS1="\u@\h\$ " +fi - HISTSIZE=256 - MAILCHECK=60 +HISTSIZE=256 +MAILCHECK=60 - # A couple of default aliases. - alias j='jobs -l' - alias po=popd - alias pu=pushd - alias ls='ls -F' +# A couple of default aliases. +alias j='jobs -l' +alias po=popd +alias pu=pushd +alias ls='ls -F' - if [ -f ~/.bash_aliases ]; then - source ~/.bash_aliases - fi -fi +[ -f ~/.bash_aliases ] && . ~/.bash_aliases diff --git a/examples/startup-files/README b/examples/startup-files/README new file mode 100644 index 0000000..bdbfd90 --- /dev/null +++ b/examples/startup-files/README @@ -0,0 +1,5 @@ +Some sample startup files. The ones starting with capital letters +are originally from Brian Fox. The ones starting with lowercase +letters are from Chet Ramey. + +They will require changes for your environment. diff --git a/examples/startup-files/bash-profile b/examples/startup-files/bash-profile index 01c322a..e811df8 100644 --- a/examples/startup-files/bash-profile +++ b/examples/startup-files/bash-profile @@ -1,52 +1,37 @@ -HOME=/usr/homes/chet -MAIL=/usr/homes/chet/mbox +# This is the filename where your incoming mail arrives. +MAIL=~/mbox MAILCHECK=30 -HISTFILE=/usr/homes/chet/.history -MACHINE=$(/usr/local/bin/machine) -HOST=$(hostname) +HISTFILE=~/.history/history.$HOSTNAME -PATH1=/usr/homes/chet/bin.$MACHINE:/usr/local/bin/gnu: +PATH1=/usr/homes/chet/bin.$HOSTTYPE:/usr/local/bin/gnu: PATH2=/usr/local/bin:/usr/ucb:/bin:/usr/bin/X11:. -PATH3=/usr/andrew/bin:/usr/bin:/usr/ibm:/usr/local/bin/mh:/usr/new/bin: +PATH3=/usr/bin:/usr/new/bin:/usr/contrib/bin PATH=$PATH1:$PATH2:$PATH3 -EDITOR=/usr/homes/chet/bin.$MACHINE/ce -VISUAL=/usr/homes/chet/bin.$MACHINE/ce -FCEDIT=/usr/homes/chet/bin.$MACHINE/ce +EDITOR=/usr/local/bin/ce VISUAL=/usr/local/bin/ce FCEDIT=/usr/local/bin/ce -if [ "$BASH" ] ; then - SHELL=$BASH -else - SHELL=/bin/bash -fi - -if [ "$MACHINE" = "ibm032" ] ; then - stty erase ^H -fi - -PAGER=/usr/ucb/more -NNTPSERVER=kiwi -NS=/nfs/cwjcc/fs1/ns-engr/proj/netsrv/cwpub/proto/src +SHELL=${SHELL:-${BASH:-/bin/bash}} +PAGER=/usr/local/bin/less +LESS='-i -e -M -P%t?f%f :stdin .?pb%pb\%:?lbLine %lb:?bbByte %bb:-...' # # Bogus 1003.2 variables. This should really be in /etc/profile # LOGNAME=${USER-$(whoami)} -TZ=EST5EDT +TZ=US/Eastern -export HOME ENV VISUAL EDITOR MAIL SHELL PATH TERM -export PAGER LESS TERMCAP HISTSZIE HISTFILE -export MAIL MAILCHECK HOST HOSTNAME NNTPSERVER NS LOGNAME TZ +export HOME VISUAL EDITOR MAIL SHELL PATH TERM +export PAGER LESS TERMCAP HISTSIZE HISTFILE MAIL MAILCHECK LOGNAME TZ -PS1="${HOST}$ " +PS1="${HOSTNAME}\$ " PS2='> ' export PS1 PS2 umask 022 if [ -f /unix ] ; then - stty intr ^c + stty intr ^c # bogus fi if [ -f ~/.bashrc ] ; then diff --git a/examples/startup-files/bashrc b/examples/startup-files/bashrc index 5363e58..069e8be 100644 --- a/examples/startup-files/bashrc +++ b/examples/startup-files/bashrc @@ -1,35 +1,35 @@ -if [ "$PS1" != "" ] ; then +if [ -z "$PS1" ]; then + return +fi -if [ -f /unix ] ; then +# bogus +if [ -f /unix ] ; then alias ls='/bin/ls -CF' - alias ll='/bin/ls -lCF' - alias dir='/bin/ls -bCalF' else alias ls='/bin/ls -F' - alias ll='/bin/ls -lF' - alias dir='/bin/ls -balF' fi +alias ll='ls -l' +alias dir='ls -ba' alias ss="ps -aux" -alias mail=/usr/ucb/mail -alias dot='ls .[a-zA-Z0-9]*' -alias mroe=more -alias pwd='echo $PWD' -alias pdw='echo $PWD' -alias news="xterm -g 80x45 -e rn -e &" -alias back='cd $OLDPWD' -alias manroff="nroff /usr/lib/tmac/tmac.an.4.3" -alias laser="lpr -Palw2" -alias lw="lpr -Palw2" +alias dot='ls .[a-zA-Z0-9_]*' +alias news="xterm -g 80x45 -e trn -e -S1 -N &" + alias c="clear" alias m="more" alias j="jobs" +# common misspellings +alias mroe=more +alias pdw=pwd + +hash -p /usr/bin/mail mail + if [ -z "$HOST" ] ; then - export HOST=`hostname` + export HOST=${HOSTNAME} fi -history_control=ignoredups +HISTIGNORE="[ ]*:&:bg:fg" psgrep() { @@ -57,10 +57,14 @@ term() tset } +xtitle () +{ + echo -n -e "\033]0;$*\007" +} + cd() { - builtin cd $* - xtitle $HOST: $PWD + builtin cd "$@" && xtitle $HOST: $PWD } bold() @@ -126,14 +130,3 @@ function chmog() chgrp $3 $4 fi } - -# -# Source kshenv for ksh-compatibility definitions -# - -if [ -f ~/.kshenv ] ; then - . ~/.kshenv -fi - -fi -#end of .bashrc diff --git a/execute_cmd.c b/execute_cmd.c index 55274ea..ce154c3 100644 --- a/execute_cmd.c +++ b/execute_cmd.c @@ -17,9 +17,11 @@ 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, 675 Mass Ave, Cambridge, MA 02139, USA. */ -#if defined (AIX) && defined (RISC6000) && !defined (__GNUC__) +#include "config.h" + +#if !defined (__GNUC__) && !defined (HAVE_ALLOCA_H) && defined (_AIX) #pragma alloca -#endif /* AIX && RISC6000 && !__GNUC__ */ +#endif /* _AIX && RISC6000 && !__GNUC__ */ #include #include @@ -28,32 +30,47 @@ #include "filecntl.h" #include "posixstat.h" #include +#include -#if !defined (SIGABRT) -#define SIGABRT SIGIOT +#if defined (HAVE_UNISTD_H) +# include +#endif + +#if defined (HAVE_LIMITS_H) +# include +#endif + +#if defined (HAVE_SYS_TIME_H) +# include +#endif + +#if defined (HAVE_SYS_RESOURCE_H) +# include +#endif + +#if defined (HAVE_SYS_TIMES_H) && defined (HAVE_TIMES) +# include #endif -#include #include #if !defined (errno) extern int errno; #endif -#if defined (HAVE_STRING_H) -# include -#else /* !HAVE_STRING_H */ -# include -#endif /* !HAVE_STRING_H */ +#include "bashansi.h" +#include "memalloc.h" #include "shell.h" #include "y.tab.h" #include "flags.h" -#include "hash.h" +#include "builtins.h" +#include "hashlib.h" #include "jobs.h" #include "execute_cmd.h" +#include "trap.h" +#include "pathexp.h" -#include "sysdefs.h" #include "builtins/common.h" #include "builtins/builtext.h" /* list of builtins */ @@ -64,55 +81,91 @@ extern int errno; # include "input.h" #endif +#if defined (ALIAS) +# include "alias.h" +#endif + +#if defined (HISTORY) +# include "bashhist.h" +#endif + extern int posixly_correct; -extern int breaking, continuing, loop_level; -extern int interactive, interactive_shell, login_shell; -extern int parse_and_execute_level; +extern int executing, breaking, continuing, loop_level; +extern int interactive, interactive_shell, login_shell, expand_aliases; +extern int parse_and_execute_level, running_trap; extern int command_string_index, variable_context, line_number; extern int dot_found_in_search; +extern int already_making_children; extern char **temporary_env, **function_env, **builtin_env; extern char *the_printed_command, *shell_name; extern pid_t last_command_subst_pid; extern Function *last_shell_builtin, *this_shell_builtin; -extern jmp_buf top_level, subshell_top_level; -extern int subshell_argc; extern char **subshell_argv, **subshell_envp; -extern int already_making_children; +extern int subshell_argc; +extern char *glob_argv_flags; extern int getdtablesize (); extern int close (); /* Static functions defined and used in this file. */ -static void close_pipes (), do_piping (), execute_disk_command (); -static void execute_subshell_builtin_or_function (); -static void cleanup_redirects (), cleanup_func_redirects (), bind_lastarg (); +static void close_pipes (), do_piping (), bind_lastarg (); +static void cleanup_redirects (); static void add_undo_close_redirect (), add_exec_redirect (); +static int add_undo_redirect (); static int do_redirection_internal (), do_redirections (); -static int expandable_redirection_filename (), execute_shell_script (); -static int execute_builtin_or_function (), add_undo_redirect (); +static int expandable_redirection_filename (); static char *find_user_command_internal (), *find_user_command_in_path (); +static char *find_in_path_element (), *find_absolute_program (); + +static int execute_for_command (); +#if defined (SELECT_COMMAND) +static int execute_select_command (); +#endif +static int time_command (); +static int execute_case_command (); +static int execute_while_command (), execute_until_command (); +static int execute_while_or_until (); +static int execute_if_command (); +static int execute_simple_command (); +static int execute_builtin (), execute_function (); +static int execute_builtin_or_function (); +static int builtin_status (); +static void execute_subshell_builtin_or_function (); +static void execute_disk_command (); +static int execute_connection (); +static int execute_intern_function (); /* The line number that the currently executing function starts on. */ -static int function_line_number = 0; +static int function_line_number; /* Set to 1 if fd 0 was the subject of redirection to a subshell. */ -static int stdin_redir = 0; +static int stdin_redir; /* The name of the command that is currently being executed. `test' needs this, for example. */ char *this_command_name; +static COMMAND *currently_executing_command; + struct stat SB; /* used for debugging */ +static int special_builtin_failed; static REDIRECTEE rd; +/* The file name which we would try to execute, except that it isn't + possible to execute it. This is the first file that matches the + name that we are looking for while we are searching $PATH for a + suitable one to execute. If we cannot find a suitable executable + file, then we use this one. */ +static char *file_to_lose_on; + /* For catching RETURN in a function. */ -int return_catch_flag = 0; +int return_catch_flag; int return_catch_value; -jmp_buf return_catch; +procenv_t return_catch; /* The value returned by the last synchronous command. */ -int last_command_exit_value = 0; +int last_command_exit_value; /* The list of redirections to perform which will undo the redirections that I made in the shell. */ @@ -125,7 +178,11 @@ REDIRECT *exec_redirection_undo_list = (REDIRECT *)NULL; /* Non-zero if we have just forked and are currently running in a subshell environment. */ -int subshell_environment = 0; +int subshell_environment; + +/* Non-zero if we should stat every command found in the hash table to + make sure it still exists. */ +int check_hashed_filenames; struct fd_bitmap *current_fds_to_close = (struct fd_bitmap *)NULL; @@ -178,6 +235,16 @@ close_fd_bitmap (fdbp) } } +/* Return the line number of the currently executing command. */ +int +executing_line_number () +{ + if (executing && variable_context == 0 && currently_executing_command && + currently_executing_command->type == cm_simple) + return currently_executing_command->value.Simple->line; + return line_number; +} + /* Execute the command passed in COMMAND. COMMAND is exactly what read_command () places into GLOBAL_COMMAND. See "command.h" for the details of the command structure. @@ -185,6 +252,7 @@ close_fd_bitmap (fdbp) EXECUTION_SUCCESS or EXECUTION_FAILURE are the only possible return values. Executing a command with nothing in it returns EXECUTION_SUCCESS. */ +int execute_command (command) COMMAND *command; { @@ -242,6 +310,7 @@ cleanup_redirects (list) dispose_redirects (list); } +#if 0 /* Function to unwind_protect the redirections for functions and builtins. */ static void cleanup_func_redirects (list) @@ -249,6 +318,7 @@ cleanup_func_redirects (list) { do_redirections (list, 1, 0, 0); } +#endif static void dispose_exec_redirects () @@ -280,7 +350,7 @@ open_files () fd_table_size = getdtablesize (); - fprintf (stderr, "pid %d open files:", getpid ()); + fprintf (stderr, "pid %d open files:", (int)getpid ()); for (i = 3; i < fd_table_size; i++) { if ((f = fcntl (i, F_GETFD, 0)) != -1) @@ -289,7 +359,7 @@ open_files () fprintf (stderr, "\n"); } -#define DESCRIBE_PID(pid) if (interactive) describe_pid (pid) +#define DESCRIBE_PID(pid) do { if (interactive) describe_pid (pid); } while (0) /* Execute the command passed in COMMAND, perhaps doing it asynchrounously. COMMAND is exactly what read_command () places into GLOBAL_COMMAND. @@ -303,30 +373,44 @@ open_files () EXECUTION_SUCCESS or EXECUTION_FAILURE are the only possible return values. Executing a command with nothing in it returns EXECUTION_SUCCESS. */ -execute_command_internal (command, asynchronous, pipe_in, pipe_out, +int +execute_command_internal (command, asynchronous, pipe_in, pipe_out, fds_to_close) COMMAND *command; int asynchronous; int pipe_in, pipe_out; struct fd_bitmap *fds_to_close; { - int exec_result = EXECUTION_SUCCESS; - int invert, ignore_return; - REDIRECT *my_undo_list, *exec_undo_list; + int exec_result, invert, ignore_return, was_debug_trap; + REDIRECT *my_undo_list, *exec_undo_list, *rp; + pid_t last_pid; - if (!command || breaking || continuing) + if (command == 0 || breaking || continuing || read_but_dont_execute) return (EXECUTION_SUCCESS); run_pending_traps (); + if (running_trap == 0) + currently_executing_command = command; + +#if defined (COMMAND_TIMING) + if (command->flags & CMD_TIME_PIPELINE) + { + exec_result = time_command (command, asynchronous, pipe_in, pipe_out, fds_to_close); + if (running_trap == 0) + currently_executing_command = (COMMAND *)NULL; + return (exec_result); + } +#endif /* COMMAND_TIMING */ + invert = (command->flags & CMD_INVERT_RETURN) != 0; + exec_result = EXECUTION_SUCCESS; /* If a command was being explicitly run in a subshell, or if it is a shell control-structure, and it has a pipe, then we do the command in a subshell. */ - if ((command->flags & CMD_WANT_SUBSHELL) || - (command->flags & CMD_FORCE_SUBSHELL) || + if ((command->flags & (CMD_WANT_SUBSHELL|CMD_FORCE_SUBSHELL)) || (shell_control_structure (command->type) && (pipe_out != NO_PIPE || pipe_in != NO_PIPE || asynchronous))) { @@ -340,26 +424,15 @@ execute_command_internal (command, asynchronous, pipe_in, pipe_out, { int user_subshell, return_code, function_value; - /* Cancel traps, in trap.c. */ - restore_original_signals (); - if (asynchronous) - setup_async_signals (); - -#if defined (JOB_CONTROL) - set_sigchld_handler (); -#endif /* JOB_CONTROL */ - - set_sigint_handler (); - user_subshell = (command->flags & CMD_WANT_SUBSHELL) != 0; command->flags &= ~(CMD_FORCE_SUBSHELL | CMD_WANT_SUBSHELL | CMD_INVERT_RETURN); /* If a command is asynchronous in a subshell (like ( foo ) & or the special case of an asynchronous GROUP command where the - the subshell bit is turned on down in case cm_group: below), + the subshell bit is turned on down in case cm_group: below), turn off `asynchronous', so that two subshells aren't spawned. - This seems semantically correct to me. For example, + This seems semantically correct to me. For example, ( foo ) & seems to say ``do the command `foo' in a subshell environment, but don't wait for that subshell to finish'', and "{ foo ; bar } &" seems to me to be like functions or @@ -378,13 +451,26 @@ execute_command_internal (command, asynchronous, pipe_in, pipe_out, original_pgrp = -1; #endif /* JOB_CONTROL */ interactive_shell = 0; + expand_aliases = 0; asynchronous = 0; } /* Subshells are neither login nor interactive. */ login_shell = interactive = 0; - subshell_environment = 1; + subshell_environment = user_subshell ? SUBSHELL_PAREN : SUBSHELL_ASYNC; + + reset_terminating_signals (); /* in shell.c */ + /* Cancel traps, in trap.c. */ + restore_original_signals (); + if (asynchronous) + setup_async_signals (); + +#if defined (JOB_CONTROL) + set_sigchld_handler (); +#endif /* JOB_CONTROL */ + + set_sigint_handler (); #if defined (JOB_CONTROL) /* Delete all traces that there were any jobs running. This is @@ -399,10 +485,8 @@ execute_command_internal (command, asynchronous, pipe_in, pipe_out, sh compatibility, but I'm not sure it's the right thing to do. */ if (user_subshell) { - REDIRECT *r; - - for (r = command->redirects; r; r = r->next) - switch (r->instruction) + for (rp = command->redirects; rp; rp = rp->next) + switch (rp->instruction) { case r_input_direction: case r_inputa_direction: @@ -414,10 +498,11 @@ execute_command_internal (command, asynchronous, pipe_in, pipe_out, case r_duplicating_input: case r_duplicating_input_word: case r_close_this: - if (r->redirector == 0) - stdin_redir++; + stdin_redir += (rp->redirector == 0); break; } + + restore_default_signal (0); } if (fds_to_close) @@ -446,7 +531,7 @@ execute_command_internal (command, asynchronous, pipe_in, pipe_out, need to handle a possible `return'. */ function_value = 0; if (return_catch_flag) - function_value = setjmp (return_catch); + function_value = setjmp (return_catch); if (function_value) return_code = return_catch_value; @@ -474,25 +559,22 @@ execute_command_internal (command, asynchronous, pipe_in, pipe_out, /* If we are part of a pipeline, and not the end of the pipeline, then we should simply return and let the last command in the pipe be waited for. If we are not in a pipeline, or are the - last command in the pipeline, then we wait for the subshell + last command in the pipeline, then we wait for the subshell and return its exit status as usual. */ if (pipe_out != NO_PIPE) return (EXECUTION_SUCCESS); stop_pipeline (asynchronous, (COMMAND *)NULL); - if (!asynchronous) + if (asynchronous == 0) { last_command_exit_value = wait_for (paren_pid); /* If we have to, invert the return value. */ if (invert) - { - if (last_command_exit_value == EXECUTION_SUCCESS) - return (EXECUTION_FAILURE); - else - return (EXECUTION_SUCCESS); - } + return ((last_command_exit_value == EXECUTION_SUCCESS) + ? EXECUTION_FAILURE + : EXECUTION_SUCCESS); else return (last_command_exit_value); } @@ -550,6 +632,71 @@ execute_command_internal (command, asynchronous, pipe_in, pipe_out, switch (command->type) { + case cm_simple: + { + /* We can't rely on this variable retaining its value across a + call to execute_simple_command if a longjmp occurs as the + result of a `return' builtin. This is true for sure with gcc. */ + last_pid = last_made_pid; + was_debug_trap = signal_is_trapped (DEBUG_TRAP) && signal_is_ignored (DEBUG_TRAP) == 0; + + if (ignore_return && command->value.Simple) + command->value.Simple->flags |= CMD_IGNORE_RETURN; + exec_result = + execute_simple_command (command->value.Simple, pipe_in, pipe_out, + asynchronous, fds_to_close); + + /* The temporary environment should be used for only the simple + command immediately following its definition. */ + dispose_used_env_vars (); + +#if (defined (ultrix) && defined (mips)) || defined (C_ALLOCA) + /* Reclaim memory allocated with alloca () on machines which + may be using the alloca emulation code. */ + (void) alloca (0); +#endif /* (ultrix && mips) || C_ALLOCA */ + + /* If we forked to do the command, then we must wait_for () + the child. */ + + /* XXX - this is something to watch out for if there are problems + when the shell is compiled without job control. */ + if (already_making_children && pipe_out == NO_PIPE && + last_pid != last_made_pid) + { + stop_pipeline (asynchronous, (COMMAND *)NULL); + + if (asynchronous) + { + DESCRIBE_PID (last_made_pid); + } + else +#if !defined (JOB_CONTROL) + /* Do not wait for asynchronous processes started from + startup files. */ + if (last_made_pid != last_asynchronous_pid) +#endif + /* When executing a shell function that executes other + commands, this causes the last simple command in + the function to be waited for twice. */ + exec_result = wait_for (last_made_pid); + } + } + + if (was_debug_trap) + run_debug_trap (); + + if (ignore_return == 0 && invert == 0 && + ((posixly_correct && interactive == 0 && special_builtin_failed) || + (exit_immediately_on_error && (exec_result != EXECUTION_SUCCESS)))) + { + last_command_exit_value = exec_result; + run_pending_traps (); + jump_to_top_level (EXITPROG); + } + + break; + case cm_for: if (ignore_return) command->value.For->flags |= CMD_IGNORE_RETURN; @@ -632,360 +779,620 @@ execute_command_internal (command, asynchronous, pipe_in, pipe_out, } break; - case cm_simple: - { - /* We can't rely on this variable retaining its value across a - call to execute_simple_command if a longjmp occurs as the - result of a `return' builtin. This is true for sure with gcc. */ - pid_t last_pid = last_made_pid; + case cm_connection: + exec_result = execute_connection (command, asynchronous, + pipe_in, pipe_out, fds_to_close); + break; - if (ignore_return && command->value.Simple) - command->value.Simple->flags |= CMD_IGNORE_RETURN; - exec_result = - execute_simple_command (command->value.Simple, pipe_in, pipe_out, - asynchronous, fds_to_close); + case cm_function_def: + exec_result = execute_intern_function (command->value.Function_def->name, + command->value.Function_def->command); + break; - /* The temporary environment should be used for only the simple - command immediately following its definition. */ - dispose_used_env_vars (); + default: + programming_error + ("execute_command: bad command type `%d'", command->type); + } -#if (defined (Ultrix) && defined (mips)) || !defined (HAVE_ALLOCA) - /* Reclaim memory allocated with alloca () on machines which - may be using the alloca emulation code. */ - (void) alloca (0); -#endif /* (Ultrix && mips) || !HAVE_ALLOCA */ + if (my_undo_list) + { + do_redirections (my_undo_list, 1, 0, 0); + dispose_redirects (my_undo_list); + } - /* If we forked to do the command, then we must wait_for () - the child. */ + if (exec_undo_list) + dispose_redirects (exec_undo_list); - /* XXX - this is something to watch out for if there are problems - when the shell is compiled without job control. */ - if (already_making_children && pipe_out == NO_PIPE && - last_pid != last_made_pid) - { - stop_pipeline (asynchronous, (COMMAND *)NULL); + if (my_undo_list || exec_undo_list) + discard_unwind_frame ("loop_redirections"); - if (asynchronous) - { - DESCRIBE_PID (last_made_pid); - } - else -#if !defined (JOB_CONTROL) - /* Do not wait for asynchronous processes started from - startup files. */ - if (last_made_pid != last_asynchronous_pid) -#endif - /* When executing a shell function that executes other - commands, this causes the last simple command in - the function to be waited for twice. */ - exec_result = wait_for (last_made_pid); - } - } + /* Invert the return value if we have to */ + if (invert) + exec_result = (exec_result == EXECUTION_SUCCESS) + ? EXECUTION_FAILURE + : EXECUTION_SUCCESS; - if (!ignore_return && exit_immediately_on_error && !invert && - (exec_result != EXECUTION_SUCCESS)) - { - last_command_exit_value = exec_result; - run_pending_traps (); - longjmp (top_level, EXITPROG); - } + last_command_exit_value = exec_result; + run_pending_traps (); + if (running_trap == 0) + currently_executing_command = (COMMAND *)NULL; + return (last_command_exit_value); +} - break; +#if defined (COMMAND_TIMING) +#if defined (HAVE_GETRUSAGE) && defined (HAVE_GETTIMEOFDAY) +static struct timeval * +difftimeval (d, t1, t2) + struct timeval *d, *t1, *t2; +{ + d->tv_sec = t2->tv_sec - t1->tv_sec; + d->tv_usec = t2->tv_usec - t1->tv_usec; + if (d->tv_usec < 0) + { + d->tv_usec += 1000000; + d->tv_sec -= 1; + if (d->tv_sec < 0) /* ??? -- BSD/OS does this */ + d->tv_sec = 0; + } + return d; +} - case cm_connection: - switch (command->value.Connection->connector) - { - /* Do the first command asynchronously. */ - case '&': - { - COMMAND *tc = command->value.Connection->first; - REDIRECT *rp; +static struct timeval * +addtimeval (d, t1, t2) + struct timeval *d, *t1, *t2; +{ + d->tv_sec = t1->tv_sec + t2->tv_sec; + d->tv_usec = t1->tv_usec + t2->tv_usec; + if (d->tv_usec > 1000000) + { + d->tv_usec -= 1000000; + d->tv_sec += 1; + } + return d; +} - if (!tc) - break; +/* Do "cpu = ((user + sys) * 10000) / real;" with timevals. + Barely-tested code from Deven T. Corzine . */ +static int +timeval_to_cpu (rt, ut, st) + struct timeval *rt, *ut, *st; /* real, user, sys */ +{ + struct timeval t1, t2; + register int i; - rp = tc->redirects; + addtimeval (&t1, ut, st); + t2.tv_sec = rt->tv_sec; + t2.tv_usec = rt->tv_usec; - if (ignore_return && tc) - tc->flags |= CMD_IGNORE_RETURN; + for (i = 0; i < 6; i++) + { + if ((t1.tv_sec > 99999999) || (t2.tv_sec > 99999999)) + break; + t1.tv_sec *= 10; + t1.tv_sec += t1.tv_usec / 100000; + t1.tv_usec *= 10; + t1.tv_usec %= 1000000; + t2.tv_sec *= 10; + t2.tv_sec += t2.tv_usec / 100000; + t2.tv_usec *= 10; + t2.tv_usec %= 1000000; + } + for (i = 0; i < 4; i++) + { + if (t1.tv_sec < 100000000) + t1.tv_sec *= 10; + else + t2.tv_sec /= 10; + } - /* If this shell was compiled without job control support, if - the shell is not running interactively, if we are currently - in a subshell via `( xxx )', or if job control is not active - then the standard input for an asynchronous command is - forced to /dev/null. */ -#if defined (JOB_CONTROL) - if ((!interactive_shell || subshell_environment || !job_control) && - !stdin_redir) -#else - if (!stdin_redir) -#endif /* JOB_CONTROL */ - { - REDIRECT *tr; + return (t1.tv_sec / t2.tv_sec); +} +#endif /* HAVE_GETRUSAGE && HAVE_GETTIMEOFDAY */ - rd.filename = make_word ("/dev/null"); - tr = make_redirection (0, r_inputa_direction, rd); - tr->next = tc->redirects; - tc->redirects = tr; - } +#define POSIX_TIMEFORMAT "real %2R\nuser %2U\nsys %2S" +#define BASH_TIMEFORMAT "\nreal\t%3lR\nuser\t%3lU\nsys\t%3lS" - exec_result = execute_command_internal - (tc, 1, pipe_in, pipe_out, fds_to_close); +static int precs[] = { 0, 100, 10, 1 }; -#if defined (JOB_CONTROL) - if ((!interactive_shell || subshell_environment || !job_control) && - !stdin_redir) -#else - if (!stdin_redir) -#endif /* JOB_CONTROL */ - { - /* Remove the redirection we added above. It matters, - especially for loops, which call execute_command () - multiple times with the same command. */ - REDIRECT *tr, *tl; +/* Expand one `%'-prefixed escape sequence from a time format string. */ +static int +mkfmt (buf, prec, lng, sec, sec_fraction) + char *buf; + int prec, lng; + long sec; + int sec_fraction; +{ + long min; + char abuf[16]; + int ind, aind; - tr = tc->redirects; - do - { - tl = tc->redirects; - tc->redirects = tc->redirects->next; - } - while (tc->redirects && tc->redirects != rp); + ind = 0; + abuf[15] = '\0'; - tl->next = (REDIRECT *)NULL; - dispose_redirects (tr); - } + /* If LNG is non-zero, we want to decompose SEC into minutes and seconds. */ + if (lng) + { + min = sec / 60; + sec %= 60; + aind = 14; + do + abuf[aind--] = (min % 10) + '0'; + while (min /= 10); + aind++; + while (abuf[aind]) + buf[ind++] = abuf[aind++]; + buf[ind++] = 'm'; + } - { - register COMMAND *second; + /* Now add the seconds. */ + aind = 14; + do + abuf[aind--] = (sec % 10) + '0'; + while (sec /= 10); + aind++; + while (abuf[aind]) + buf[ind++] = abuf[aind++]; + + /* We want to add a decimal point and PREC places after it if PREC is + nonzero. PREC is not greater than 3. SEC_FRACTION is between 0 + and 999. */ + if (prec != 0) + { + buf[ind++] = '.'; + for (aind = 1; aind <= prec; aind++) + { + buf[ind++] = (sec_fraction / precs[aind]) + '0'; + sec_fraction %= precs[aind]; + } + } - second = command->value.Connection->second; + if (lng) + buf[ind++] = 's'; + buf[ind] = '\0'; - if (second) - { - if (ignore_return) - second->flags |= CMD_IGNORE_RETURN; + return (ind); +} - exec_result = execute_command_internal - (second, asynchronous, pipe_in, pipe_out, fds_to_close); - } - } - } - break; +/* Interpret the format string FORMAT, interpolating the following escape + sequences: + %[prec][l][RUS] + + where the optional `prec' is a precision, meaning the number of + characters after the decimal point, the optional `l' means to format + using minutes and seconds (MMmNN[.FF]s), like the `times' builtin', + and the last character is one of + + R number of seconds of `real' time + U number of seconds of `user' time + S number of seconds of `system' time + + An occurrence of `%%' in the format string is translated to a `%'. The + result is printed to FP, a pointer to a FILE. The other variables are + the seconds and thousandths of a second of real, user, and system time, + resectively. */ +static void +print_formatted_time (fp, format, rs, rsf, us, usf, ss, ssf, cpu) + FILE *fp; + char *format; + long rs, us, ss; + int rsf, usf, ssf, cpu; +{ + int prec, lng, len; + char *str, *s, ts[32]; + int sum, sum_frac; + int sindex, ssize; - case ';': - /* Just call execute command on both of them. */ - if (ignore_return) + len = strlen (format); + ssize = (len + 64) - (len % 64); + str = xmalloc (ssize); + sindex = 0; + + for (s = format; *s; s++) + { + if (*s != '%' || s[1] == '\0') + { + RESIZE_MALLOCED_BUFFER (str, sindex, 1, ssize, 64); + str[sindex++] = *s; + } + else if (s[1] == '%') + { + s++; + RESIZE_MALLOCED_BUFFER (str, sindex, 1, ssize, 64); + str[sindex++] = *s; + } + else if (s[1] == 'P') + { + s++; + if (cpu > 10000) + cpu = 10000; + sum = cpu / 100; + sum_frac = (cpu % 100) * 10; + len = mkfmt (ts, 2, 0, sum, sum_frac); + RESIZE_MALLOCED_BUFFER (str, sindex, len, ssize, 64); + strcpy (str + sindex, ts); + sindex += len; + } + else + { + prec = 3; /* default is three places past the decimal point. */ + lng = 0; /* default is to not use minutes or append `s' */ + s++; + if (isdigit (*s)) /* `precision' */ { - if (command->value.Connection->first) - command->value.Connection->first->flags |= CMD_IGNORE_RETURN; - if (command->value.Connection->second) - command->value.Connection->second->flags |= CMD_IGNORE_RETURN; + prec = *s++ - '0'; + if (prec > 3) prec = 3; } - QUIT; - execute_command (command->value.Connection->first); - QUIT; - exec_result = - execute_command_internal (command->value.Connection->second, - asynchronous, pipe_in, pipe_out, - fds_to_close); - break; - - case '|': - { - int prev, fildes[2], new_bitmap_size, dummyfd; - COMMAND *cmd; - struct fd_bitmap *fd_bitmap; + if (*s == 'l') /* `length extender' */ + { + lng = 1; + s++; + } + if (*s == 'R' || *s == 'E') + len = mkfmt (ts, prec, lng, rs, rsf); + else if (*s == 'U') + len = mkfmt (ts, prec, lng, us, usf); + else if (*s == 'S') + len = mkfmt (ts, prec, lng, ss, ssf); + else + { + internal_error ("bad format character in time format: %c", *s); + free (str); + return; + } + RESIZE_MALLOCED_BUFFER (str, sindex, len, ssize, 64); + strcpy (str + sindex, ts); + sindex += len; + } + } + + str[sindex] = '\0'; + fprintf (fp, "%s\n", str); + fflush (fp); + + free (str); +} + +static int +time_command (command, asynchronous, pipe_in, pipe_out, fds_to_close) + COMMAND *command; + int asynchronous, pipe_in, pipe_out; + struct fd_bitmap *fds_to_close; +{ + int rv, posix_time; + long rs, us, ss; + int rsf, usf, ssf; + int cpu; + char *time_format; + +#if defined (HAVE_GETRUSAGE) && defined (HAVE_GETTIMEOFDAY) + struct timeval real, user, sys; + struct timeval before, after; + struct timezone dtz; + struct rusage selfb, selfa, kidsb, kidsa; /* a = after, b = before */ +#else +# if defined (HAVE_TIMES) + clock_t tbefore, tafter, real, user, sys; + struct tms before, after; +# endif +#endif + +#if defined (HAVE_GETRUSAGE) && defined (HAVE_GETTIMEOFDAY) + gettimeofday (&before, &dtz); + getrusage (RUSAGE_SELF, &selfb); + getrusage (RUSAGE_CHILDREN, &kidsb); +#else +# if defined (HAVE_TIMES) + tbefore = times (&before); +# endif +#endif + + posix_time = (command->flags & CMD_TIME_POSIX); + + command->flags &= ~(CMD_TIME_PIPELINE|CMD_TIME_POSIX); + rv = execute_command_internal (command, asynchronous, pipe_in, pipe_out, fds_to_close); + +#if defined (HAVE_GETRUSAGE) && defined (HAVE_GETTIMEOFDAY) + gettimeofday (&after, &dtz); + getrusage (RUSAGE_SELF, &selfa); + getrusage (RUSAGE_CHILDREN, &kidsa); + + difftimeval (&real, &before, &after); + timeval_to_secs (&real, &rs, &rsf); + + addtimeval (&user, difftimeval(&after, &selfb.ru_utime, &selfa.ru_utime), + difftimeval(&before, &kidsb.ru_utime, &kidsa.ru_utime)); + timeval_to_secs (&user, &us, &usf); + + addtimeval (&sys, difftimeval(&after, &selfb.ru_stime, &selfa.ru_stime), + difftimeval(&before, &kidsb.ru_stime, &kidsa.ru_stime)); + timeval_to_secs (&sys, &ss, &ssf); + + cpu = timeval_to_cpu (&real, &user, &sys); +#else +# if defined (HAVE_TIMES) + tafter = times (&after); + + real = tafter - tbefore; + clock_t_to_secs (real, &rs, &rsf); + + user = (after.tms_utime - before.tms_utime) + (after.tms_cutime - before.tms_cutime); + clock_t_to_secs (user, &us, &usf); + + sys = (after.tms_stime - before.tms_stime) + (after.tms_cstime - before.tms_cstime); + clock_t_to_secs (sys, &ss, &ssf); + + cpu = ((user + sys) * 10000) / real; + +# else + rs = us = ss = 0L; + rsf = usf = ssf = cpu = 0; +# endif +#endif + + if (posix_time) + time_format = POSIX_TIMEFORMAT; + else if ((time_format = get_string_value ("TIMEFORMAT")) == 0) + time_format = BASH_TIMEFORMAT; + + if (time_format && *time_format) + print_formatted_time (stderr, time_format, rs, rsf, us, usf, ss, ssf, cpu); + + return rv; +} +#endif /* COMMAND_TIMING */ + +static int +execute_pipeline (command, asynchronous, pipe_in, pipe_out, fds_to_close) + COMMAND *command; + int asynchronous, pipe_in, pipe_out; + struct fd_bitmap *fds_to_close; +{ + int prev, fildes[2], new_bitmap_size, dummyfd, ignore_return, exec_result; + COMMAND *cmd; + struct fd_bitmap *fd_bitmap; #if defined (JOB_CONTROL) - sigset_t set, oset; - BLOCK_CHILD (set, oset); + sigset_t set, oset; + BLOCK_CHILD (set, oset); #endif /* JOB_CONTROL */ - prev = pipe_in; - cmd = command; + ignore_return = (command->flags & CMD_IGNORE_RETURN) != 0; - while (cmd && - cmd->type == cm_connection && - cmd->value.Connection && - cmd->value.Connection->connector == '|') - { - /* Make a pipeline between the two commands. */ - if (pipe (fildes) < 0) - { - report_error ("pipe error: %s", strerror (errno)); + prev = pipe_in; + cmd = command; + + while (cmd && cmd->type == cm_connection && + cmd->value.Connection && cmd->value.Connection->connector == '|') + { + /* Make a pipeline between the two commands. */ + if (pipe (fildes) < 0) + { + sys_error ("pipe error"); #if defined (JOB_CONTROL) - terminate_current_pipeline (); - kill_current_pipeline (); + terminate_current_pipeline (); + kill_current_pipeline (); #endif /* JOB_CONTROL */ - last_command_exit_value = EXECUTION_FAILURE; - /* The unwind-protects installed below will take care - of closing all of the open file descriptors. */ - throw_to_top_level (); - } - else - { - /* Here is a problem: with the new file close-on-exec - code, the read end of the pipe (fildes[0]) stays open - in the first process, so that process will never get a - SIGPIPE. There is no way to signal the first process - that it should close fildes[0] after forking, so it - remains open. No SIGPIPE is ever sent because there - is still a file descriptor open for reading connected - to the pipe. We take care of that here. This passes - around a bitmap of file descriptors that must be - closed after making a child process in - execute_simple_command. */ - - /* We need fd_bitmap to be at least as big as fildes[0]. - If fildes[0] is less than fds_to_close->size, then - use fds_to_close->size. */ - if (fildes[0] < fds_to_close->size) - new_bitmap_size = fds_to_close->size; - else - new_bitmap_size = fildes[0] + 8; - - fd_bitmap = new_fd_bitmap (new_bitmap_size); - - /* Now copy the old information into the new bitmap. */ - xbcopy ((char *)fds_to_close->bitmap, - (char *)fd_bitmap->bitmap, fds_to_close->size); - - /* And mark the pipe file descriptors to be closed. */ - fd_bitmap->bitmap[fildes[0]] = 1; - - /* In case there are pipe or out-of-processes errors, we - want all these file descriptors to be closed when - unwind-protects are run, and the storage used for the - bitmaps freed up. */ - begin_unwind_frame ("pipe-file-descriptors"); - add_unwind_protect (dispose_fd_bitmap, fd_bitmap); - add_unwind_protect (close_fd_bitmap, fd_bitmap); - if (prev >= 0) - add_unwind_protect (close, prev); - dummyfd = fildes[1]; - add_unwind_protect (close, dummyfd); + last_command_exit_value = EXECUTION_FAILURE; + /* The unwind-protects installed below will take care + of closing all of the open file descriptors. */ + throw_to_top_level (); + return (EXECUTION_FAILURE); /* XXX */ + } + + /* Here is a problem: with the new file close-on-exec + code, the read end of the pipe (fildes[0]) stays open + in the first process, so that process will never get a + SIGPIPE. There is no way to signal the first process + that it should close fildes[0] after forking, so it + remains open. No SIGPIPE is ever sent because there + is still a file descriptor open for reading connected + to the pipe. We take care of that here. This passes + around a bitmap of file descriptors that must be + closed after making a child process in execute_simple_command. */ + + /* We need fd_bitmap to be at least as big as fildes[0]. + If fildes[0] is less than fds_to_close->size, then + use fds_to_close->size. */ + new_bitmap_size = (fildes[0] < fds_to_close->size) + ? fds_to_close->size + : fildes[0] + 8; + + fd_bitmap = new_fd_bitmap (new_bitmap_size); + + /* Now copy the old information into the new bitmap. */ + xbcopy ((char *)fds_to_close->bitmap, (char *)fd_bitmap->bitmap, fds_to_close->size); + + /* And mark the pipe file descriptors to be closed. */ + fd_bitmap->bitmap[fildes[0]] = 1; + + /* In case there are pipe or out-of-processes errors, we + want all these file descriptors to be closed when + unwind-protects are run, and the storage used for the + bitmaps freed up. */ + begin_unwind_frame ("pipe-file-descriptors"); + add_unwind_protect (dispose_fd_bitmap, fd_bitmap); + add_unwind_protect (close_fd_bitmap, fd_bitmap); + if (prev >= 0) + add_unwind_protect (close, prev); + dummyfd = fildes[1]; + add_unwind_protect (close, dummyfd); #if defined (JOB_CONTROL) - add_unwind_protect (restore_signal_mask, oset); + add_unwind_protect (restore_signal_mask, oset); #endif /* JOB_CONTROL */ - if (ignore_return && cmd->value.Connection->first) - cmd->value.Connection->first->flags |= - CMD_IGNORE_RETURN; - execute_command_internal - (cmd->value.Connection->first, asynchronous, prev, - fildes[1], fd_bitmap); - - if (prev >= 0) - close (prev); - - prev = fildes[0]; - close (fildes[1]); - - dispose_fd_bitmap (fd_bitmap); - discard_unwind_frame ("pipe-file-descriptors"); - } - cmd = cmd->value.Connection->second; - } + if (ignore_return && cmd->value.Connection->first) + cmd->value.Connection->first->flags |= CMD_IGNORE_RETURN; + execute_command_internal (cmd->value.Connection->first, asynchronous, + prev, fildes[1], fd_bitmap); + + if (prev >= 0) + close (prev); + + prev = fildes[0]; + close (fildes[1]); + + dispose_fd_bitmap (fd_bitmap); + discard_unwind_frame ("pipe-file-descriptors"); - /* Now execute the rightmost command in the pipeline. */ - if (ignore_return && cmd) - cmd->flags |= CMD_IGNORE_RETURN; - exec_result = - execute_command_internal - (cmd, asynchronous, prev, pipe_out, fds_to_close); + cmd = cmd->value.Connection->second; + } + + /* Now execute the rightmost command in the pipeline. */ + if (ignore_return && cmd) + cmd->flags |= CMD_IGNORE_RETURN; + exec_result = execute_command_internal (cmd, asynchronous, prev, pipe_out, fds_to_close); - if (prev >= 0) - close (prev); + if (prev >= 0) + close (prev); #if defined (JOB_CONTROL) - UNBLOCK_CHILD (oset); + UNBLOCK_CHILD (oset); #endif - } - break; - case AND_AND: - case OR_OR: - if (asynchronous) + return (exec_result); +} + +static int +execute_connection (command, asynchronous, pipe_in, pipe_out, fds_to_close) + COMMAND *command; + int asynchronous, pipe_in, pipe_out; + struct fd_bitmap *fds_to_close; +{ + REDIRECT *tr, *tl, *rp; + COMMAND *tc, *second; + int ignore_return, exec_result; + + ignore_return = (command->flags & CMD_IGNORE_RETURN) != 0; + + switch (command->value.Connection->connector) + { + /* Do the first command asynchronously. */ + case '&': + tc = command->value.Connection->first; + if (tc == 0) + return (EXECUTION_SUCCESS); + + rp = tc->redirects; + + if (ignore_return && tc) + tc->flags |= CMD_IGNORE_RETURN; + + /* If this shell was compiled without job control support, if + the shell is not running interactively, if we are currently + in a subshell via `( xxx )', or if job control is not active + then the standard input for an asynchronous command is + forced to /dev/null. */ +#if defined (JOB_CONTROL) + if ((!interactive_shell || subshell_environment || !job_control) && !stdin_redir) +#else + if (!stdin_redir) +#endif /* JOB_CONTROL */ + { + rd.filename = make_bare_word ("/dev/null"); + tr = make_redirection (0, r_inputa_direction, rd); + tr->next = tc->redirects; + tc->redirects = tr; + } + + exec_result = execute_command_internal (tc, 1, pipe_in, pipe_out, fds_to_close); + +#if defined (JOB_CONTROL) + if ((!interactive_shell || subshell_environment || !job_control) && !stdin_redir) +#else + if (!stdin_redir) +#endif /* JOB_CONTROL */ + { + /* Remove the redirection we added above. It matters, + especially for loops, which call execute_command () + multiple times with the same command. */ + tr = tc->redirects; + do { - /* If we have something like `a && b &' or `a || b &', run the - && or || stuff in a subshell. Force a subshell and just call - execute_command_internal again. Leave asynchronous on - so that we get a report from the parent shell about the - background job. */ - command->flags |= CMD_FORCE_SUBSHELL; - exec_result = execute_command_internal (command, 1, pipe_in, - pipe_out, fds_to_close); - break; + tl = tc->redirects; + tc->redirects = tc->redirects->next; } + while (tc->redirects && tc->redirects != rp); - /* Execute the first command. If the result of that is successful - and the connector is AND_AND, or the result is not successful - and the connector is OR_OR, then execute the second command, - otherwise return. */ + tl->next = (REDIRECT *)NULL; + dispose_redirects (tr); + } - if (command->value.Connection->first) - command->value.Connection->first->flags |= CMD_IGNORE_RETURN; + second = command->value.Connection->second; + if (second) + { + if (ignore_return) + second->flags |= CMD_IGNORE_RETURN; - exec_result = execute_command (command->value.Connection->first); - QUIT; - if (((command->value.Connection->connector == AND_AND) && - (exec_result == EXECUTION_SUCCESS)) || - ((command->value.Connection->connector == OR_OR) && - (exec_result != EXECUTION_SUCCESS))) - { - if (ignore_return && command->value.Connection->second) - command->value.Connection->second->flags |= - CMD_IGNORE_RETURN; + exec_result = execute_command_internal (second, asynchronous, pipe_in, pipe_out, fds_to_close); + } - exec_result = - execute_command (command->value.Connection->second); - } - break; + break; - default: - programming_error ("Bad connector `%d'!", - command->value.Connection->connector); - longjmp (top_level, DISCARD); - break; + /* Just call execute command on both sides. */ + case ';': + if (ignore_return) + { + if (command->value.Connection->first) + command->value.Connection->first->flags |= CMD_IGNORE_RETURN; + if (command->value.Connection->second) + command->value.Connection->second->flags |= CMD_IGNORE_RETURN; } + QUIT; + execute_command (command->value.Connection->first); + QUIT; + exec_result = execute_command_internal (command->value.Connection->second, + asynchronous, pipe_in, pipe_out, + fds_to_close); break; - case cm_function_def: - exec_result = intern_function (command->value.Function_def->name, - command->value.Function_def->command); + case '|': + exec_result = execute_pipeline (command, asynchronous, pipe_in, pipe_out, fds_to_close); break; - default: - programming_error - ("execute_command: Bad command type `%d'!", command->type); - } + case AND_AND: + case OR_OR: + if (asynchronous) + { + /* If we have something like `a && b &' or `a || b &', run the + && or || stuff in a subshell. Force a subshell and just call + execute_command_internal again. Leave asynchronous on + so that we get a report from the parent shell about the + background job. */ + command->flags |= CMD_FORCE_SUBSHELL; + exec_result = execute_command_internal (command, 1, pipe_in, pipe_out, fds_to_close); + break; + } - if (my_undo_list) - { - do_redirections (my_undo_list, 1, 0, 0); - dispose_redirects (my_undo_list); - } + /* Execute the first command. If the result of that is successful + and the connector is AND_AND, or the result is not successful + and the connector is OR_OR, then execute the second command, + otherwise return. */ - if (exec_undo_list) - dispose_redirects (exec_undo_list); + if (command->value.Connection->first) + command->value.Connection->first->flags |= CMD_IGNORE_RETURN; - if (my_undo_list || exec_undo_list) - discard_unwind_frame ("loop_redirections"); + exec_result = execute_command (command->value.Connection->first); + QUIT; + if (((command->value.Connection->connector == AND_AND) && + (exec_result == EXECUTION_SUCCESS)) || + ((command->value.Connection->connector == OR_OR) && + (exec_result != EXECUTION_SUCCESS))) + { + if (ignore_return && command->value.Connection->second) + command->value.Connection->second->flags |= CMD_IGNORE_RETURN; - /* Invert the return value if we have to */ - if (invert) - { - if (exec_result == EXECUTION_SUCCESS) - exec_result = EXECUTION_FAILURE; - else - exec_result = EXECUTION_SUCCESS; + exec_result = execute_command (command->value.Connection->second); + } + break; + + default: + programming_error ("execute_connection: bad connector `%d'", command->value.Connection->connector); + jump_to_top_level (DISCARD); + exec_result = EXECUTION_FAILURE; } - last_command_exit_value = exec_result; - run_pending_traps (); - return (last_command_exit_value); + return exec_result; } #if defined (JOB_CONTROL) @@ -1009,22 +1416,27 @@ execute_command_internal (command, asynchronous, pipe_in, pipe_out, /* Execute a FOR command. The syntax is: FOR word_desc IN word_list; DO command; DONE */ +static int execute_for_command (for_command) FOR_COM *for_command; { - /* I just noticed that the Bourne shell leaves word_desc bound to the - last name in word_list after the FOR statement is done. This seems - wrong to me; I thought that the variable binding should be lexically - scoped, i.e., only would last the duration of the FOR command. This - behaviour can be gotten by turning on the lexical_scoping switch. */ - register WORD_LIST *releaser, *list; + SHELL_VAR *v; char *identifier; + int retval; +#if 0 SHELL_VAR *old_value = (SHELL_VAR *)NULL; /* Remember the old value of x. */ - int retval = EXECUTION_SUCCESS; +#endif if (check_identifier (for_command->name, 1) == 0) - return (EXECUTION_FAILURE); + { + if (posixly_correct && interactive_shell == 0) + { + last_command_exit_value = EX_USAGE; + jump_to_top_level (EXITPROG); + } + return (EXECUTION_FAILURE); + } loop_level++; identifier = for_command->name->word; @@ -1034,28 +1446,43 @@ execute_for_command (for_command) begin_unwind_frame ("for"); add_unwind_protect (dispose_words, releaser); +#if 0 if (lexical_scoping) { old_value = copy_variable (find_variable (identifier)); if (old_value) add_unwind_protect (dispose_variable, old_value); } +#endif if (for_command->flags & CMD_IGNORE_RETURN) for_command->action->flags |= CMD_IGNORE_RETURN; - while (list) + for (retval = EXECUTION_SUCCESS; list; list = list->next) { QUIT; - bind_variable (identifier, list->word->word); - execute_command (for_command->action); - retval = last_command_exit_value; + this_command_name = (char *)NULL; + v = bind_variable (identifier, list->word->word); + if (readonly_p (v)) + { + if (interactive_shell == 0 && posixly_correct) + { + last_command_exit_value = EXECUTION_FAILURE; + jump_to_top_level (FORCE_EOF); + } + else + { + run_unwind_frame ("for"); + return (EXECUTION_FAILURE); + } + } + retval = execute_command (for_command->action); REAP (); QUIT; if (breaking) { - breaking--; + breaking--; break; } @@ -1065,12 +1492,11 @@ execute_for_command (for_command) if (continuing) break; } - - list = list->next; } loop_level--; +#if 0 if (lexical_scoping) { if (!old_value) @@ -1084,6 +1510,7 @@ execute_for_command (for_command) dispose_variable (old_value); } } +#endif dispose_words (releaser); discard_unwind_frame ("for"); @@ -1115,10 +1542,8 @@ print_index_and_element (len, ind, list) if (list == 0) return (0); - i = ind; - l = list; - while (l && --i) - l = l->next; + for (i = ind, l = list; l && --i; l = l->next) + ; fprintf (stderr, "%*d%s%s", len, ind, RP_SPACE, l->word->word); return (STRLEN (l->word->word)); } @@ -1156,7 +1581,7 @@ print_select_list (list, list_len, max_elem_len, indices_len) return; } - cols = COLS / max_elem_len; + cols = max_elem_len ? COLS / max_elem_len : 1; if (cols == 0) cols = 1; rows = list_len ? list_len / cols + (list_len % cols != 0) : 1; @@ -1232,8 +1657,8 @@ select_query (list, list_len, prompt) while (1) { print_select_list (list, list_len, max_elem_len, indices_len); - printf ("%s", prompt); - fflush (stdout); + fprintf (stderr, "%s", prompt); + fflush (stderr); QUIT; if (read_builtin ((WORD_LIST *)NULL) == EXECUTION_FAILURE) @@ -1248,9 +1673,8 @@ select_query (list, list_len, prompt) if (reply < 1 || reply > list_len) return ""; - l = list; - while (l && --reply) - l = l->next; + for (l = list; l && --reply; l = l->next) + ; return (l->word->word); } } @@ -1259,18 +1683,14 @@ select_query (list, list_len, prompt) SELECT word IN list DO command_list DONE Only `break' or `return' in command_list will terminate the command. */ +static int execute_select_command (select_command) SELECT_COM *select_command; { WORD_LIST *releaser, *list; + SHELL_VAR *v; char *identifier, *ps3_prompt, *selection; int retval, list_len, return_val; -#if 0 - SHELL_VAR *old_value = (SHELL_VAR *)0; -#endif - - - retval = EXECUTION_SUCCESS; if (check_identifier (select_command->name, 1) == 0) return (EXECUTION_FAILURE); @@ -1292,18 +1712,11 @@ execute_select_command (select_command) begin_unwind_frame ("select"); add_unwind_protect (dispose_words, releaser); -#if 0 - if (lexical_scoping) - { - old_value = copy_variable (find_variable (identifier)); - if (old_value) - add_unwind_protect (dispose_variable, old_value); - } -#endif - if (select_command->flags & CMD_IGNORE_RETURN) select_command->action->flags |= CMD_IGNORE_RETURN; + retval = EXECUTION_SUCCESS; + unwind_protect_int (return_catch_flag); unwind_protect_jmp_buf (return_catch); return_catch_flag++; @@ -1311,7 +1724,7 @@ execute_select_command (select_command) while (1) { ps3_prompt = get_string_value ("PS3"); - if (!ps3_prompt) + if (ps3_prompt == 0) ps3_prompt = "#? "; QUIT; @@ -1319,8 +1732,21 @@ execute_select_command (select_command) QUIT; if (selection == 0) break; - else - bind_variable (identifier, selection); + + v = bind_variable (identifier, selection); + if (readonly_p (v)) + { + if (interactive_shell == 0 && posixly_correct) + { + last_command_exit_value = EXECUTION_FAILURE; + jump_to_top_level (FORCE_EOF); + } + else + { + run_unwind_frame ("select"); + return (EXECUTION_FAILURE); + } + } return_val = setjmp (return_catch); @@ -1344,22 +1770,6 @@ execute_select_command (select_command) loop_level--; -#if 0 - if (lexical_scoping) - { - if (!old_value) - makunbound (identifier, shell_variables); - else - { - SHELL_VAR *new_value; - - new_value = bind_variable (identifier, value_cell(old_value)); - new_value->attributes = old_value->attributes; - dispose_variable (old_value); - } - } -#endif - run_unwind_frame ("select"); return (retval); } @@ -1369,49 +1779,48 @@ execute_select_command (select_command) The pattern_list is a linked list of pattern clauses; each clause contains some patterns to compare word_desc against, and an associated command to execute. */ +static int execute_case_command (case_command) CASE_COM *case_command; { register WORD_LIST *list; - WORD_LIST *wlist; + WORD_LIST *wlist, *es; PATTERN_LIST *clauses; - char *word; - int retval; + char *word, *pattern; + int retval, match, ignore_return; /* Posix.2 specifies that the WORD is tilde expanded. */ if (member ('~', case_command->word->word)) { - word = tilde_expand (case_command->word->word); + word = bash_tilde_expand (case_command->word->word); free (case_command->word->word); case_command->word->word = word; } wlist = expand_word_no_split (case_command->word, 0); - clauses = case_command->clauses; - word = (wlist) ? string_list (wlist) : savestring (""); + word = wlist ? string_list (wlist) : savestring (""); + dispose_words (wlist); + retval = EXECUTION_SUCCESS; + ignore_return = case_command->flags & CMD_IGNORE_RETURN; begin_unwind_frame ("case"); - add_unwind_protect (dispose_words, wlist); add_unwind_protect ((Function *)xfree, word); - while (clauses) +#define EXIT_CASE() goto exit_case_command + + for (clauses = case_command->clauses; clauses; clauses = clauses->next) { QUIT; - list = clauses->patterns; - while (list) + for (list = clauses->patterns; list; list = list->next) { - char *pattern; - WORD_LIST *es; - int match; - /* Posix.2 specifies to tilde expand each member of the pattern list. */ if (member ('~', list->word->word)) { - char *expansion = tilde_expand (list->word->word); + pattern = bash_tilde_expand (list->word->word); free (list->word->word); - list->word->word = expansion; + list->word->word = pattern; } es = expand_word_leave_quoted (list->word, 0); @@ -1419,38 +1828,34 @@ execute_case_command (case_command) if (es && es->word && es->word->word && *(es->word->word)) pattern = quote_string_for_globbing (es->word->word, 1); else - pattern = savestring (""); + { + pattern = xmalloc (1); + pattern[0] = '\0'; + } /* Since the pattern does not undergo quote removal (as per Posix.2, section 3.9.4.3), the fnmatch () call must be able to recognize backslashes as escape characters. */ - match = (fnmatch (pattern, word, 0) != FNM_NOMATCH); + match = fnmatch (pattern, word, 0) != FNM_NOMATCH; free (pattern); dispose_words (es); if (match) { - if (clauses->action && - (case_command->flags & CMD_IGNORE_RETURN)) + if (clauses->action && ignore_return) clauses->action->flags |= CMD_IGNORE_RETURN; - execute_command (clauses->action); - retval = last_command_exit_value; - goto exit_command; + retval = execute_command (clauses->action); + EXIT_CASE (); } - list = list->next; QUIT; } - - clauses = clauses->next; } - exit_command: - dispose_words (wlist); - free (word); +exit_case_command: + free (word); discard_unwind_frame ("case"); - return (retval); } @@ -1460,6 +1865,7 @@ execute_case_command (case_command) /* The WHILE command. Syntax: WHILE test DO action; DONE. Repeatedly execute action while executing test produces EXECUTION_SUCCESS. */ +static int execute_while_command (while_command) WHILE_COM *while_command; { @@ -1467,6 +1873,7 @@ execute_while_command (while_command) } /* UNTIL is just like WHILE except that the test result is negated. */ +static int execute_until_command (while_command) WHILE_COM *while_command; { @@ -1478,6 +1885,7 @@ execute_until_command (while_command) CMD_WHILE or CMD_UNTIL. The return value for both commands should be EXECUTION_SUCCESS if no commands in the body are executed, and the status of the last command executed in the body otherwise. */ +static int execute_while_or_until (while_command, type) WHILE_COM *while_command; int type; @@ -1526,6 +1934,7 @@ execute_while_or_until (while_command, type) /* IF test THEN command [ELSE command]. IF also allows ELIF in the place of ELSE IF, but the parser makes *that* stupidity transparent. */ +static int execute_if_command (if_command) IF_COM *if_command; { @@ -1537,8 +1946,10 @@ execute_if_command (if_command) if (return_value == EXECUTION_SUCCESS) { QUIT; + if (if_command->true_case && (if_command->flags & CMD_IGNORE_RETURN)) - if_command->true_case->flags |= CMD_IGNORE_RETURN; + if_command->true_case->flags |= CMD_IGNORE_RETURN; + return (execute_command (if_command->true_case)); } else @@ -1558,39 +1969,117 @@ bind_lastarg (arg) { SHELL_VAR *var; - if (!arg) + if (arg == 0) arg = ""; var = bind_variable ("_", arg); var->attributes &= ~att_exported; } +/* Execute a null command. Fork a subshell if the command uses pipes or is + to be run asynchronously. This handles all the side effects that are + supposed to take place. */ +static int +execute_null_command (redirects, pipe_in, pipe_out, async, old_last_command_subst_pid) + REDIRECT *redirects; + int pipe_in, pipe_out, async, old_last_command_subst_pid; +{ + if (pipe_in != NO_PIPE || pipe_out != NO_PIPE || async) + { + /* We have a null command, but we really want a subshell to take + care of it. Just fork, do piping and redirections, and exit. */ + if (make_child ((char *)NULL, async) == 0) + { + /* Cancel traps, in trap.c. */ + restore_original_signals (); /* XXX */ + + do_piping (pipe_in, pipe_out); + + subshell_environment = SUBSHELL_ASYNC; + + if (do_redirections (redirects, 1, 0, 0) == 0) + exit (EXECUTION_SUCCESS); + else + exit (EXECUTION_FAILURE); + } + else + { + close_pipes (pipe_in, pipe_out); +#if defined (PROCESS_SUBSTITUTION) && defined (HAVE_DEV_FD) + unlink_fifo_list (); +#endif + return (EXECUTION_SUCCESS); + } + } + else + { + /* Even if there aren't any command names, pretend to do the + redirections that are specified. The user expects the side + effects to take place. If the redirections fail, then return + failure. Otherwise, if a command substitution took place while + expanding the command or a redirection, return the value of that + substitution. Otherwise, return EXECUTION_SUCCESS. */ + + if (do_redirections (redirects, 0, 0, 0) != 0) + return (EXECUTION_FAILURE); + else if (old_last_command_subst_pid != last_command_subst_pid) + return (last_command_exit_value); + else + return (EXECUTION_SUCCESS); + } +} + +/* This is a hack to suppress word splitting for assignment statements + given as arguments to builtins with the ASSIGNMENT_BUILTIN flag set. */ +static void +fix_assignment_words (words) + WORD_LIST *words; +{ + WORD_LIST *w; + struct builtin *b; + + if (words == 0) + return; + + b = builtin_address_internal (words->word->word); + if (b == 0 || (b->flags & ASSIGNMENT_BUILTIN) == 0) + return; + + for (w = words; w; w = w->next) + if (w->word->flags & W_ASSIGNMENT) + w->word->flags |= W_NOSPLIT; +} + /* The meaty part of all the executions. We have to start hacking the real execution of commands here. Fork a process, set things up, execute the command. */ +static int execute_simple_command (simple_command, pipe_in, pipe_out, async, fds_to_close) SIMPLE_COM *simple_command; int pipe_in, pipe_out, async; struct fd_bitmap *fds_to_close; { WORD_LIST *words, *lastword; - char *command_line, *lastarg; - int first_word_quoted, result; + char *command_line, *lastarg, *temp; + int first_word_quoted, result, builtin_is_special; pid_t old_last_command_subst_pid; + Function *builtin; + SHELL_VAR *func; result = EXECUTION_SUCCESS; + special_builtin_failed = builtin_is_special = 0; - /* If we're in a function, update the pseudo-line-number information. */ + /* If we're in a function, update the line number information. */ if (variable_context) line_number = simple_command->line - function_line_number; /* Remember what this command line looks like at invocation. */ command_string_index = 0; print_simple_command (simple_command); - command_line = (char *)alloca (1 + strlen (the_printed_command)); + command_line = xmalloc (1 + strlen (the_printed_command)); strcpy (command_line, the_printed_command); first_word_quoted = - simple_command->words ? simple_command->words->word->quoted : 0; + simple_command->words ? (simple_command->words->word->flags & W_QUOTED): 0; old_last_command_subst_pid = last_command_subst_pid; @@ -1599,249 +2088,251 @@ execute_simple_command (simple_command, pipe_in, pipe_out, async, fds_to_close) if ((simple_command->flags & CMD_INHIBIT_EXPANSION) == 0) { current_fds_to_close = fds_to_close; + fix_assignment_words (simple_command->words); words = expand_words (simple_command->words); current_fds_to_close = (struct fd_bitmap *)NULL; } else words = copy_word_list (simple_command->words); - lastarg = (char *)NULL; - /* It is possible for WORDS not to have anything left in it. Perhaps all the words consisted of `$foo', and there was no variable `$foo'. */ - if (words) + if (words == 0) { - Function *builtin; - SHELL_VAR *func; + result = execute_null_command (simple_command->redirects, + pipe_in, pipe_out, async, + old_last_command_subst_pid); + FREE (command_line); + bind_lastarg ((char *)NULL); + return (result); + } - begin_unwind_frame ("simple-command"); + lastarg = (char *)NULL; - if (echo_command_at_execute) - { - char *line = string_list (words); + begin_unwind_frame ("simple-command"); - if (line && *line) - fprintf (stderr, "%s%s\n", indirection_level_string (), line); + if (echo_command_at_execute) + xtrace_print_word_list (words); - FREE (line); + builtin = (Function *)NULL; + func = (SHELL_VAR *)NULL; + if ((simple_command->flags & CMD_NO_FUNCTIONS) == 0) + { + /* Posix.2 says special builtins are found before functions. We + don't set builtin_is_special anywhere other than here, because + this path is followed only when the `command' builtin is *not* + being used, and we don't want to exit the shell if a special + builtin executed with `command builtin' fails. `command' is not + a special builtin. */ + if (posixly_correct) + { + builtin = find_special_builtin (words->word->word); + if (builtin) + builtin_is_special = 1; } - - if (simple_command->flags & CMD_NO_FUNCTIONS) - func = (SHELL_VAR *)NULL; - else + if (builtin == 0) func = find_function (words->word->word); + } - add_unwind_protect (dispose_words, words); - - QUIT; + add_unwind_protect (dispose_words, words); + QUIT; - /* Bind the last word in this command to "$_" after execution. */ - for (lastword = words; lastword->next; lastword = lastword->next); - lastarg = lastword->word->word; + /* Bind the last word in this command to "$_" after execution. */ + for (lastword = words; lastword->next; lastword = lastword->next) + ; + lastarg = lastword->word->word; #if defined (JOB_CONTROL) - /* Is this command a job control related thing? */ - if (words->word->word[0] == '%') - { - int result; - - if (async) - this_command_name = "bg"; - else - this_command_name = "fg"; - - last_shell_builtin = this_shell_builtin; - this_shell_builtin = builtin_address (this_command_name); - result = (*this_shell_builtin) (words); - goto return_result; - } - - /* One other possiblilty. The user may want to resume an existing job. - If they do, find out whether this word is a candidate for a running - job. */ - { - char *auto_resume_value = get_string_value ("auto_resume"); - - if (auto_resume_value && - !first_word_quoted && - !words->next && - words->word->word[0] && - !simple_command->redirects && - pipe_in == NO_PIPE && - pipe_out == NO_PIPE && - !async) - { - char *word = words->word->word; - register int i; - int wl, cl, exact, substring, match, started_status; - register PROCESS *p; - - exact = STREQ (auto_resume_value, "exact"); - substring = STREQ (auto_resume_value, "substring"); - wl = strlen (word); - for (i = job_slots - 1; i > -1; i--) - { - if (!jobs[i] || (JOBSTATE (i) != JSTOPPED)) - continue; - - p = jobs[i]->pipe; - do - { - if (exact) - { - cl = strlen (p->command); - match = STREQN (p->command, word, cl); - } - else if (substring) - match = strindex (p->command, word) != (char *)0; - else - match = STREQN (p->command, word, wl); - - if (match == 0) - { - p = p->next; - continue; - } - - run_unwind_frame ("simple-command"); - last_shell_builtin = this_shell_builtin; - this_shell_builtin = builtin_address ("fg"); - - started_status = start_job (i, 1); - - if (started_status < 0) - return (EXECUTION_FAILURE); - else - return (started_status); - } - while (p != jobs[i]->pipe); - } - } - } -#endif /* JOB_CONTROL */ - - /* Remember the name of this command globally. */ - this_command_name = words->word->word; - - QUIT; - - /* This command could be a shell builtin or a user-defined function. - If so, and we have pipes, then fork a subshell in here. Else, just - do the command. */ - - if (func) - builtin = (Function *)NULL; - else - builtin = find_shell_builtin (this_command_name); - + /* Is this command a job control related thing? */ + if (words->word->word[0] == '%') + { + this_command_name = async ? "bg" : "fg"; last_shell_builtin = this_shell_builtin; - this_shell_builtin = builtin; + this_shell_builtin = builtin_address (this_command_name); + result = (*this_shell_builtin) (words); + goto return_result; + } - if (builtin || func) + /* One other possiblilty. The user may want to resume an existing job. + If they do, find out whether this word is a candidate for a running + job. */ + if (job_control && async == 0 && + !first_word_quoted && + !words->next && + words->word->word[0] && + !simple_command->redirects && + pipe_in == NO_PIPE && + pipe_out == NO_PIPE && + (temp = get_string_value ("auto_resume"))) + { + char *word; + register int i; + int wl, cl, exact, substring, match, started_status; + register PROCESS *p; + + word = words->word->word; + exact = STREQ (temp, "exact"); + substring = STREQ (temp, "substring"); + wl = strlen (word); + for (i = job_slots - 1; i > -1; i--) { - if ((pipe_in != NO_PIPE) || (pipe_out != NO_PIPE) || async) + if (jobs[i] == 0 || (JOBSTATE (i) != JSTOPPED)) + continue; + + p = jobs[i]->pipe; + do { - if (make_child (savestring (command_line), async) == 0) + if (exact) { - /* Cancel traps, in trap.c. */ - restore_original_signals (); - - if (async) - setup_async_signals (); - - execute_subshell_builtin_or_function - (words, simple_command->redirects, builtin, func, - pipe_in, pipe_out, async, fds_to_close, - simple_command->flags); + cl = strlen (p->command); + match = STREQN (p->command, word, cl); } + else if (substring) + match = strindex (p->command, word) != (char *)0; else + match = STREQN (p->command, word, wl); + + if (match == 0) { - close_pipes (pipe_in, pipe_out); -#if defined (PROCESS_SUBSTITUTION) && defined (HAVE_DEV_FD) - unlink_fifo_list (); -#endif - goto return_result; + p = p->next; + continue; } - } - else - { - result = execute_builtin_or_function - (words, builtin, func, simple_command->redirects, fds_to_close, - simple_command->flags); - goto return_result; + run_unwind_frame ("simple-command"); + this_command_name = "fg"; + last_shell_builtin = this_shell_builtin; + this_shell_builtin = builtin_address ("fg"); + + started_status = start_job (i, 1); + return ((started_status < 0) ? EXECUTION_FAILURE : started_status); } + while (p != jobs[i]->pipe); } + } +#endif /* JOB_CONTROL */ - execute_disk_command (words, simple_command->redirects, command_line, - pipe_in, pipe_out, async, fds_to_close, - (simple_command->flags & CMD_NO_FORK)); + /* Remember the name of this command globally. */ + this_command_name = words->word->word; - goto return_result; - } - else if (pipe_in != NO_PIPE || pipe_out != NO_PIPE || async) + QUIT; + + /* This command could be a shell builtin or a user-defined function. + We have already found special builtins by this time, so we do not + set builtin_is_special. If this is a function or builtin, and we + have pipes, then fork a subshell in here. Otherwise, just execute + the command directly. */ + if (func == 0 && builtin == 0) + builtin = find_shell_builtin (this_command_name); + + last_shell_builtin = this_shell_builtin; + this_shell_builtin = builtin; + + if (builtin || func) { - /* We have a null command, but we really want a subshell to take - care of it. Just fork, do piping and redirections, and exit. */ - if (make_child (savestring (""), async) == 0) + if ((pipe_in != NO_PIPE) || (pipe_out != NO_PIPE) || async) { - /* Cancel traps, in trap.c. */ - restore_original_signals (); - - do_piping (pipe_in, pipe_out); + if (make_child (command_line, async) == 0) + { + /* reset_terminating_signals (); */ /* XXX */ + /* Cancel traps, in trap.c. */ + restore_original_signals (); - subshell_environment = 1; + if (async) + setup_async_signals (); - if (do_redirections (simple_command->redirects, 1, 0, 0) == 0) - exit (EXECUTION_SUCCESS); + execute_subshell_builtin_or_function + (words, simple_command->redirects, builtin, func, + pipe_in, pipe_out, async, fds_to_close, + simple_command->flags); + } else - exit (EXECUTION_FAILURE); + { + close_pipes (pipe_in, pipe_out); +#if defined (PROCESS_SUBSTITUTION) && defined (HAVE_DEV_FD) + unlink_fifo_list (); +#endif + command_line = (char *)NULL; /* don't free this. */ + goto return_result; + } } else { - close_pipes (pipe_in, pipe_out); -#if defined (PROCESS_SUBSTITUTION) && defined (HAVE_DEV_FD) - unlink_fifo_list (); -#endif - result = EXECUTION_SUCCESS; + result = execute_builtin_or_function + (words, builtin, func, simple_command->redirects, fds_to_close, + simple_command->flags); + if (builtin) + { + if (result > EX_SHERRBASE) + { + result = builtin_status (result); + if (builtin_is_special) + special_builtin_failed = 1; + } + /* In POSIX mode, if there are assignment statements preceding + a special builtin, they persist after the builtin + completes. */ + if (posixly_correct && builtin_is_special && temporary_env) + merge_temporary_env (); + } + else /* function */ + { + if (result == EX_USAGE) + result = EX_BADUSAGE; + else if (result > EX_SHERRBASE) + result = EXECUTION_FAILURE; + } + goto return_result; } } - else - { - /* Even if there aren't any command names, pretend to do the - redirections that are specified. The user expects the side - effects to take place. If the redirections fail, then return - failure. Otherwise, if a command substitution took place while - expanding the command or a redirection, return the value of that - substitution. Otherwise, return EXECUTION_SUCCESS. */ - if (do_redirections (simple_command->redirects, 0, 0, 0) != 0) - result = EXECUTION_FAILURE; - else if (old_last_command_subst_pid != last_command_subst_pid) - result = last_command_exit_value; - else - result = EXECUTION_SUCCESS; - } + execute_disk_command (words, simple_command->redirects, command_line, + pipe_in, pipe_out, async, fds_to_close, + (simple_command->flags & CMD_NO_FORK)); return_result: bind_lastarg (lastarg); - /* The unwind-protect frame is set up only if WORDS is not empty. */ - if (words) - run_unwind_frame ("simple-command"); + FREE (command_line); + run_unwind_frame ("simple-command"); return (result); } +/* Translate the special builtin exit statuses. We don't really need a + function for this; it's a placeholder for future work. */ +static int +builtin_status (result) + int result; +{ + int r; + + switch (result) + { + case EX_USAGE: + r = EX_BADUSAGE; + break; + case EX_REDIRFAIL: + case EX_BADSYNTAX: + case EX_BADASSIGN: + case EX_EXPFAIL: + r = EXECUTION_FAILURE; + break; + default: + r = EXECUTION_SUCCESS; + break; + } + return (r); +} + static int execute_builtin (builtin, words, flags, subshell) Function *builtin; WORD_LIST *words; int flags, subshell; { - int old_e_flag = exit_immediately_on_error; - int result; + int old_e_flag, result; + old_e_flag = exit_immediately_on_error; /* The eval builtin calls parse_and_execute, which does not know about the setting of flags, and always calls the execution functions with flags that will exit the shell on an error if -e is set. If the @@ -1880,6 +2371,11 @@ execute_builtin (builtin, words, flags, subshell) if (subshell == 0 && builtin == source_builtin) { + /* In POSIX mode, if any variable assignments precede the `.' builtin, + they persist after the builtin completes, since `.' is a special + builtin. */ + if (posixly_correct && builtin_env) + merge_builtin_env (); dispose_builtin_env (); discard_unwind_frame ("builtin_env"); } @@ -1893,8 +2389,6 @@ execute_builtin (builtin, words, flags, subshell) return (result); } -/* XXX -- why do we need to set up unwind-protects for the case where - subshell == 1 at all? */ static int execute_function (var, words, flags, fds_to_close, async, subshell) SHELL_VAR *var; @@ -1904,36 +2398,44 @@ execute_function (var, words, flags, fds_to_close, async, subshell) { int return_val, result; COMMAND *tc, *fc; + char *debug_trap; tc = (COMMAND *)copy_command (function_cell (var)); if (tc && (flags & CMD_IGNORE_RETURN)) tc->flags |= CMD_IGNORE_RETURN; - if (subshell) - begin_unwind_frame ("subshell_function_calling"); - else - begin_unwind_frame ("function_calling"); - if (subshell == 0) { + begin_unwind_frame ("function_calling"); push_context (); add_unwind_protect (pop_context, (char *)NULL); unwind_protect_int (line_number); + unwind_protect_int (return_catch_flag); + unwind_protect_jmp_buf (return_catch); + add_unwind_protect (dispose_command, (char *)tc); + unwind_protect_int (loop_level); } - else - unwind_protect_int (variable_context); - unwind_protect_int (loop_level); - unwind_protect_int (return_catch_flag); - unwind_protect_jmp_buf (return_catch); - add_unwind_protect (dispose_command, (char *)tc); + debug_trap = (signal_is_trapped (DEBUG_TRAP) && signal_is_ignored (DEBUG_TRAP) == 0) + ? trap_list[DEBUG_TRAP] + : (char *)NULL; + if (debug_trap) + { + if (subshell == 0) + { + debug_trap = savestring (debug_trap); + add_unwind_protect (set_debug_trap, debug_trap); + } + restore_default_signal (DEBUG_TRAP); + } /* The temporary environment for a function is supposed to apply to all commands executed within the function body. */ if (temporary_env) { function_env = copy_array (temporary_env); - add_unwind_protect (dispose_function_env, (char *)NULL); + if (subshell == 0) + add_unwind_protect (dispose_function_env, (char *)NULL); dispose_used_env_vars (); } #if 0 @@ -1941,10 +2443,9 @@ execute_function (var, words, flags, fds_to_close, async, subshell) function_env = (char **)NULL; #endif - /* Note the second argument of "1", meaning that we discard - the current value of "$*"! This is apparently the right thing. */ remember_args (words->next, 1); + /* Number of the line on which the function body starts. */ line_number = function_line_number = tc->line; if (subshell) @@ -1952,10 +2453,7 @@ execute_function (var, words, flags, fds_to_close, async, subshell) #if defined (JOB_CONTROL) stop_pipeline (async, (COMMAND *)NULL); #endif - if (tc->type == cm_group) - fc = tc->value.Group->command; - else - fc = tc; + fc = (tc->type == cm_group) ? tc->value.Group->command : tc; if (fc && (flags & CMD_IGNORE_RETURN)) fc->flags |= CMD_IGNORE_RETURN; @@ -1973,9 +2471,7 @@ execute_function (var, words, flags, fds_to_close, async, subshell) else result = execute_command_internal (fc, 0, NO_PIPE, NO_PIPE, fds_to_close); - if (subshell) - run_unwind_frame ("subshell_function_calling"); - else + if (subshell == 0) run_unwind_frame ("function_calling"); return (result); @@ -1999,12 +2495,14 @@ execute_subshell_builtin_or_function (words, redirects, builtin, var, struct fd_bitmap *fds_to_close; int flags; { + int result, r; + /* A subshell is neither a login shell nor interactive. */ login_shell = interactive = 0; - subshell_environment = 1; + subshell_environment = SUBSHELL_ASYNC; - maybe_make_export_env (); + maybe_make_export_env (); /* XXX - is this needed? */ #if defined (JOB_CONTROL) /* Eradicate all traces of job control after we fork the subshell, so @@ -2033,8 +2531,6 @@ execute_subshell_builtin_or_function (words, redirects, builtin, var, if (builtin) { - int result; - /* Give builtins a place to jump back to on failure, so we don't go back up to main(). */ result = setjmp (top_level); @@ -2044,12 +2540,15 @@ execute_subshell_builtin_or_function (words, redirects, builtin, var, else if (result) exit (EXECUTION_FAILURE); else - exit (execute_builtin (builtin, words, flags, 1)); + { + r = execute_builtin (builtin, words, flags, 1); + if (r == EX_USAGE) + r = EX_BADUSAGE; + exit (r); + } } else - { - exit (execute_function (var, words, flags, fds_to_close, async, 1)); - } + exit (execute_function (var, words, flags, fds_to_close, async, 1)); } /* Execute a builtin or function in the current shell context. If BUILTIN @@ -2070,7 +2569,7 @@ execute_builtin_or_function (words, builtin, var, redirects, struct fd_bitmap *fds_to_close; int flags; { - int result = EXECUTION_FAILURE; + int result; REDIRECT *saved_undo_list; if (do_redirections (redirects, 1, 1, 0) != 0) @@ -2078,7 +2577,7 @@ execute_builtin_or_function (words, builtin, var, redirects, cleanup_redirects (redirection_undo_list); redirection_undo_list = (REDIRECT *)NULL; dispose_exec_redirects (); - return (EXECUTION_FAILURE); + return (EX_REDIRFAIL); /* was EXECUTION_FAILURE */ } saved_undo_list = redirection_undo_list; @@ -2096,8 +2595,7 @@ execute_builtin_or_function (words, builtin, var, redirects, if (saved_undo_list) { begin_unwind_frame ("saved redirects"); - add_unwind_protect (cleanup_func_redirects, (char *)saved_undo_list); - add_unwind_protect (dispose_redirects, (char *)saved_undo_list); + add_unwind_protect (cleanup_redirects, (char *)saved_undo_list); } redirection_undo_list = (REDIRECT *)NULL; @@ -2115,8 +2613,7 @@ execute_builtin_or_function (words, builtin, var, redirects, if (redirection_undo_list) { - do_redirections (redirection_undo_list, 1, 0, 0); - dispose_redirects (redirection_undo_list); + cleanup_redirects (redirection_undo_list); redirection_undo_list = (REDIRECT *)NULL; } @@ -2163,72 +2660,29 @@ execute_disk_command (words, redirects, command_line, pipe_in, pipe_out, struct fd_bitmap *fds_to_close; int nofork; /* Don't fork, just exec, if no pipes */ { - register char *pathname; - char *hashed_file, *command, **args; - int pid, temp_path; - SHELL_VAR *path; + char *pathname, *command, **args; + int pid; pathname = words->word->word; + #if defined (RESTRICTED_SHELL) if (restricted && strchr (pathname, '/')) { - report_error ("%s: restricted: cannot specify `/' in command names", + internal_error ("%s: restricted: cannot specify `/' in command names", pathname); last_command_exit_value = EXECUTION_FAILURE; return; } #endif /* RESTRICTED_SHELL */ - hashed_file = command = (char *)NULL; - - /* If PATH is in the temporary environment for this command, don't use the - hash table to search for the full pathname. */ - temp_path = 0; - path = find_tempenv_variable ("PATH"); - if (path) - temp_path = 1; - - /* Don't waste time trying to find hashed data for a pathname - that is already completely specified. */ - - if (!path && !absolute_program (pathname)) - hashed_file = find_hashed_filename (pathname); - - /* If a command found in the hash table no longer exists, we need to - look for it in $PATH. Thank you Posix.2. This forces us to stat - every command found in the hash table. It seems pretty stupid to me, - so I am basing it on the presence of POSIXLY_CORRECT. */ - - if (hashed_file && posixly_correct) - { - int st; - - st = file_status (hashed_file); - if ((st ^ (FS_EXISTS | FS_EXECABLE)) != 0) - { - remove_hashed_filename (pathname); - hashed_file = (char *)NULL; - } - } + command = search_for_command (pathname); - if (hashed_file) - command = savestring (hashed_file); - else if (absolute_program (pathname)) - /* A command containing a slash is not looked up in PATH or saved in - the hash table. */ - command = savestring (pathname); - else + if (command) { - command = find_user_command (pathname); - if (command && !hashing_disabled && !temp_path) - remember_filename (pathname, command, dot_found_in_search, 1); + maybe_make_export_env (); + put_command_name_into_env (command); } - maybe_make_export_env (); - - if (command) - put_command_name_into_env (command); - /* We have to make the child before we check for the non-existance of COMMAND, since we want the error messages to be redirected. */ /* If we can get away without forking and there are no pipes to deal with, @@ -2242,6 +2696,11 @@ execute_disk_command (words, redirects, command_line, pipe_in, pipe_out, { int old_interactive; +#if !defined (ARG_MAX) || ARG_MAX >= 10240 + if (posixly_correct == 0) + put_gnu_argv_flags_into_env ((int)getpid (), glob_argv_flags); +#endif + /* Cancel traps, in trap.c. */ restore_original_signals (); @@ -2253,23 +2712,18 @@ execute_disk_command (words, redirects, command_line, pipe_in, pipe_out, do_piping (pipe_in, pipe_out); - /* Execve expects the command name to be in args[0]. So we - leave it there, in the same format that the user used to - type it in. */ - args = make_word_array (words); - if (async) { old_interactive = interactive; interactive = 0; } - subshell_environment = 1; + subshell_environment = SUBSHELL_FORK; /* This functionality is now provided by close-on-exec of the file descriptors manipulated by redirection and piping. Some file descriptors still need to be closed in all children - because of the way bash does pipes; fds_to_close is a + because of the way bash does pipes; fds_to_close is a bitmap of all such file descriptors. */ if (fds_to_close) close_fd_bitmap (fds_to_close); @@ -2287,12 +2741,16 @@ execute_disk_command (words, redirects, command_line, pipe_in, pipe_out, if (async) interactive = old_interactive; - if (!command) + if (command == 0) { - report_error ("%s: command not found", args[0]); + internal_error ("%s: command not found", pathname); exit (EX_NOTFOUND); /* Posix.2 says the exit status is 127 */ } + /* Execve expects the command name to be in args[0]. So we + leave it there, in the same format that the user used to + type it in. */ + args = word_list_to_argv (words, 0, 0, (int *)NULL); exit (shell_execve (command, args, export_env)); } else @@ -2306,6 +2764,7 @@ execute_disk_command (words, redirects, command_line, pipe_in, pipe_out, } } +#if !defined (HAVE_HASH_BANG_EXEC) /* If the operating system on which we're running does not handle the #! executable format, then help out. SAMPLE is the text read from the file, SAMPLE_LEN characters. COMMAND is the name of @@ -2335,9 +2794,10 @@ execute_shell_script (sample, sample_len, command, args, env) i++) ; - execname = xmalloc (1 + (i - start)); - strncpy (execname, (char *) (sample + start), i - start); - execname[i - start] = '\0'; + larry = i - start; + execname = xmalloc (1 + larry); + strncpy (execname, (char *)(sample + start), larry); + execname[larry] = '\0'; size_increment = 1; /* Now the argument, if any. */ @@ -2355,9 +2815,10 @@ execute_shell_script (sample, sample_len, command, args, env) !whitespace (sample[i]) && sample[i] != '\n' && i < sample_len; i++) ; - firstarg = xmalloc (1 + (i - start)); - strncpy (firstarg, (char *)(sample + start), i - start); - firstarg[i - start] = '\0'; + larry = i - start; + firstarg = xmalloc (1 + larry); + strncpy (firstarg, (char *)(sample + start), larry); + firstarg[larry] = '\0'; size_increment = 2; } @@ -2382,6 +2843,13 @@ execute_shell_script (sample, sample_len, command, args, env) return (shell_execve (execname, args, env)); } +#endif /* !HAVE_HASH_BANG_EXEC */ + +#if defined (HAVE_SETOSTYPE) && defined (_POSIX_SOURCE) +# define SETOSTYPE(x) __setostype(x) +#else +# define SETOSTYPE(x) +#endif /* Call execve (), handling interpreting shell scripts, and handling exec failures. */ @@ -2390,130 +2858,170 @@ shell_execve (command, args, env) char *command; char **args, **env; { -#if defined (isc386) && defined (_POSIX_SOURCE) - __setostype (0); /* Turn on USGr3 semantics. */ - execve (command, args, env); - __setostype (1); /* Turn the POSIX semantics back on. */ -#else + struct stat finfo; + int larray, i, fd; + + SETOSTYPE (0); /* Some systems use for USG/POSIX semantics */ execve (command, args, env); -#endif /* !(isc386 && _POSIX_SOURCE) */ + SETOSTYPE (1); /* If we get to this point, then start checking out the file. Maybe it is something we can hack ourselves. */ - { - struct stat finfo; - - if (errno != ENOEXEC) - { - if ((stat (command, &finfo) == 0) && - (S_ISDIR (finfo.st_mode))) - report_error ("%s: is a directory", args[0]); - else + if (errno != ENOEXEC) + { + i = errno; + if ((stat (command, &finfo) == 0) && (S_ISDIR (finfo.st_mode))) + internal_error ("%s: is a directory", command); + else + { + errno = i; file_error (command); + } + return (EX_NOEXEC); /* XXX Posix.2 says that exit status is 126 */ + } - return (EX_NOEXEC); /* XXX Posix.2 says that exit status is 126 */ - } - else - { - /* This file is executable. - If it begins with #!, then help out people with losing operating - systems. Otherwise, check to see if it is a binary file by seeing - if the first line (or up to 30 characters) are in the ASCII set. - Execute the contents as shell commands. */ - int larray = array_len (args) + 1; - int i, should_exec = 0; - + /* This file is executable. + If it begins with #!, then help out people with losing operating + systems. Otherwise, check to see if it is a binary file by seeing + if the first line (or up to 80 characters) are in the ASCII set. + Execute the contents as shell commands. */ + fd = open (command, O_RDONLY); + if (fd >= 0) + { + unsigned char sample[80]; + int sample_len; + + sample_len = read (fd, (char *)sample, 80); + close (fd); + + if (sample_len == 0) + return (EXECUTION_SUCCESS); + + /* Is this supposed to be an executable script? + If so, the format of the line is "#! interpreter [argument]". + A single argument is allowed. The BSD kernel restricts + the length of the entire line to 32 characters (32 bytes + being the size of the BSD exec header), but we allow 80 + characters. */ + if (sample_len > 0) { - int fd = open (command, O_RDONLY); - if (fd != -1) +#if !defined (HAVE_HASH_BANG_EXEC) + if (sample[0] == '#' && sample[1] == '!') + return (execute_shell_script (sample, sample_len, command, args, env)); + else +#endif + if (check_binary_file (sample, sample_len)) { - unsigned char sample[80]; - int sample_len = read (fd, &sample[0], 80); - - close (fd); - - if (sample_len == 0) - return (EXECUTION_SUCCESS); - - /* Is this supposed to be an executable script? - If so, the format of the line is "#! interpreter [argument]". - A single argument is allowed. The BSD kernel restricts - the length of the entire line to 32 characters (32 bytes - being the size of the BSD exec header), but we allow 80 - characters. */ - - if (sample_len > 0 && sample[0] == '#' && sample[1] == '!') - return (execute_shell_script - (sample, sample_len, command, args, env)); - else if ((sample_len != -1) && - check_binary_file (sample, sample_len)) - { - report_error ("%s: cannot execute binary file", command); - return (EX_BINARY_FILE); - } + internal_error ("%s: cannot execute binary file", command); + return (EX_BINARY_FILE); } } -#if defined (JOB_CONTROL) - /* Forget about the way that job control was working. We are - in a subshell. */ - without_job_control (); -#endif /* JOB_CONTROL */ + } + + larray = array_len (args) + 1; + #if defined (ALIAS) - /* Forget about any aliases that we knew of. We are in a subshell. */ - delete_all_aliases (); + /* Forget about any aliases that we knew of. We are in a subshell. */ + delete_all_aliases (); #endif /* ALIAS */ +#if defined (HISTORY) + /* Forget about the history lines we have read. This is a non-interactive + subshell. */ + history_lines_this_session = 0; +#endif + #if defined (JOB_CONTROL) - set_sigchld_handler (); + /* Forget about the way job control was working. We are in a subshell. */ + without_job_control (); + set_sigchld_handler (); #endif /* JOB_CONTROL */ - set_sigint_handler (); - /* Insert the name of this shell into the argument list. */ - args = (char **)xrealloc ((char *)args, (1 + larray) * sizeof (char *)); + /* If we're not interactive, close the file descriptor from which we're + reading the current shell script. */ +#if defined (BUFFERED_INPUT) + if (interactive_shell == 0 && default_buffered_input >= 0) + { + close_buffered_fd (default_buffered_input); + default_buffered_input = bash_input.location.buffered_fd = -1; + } +#else + if (interactive_shell == 0 && default_input) + { + fclose (default_input); + default_input = (FILE *)NULL; + } +#endif - for (i = larray - 1; i; i--) - args[i] = args[i - 1]; + set_sigint_handler (); - args[0] = shell_name; - args[1] = command; - args[larray] = (char *)NULL; + /* Insert the name of this shell into the argument list. */ + args = (char **)xrealloc ((char *)args, (1 + larray) * sizeof (char *)); - if (args[0][0] == '-') - args[0]++; + for (i = larray - 1; i; i--) + args[i] = args[i - 1]; - if (should_exec) - { - struct stat finfo; + args[0] = shell_name; + args[1] = command; + args[larray] = (char *)NULL; -#if defined (isc386) && defined (_POSIX_SOURCE) - __setostype (0); /* Turn on USGr3 semantics. */ - execve (shell_name, args, env); - __setostype (1); /* Turn the POSIX semantics back on. */ -#else - execve (shell_name, args, env); -#endif /* isc386 && _POSIX_SOURCE */ + if (args[0][0] == '-') + args[0]++; - /* Oh, no! We couldn't even exec this! */ - if ((stat (args[0], &finfo) == 0) && (S_ISDIR (finfo.st_mode))) - report_error ("%s: is a directory", args[0]); - else - file_error (args[0]); +#if defined (RESTRICTED_SHELL) + if (restricted) + change_flag ('r', FLAG_OFF); +#endif - return (EXECUTION_FAILURE); - } - else - { - subshell_argc = larray; - subshell_argv = args; - subshell_envp = env; - longjmp (subshell_top_level, 1); - } - } - } + if (subshell_argv) + { + /* Can't free subshell_argv[0]; that is shell_name. */ + for (i = 1; i < subshell_argc; i++) + free (subshell_argv[i]); + free (subshell_argv); + } + + dispose_command (currently_executing_command); /* XXX */ + currently_executing_command = (COMMAND *)NULL; + + subshell_argc = larray; + subshell_argv = args; + subshell_envp = env; + + unbind_args (); /* remove the positional parameters */ + + longjmp (subshell_top_level, 1); +} + +static int +execute_intern_function (name, function) + WORD_DESC *name; + COMMAND *function; +{ + SHELL_VAR *var; + + if (check_identifier (name, posixly_correct) == 0) + { + if (posixly_correct && interactive_shell == 0) + { + last_command_exit_value = EX_USAGE; + jump_to_top_level (EXITPROG); + } + return (EXECUTION_FAILURE); + } + + var = find_function (name->word); + if (var && readonly_p (var)) + { + internal_error ("%s: readonly function", var->name); + return (EXECUTION_FAILURE); + } + + bind_function (name->word, function); + return (EXECUTION_SUCCESS); } #if defined (PROCESS_SUBSTITUTION) -/* Currently unused */ void close_all_files () { @@ -2547,8 +3055,7 @@ do_piping (pipe_in, pipe_out) if (pipe_in != NO_PIPE) { if (dup2 (pipe_in, 0) < 0) - internal_error ("cannot duplicate fd %d to fd 0: %s", - pipe_in, strerror (errno)); + sys_error ("cannot duplicate fd %d to fd 0", pipe_in); if (pipe_in > 0) close (pipe_in); } @@ -2557,19 +3064,64 @@ do_piping (pipe_in, pipe_out) if (pipe_out != REDIRECT_BOTH) { if (dup2 (pipe_out, 1) < 0) - internal_error ("cannot duplicate fd %d to fd 1: %s", - pipe_out, strerror (errno)); + sys_error ("cannot duplicate fd %d to fd 1", pipe_out); if (pipe_out == 0 || pipe_out > 1) close (pipe_out); } else - dup2 (1, 2); + if (dup2 (1, 2) < 0) + sys_error ("cannot duplicate fd 1 to fd 2"); } } -#define AMBIGUOUS_REDIRECT -1 -#define NOCLOBBER_REDIRECT -2 -#define RESTRICTED_REDIRECT -3 /* Only can happen in restricted shells. */ +static void +redirection_error (temp, error) + REDIRECT *temp; + int error; +{ + char *filename; + + if (expandable_redirection_filename (temp)) + { + if (posixly_correct && !interactive_shell) + disallow_filename_globbing++; + filename = redirection_expand (temp->redirectee.filename); + if (posixly_correct && !interactive_shell) + disallow_filename_globbing--; + if (filename == 0) + filename = savestring (temp->redirectee.filename->word); + if (filename == 0) + { + filename = xmalloc (1); + filename[0] = '\0'; + } + } + else + filename = itos (temp->redirectee.dest); + + switch (error) + { + case AMBIGUOUS_REDIRECT: + internal_error ("%s: ambiguous redirect", filename); + break; + + case NOCLOBBER_REDIRECT: + internal_error ("%s: cannot overwrite existing file", filename); + break; + +#if defined (RESTRICTED_SHELL) + case RESTRICTED_REDIRECT: + internal_error ("%s: restricted: cannot redirect output", filename); + break; +#endif /* RESTRICTED_SHELL */ + + default: + internal_error ("%s: %s", filename, strerror (error)); + break; + } + + FREE (filename); +} /* Perform the redirections on LIST. If FOR_REAL, then actually make input and output file descriptors, otherwise just do whatever is @@ -2582,8 +3134,8 @@ do_redirections (list, for_real, internal, set_clexec) REDIRECT *list; int for_real, internal, set_clexec; { - register int error; - register REDIRECT *temp = list; + int error; + REDIRECT *temp; if (internal) { @@ -2596,54 +3148,14 @@ do_redirections (list, for_real, internal, set_clexec) dispose_exec_redirects (); } - while (temp) + for (temp = list; temp; temp = temp->next) { error = do_redirection_internal (temp, for_real, internal, set_clexec); - if (error) { - char *filename; - - if (expandable_redirection_filename (temp)) - { - if (posixly_correct && !interactive_shell) - disallow_filename_globbing++; - filename = redirection_expand (temp->redirectee.filename); - if (posixly_correct && !interactive_shell) - disallow_filename_globbing--; - - if (!filename) - filename = savestring (""); - } - else - filename = itos (temp->redirectee.dest); - - switch (error) - { - case AMBIGUOUS_REDIRECT: - report_error ("%s: Ambiguous redirect", filename); - break; - - case NOCLOBBER_REDIRECT: - report_error ("%s: Cannot clobber existing file", filename); - break; - -#if defined (RESTRICTED_SHELL) - case RESTRICTED_REDIRECT: - report_error ("%s: output redirection restricted", filename); - break; -#endif /* RESTRICTED_SHELL */ - - default: - report_error ("%s: %s", filename, strerror (error)); - break; - } - - free (filename); + redirection_error (temp, error); return (error); } - - temp = temp->next; } return (0); } @@ -2654,8 +3166,6 @@ static int expandable_redirection_filename (redirect) REDIRECT *redirect; { - int result; - switch (redirect->instruction) { case r_output_direction: @@ -2667,15 +3177,13 @@ expandable_redirection_filename (redirect) case r_output_force: case r_duplicating_input_word: case r_duplicating_output_word: - result = 1; - break; + return 1; default: - result = 0; + return 0; } - return (result); } - + /* Expand the word in WORD returning a string. If WORD expands to multiple words (or no words), then return NULL. */ char * @@ -2689,17 +3197,86 @@ redirection_expand (word) tlist2 = expand_words_no_vars (tlist1); dispose_words (tlist1); - if (!tlist2 || tlist2->next) + if (!tlist2 || tlist2->next) + { + /* We expanded to no words, or to more than a single word. + Dispose of the word list and return NULL. */ + if (tlist2) + dispose_words (tlist2); + return ((char *)NULL); + } + result = string_list (tlist2); /* XXX savestring (tlist2->word->word)? */ + dispose_words (tlist2); + return (result); +} + +static int +write_here_document (fd, redirectee) + int fd; + WORD_DESC *redirectee; +{ + char *document; + int document_len, fd2; + FILE *fp; + register WORD_LIST *t, *tlist; + + /* Expand the text if the word that was specified had + no quoting. The text that we expand is treated + exactly as if it were surrounded by double quotes. */ + + if (redirectee->flags & W_QUOTED) + { + document = redirectee->word; + document_len = strlen (document); + /* Set errno to something reasonable if the write fails. */ + if (write (fd, document, document_len) < document_len) + { + if (errno == 0) + errno = ENOSPC; + return (errno); + } + else + return 0; + } + + tlist = expand_string (redirectee->word, Q_HERE_DOCUMENT); + if (tlist) { - /* We expanded to no words, or to more than a single word. - Dispose of the word list and return NULL. */ - if (tlist2) - dispose_words (tlist2); - return ((char *)NULL); + /* Try using buffered I/O (stdio) and writing a word + at a time, letting stdio do the work of buffering + for us rather than managing our own strings. Most + stdios are not particularly fast, however -- this + may need to be reconsidered later. */ + if ((fd2 = dup (fd)) < 0 || (fp = fdopen (fd2, "w")) == NULL) + { + if (fd2 >= 0) + close (fd2); + return (errno); + } + errno = 0; + for (t = tlist; t; t = t->next) + { + /* This is essentially the body of + string_list_internal expanded inline. */ + document = t->word->word; + document_len = strlen (document); + if (t != tlist) + putc (' ', fp); /* separator */ + fwrite (document, document_len, 1, fp); + if (ferror (fp)) + { + if (errno == 0) + errno = ENOSPC; + fd2 = errno; + fclose(fp); + dispose_words (tlist); + return (fd2); + } + } + fclose (fp); + dispose_words (tlist); } - result = string_list (tlist2); - dispose_words (tlist2); - return (result); + return 0; } /* Do the specific redirection requested. Returns errno in case of error. @@ -2712,12 +3289,17 @@ do_redirection_internal (redirect, for_real, remembering, set_clexec) REDIRECT *redirect; int for_real, remembering, set_clexec; { - WORD_DESC *redirectee = redirect->redirectee.filename; - int redir_fd = redirect->redirectee.dest; - int fd, redirector = redirect->redirector; + WORD_DESC *redirectee; + int redir_fd, fd, redirector, r; char *redirectee_word; - enum r_instruction ri = redirect->instruction; + enum r_instruction ri; REDIRECT *new_redirect; + struct stat finfo; + + redirectee = redirect->redirectee.filename; + redir_fd = redirect->redirectee.dest; + redirector = redirect->redirector; + ri = redirect->instruction; if (ri == r_duplicating_input_word || ri == r_duplicating_output_word) { @@ -2725,7 +3307,9 @@ do_redirection_internal (redirect, for_real, remembering, set_clexec) the redirection into a new one and continue. */ redirectee_word = redirection_expand (redirectee); - if (redirectee_word[0] == '-' && redirectee_word[1] == '\0') + if (redirectee_word == 0) + return (AMBIGUOUS_REDIRECT); + else if (redirectee_word[0] == '-' && redirectee_word[1] == '\0') { rd.dest = 0L; new_redirect = make_redirection (redirector, r_close_this, rd); @@ -2745,9 +3329,9 @@ do_redirection_internal (redirect, for_real, remembering, set_clexec) } else if (ri == r_duplicating_output_word && redirector == 1) { - if (!posixly_correct) + if (posixly_correct == 0) { - rd.filename = make_word (redirectee_word); + rd.filename = make_bare_word (redirectee_word); new_redirect = make_redirection (1, r_err_and_out, rd); } else @@ -2800,22 +3384,17 @@ do_redirection_internal (redirect, for_real, remembering, set_clexec) case r_err_and_out: /* command &>filename */ case r_input_output: case r_output_force: - if (posixly_correct && !interactive_shell) disallow_filename_globbing++; redirectee_word = redirection_expand (redirectee); if (posixly_correct && !interactive_shell) disallow_filename_globbing--; - - if (!redirectee_word) + + if (redirectee_word == 0) return (AMBIGUOUS_REDIRECT); #if defined (RESTRICTED_SHELL) - if (restricted && (ri == r_output_direction || - ri == r_input_output || - ri == r_err_and_out || - ri == r_appending_to || - ri == r_output_force)) + if (restricted && (WRITE_REDIRECT (ri))) { free (redirectee_word); return (RESTRICTED_REDIRECT); @@ -2824,16 +3403,11 @@ do_redirection_internal (redirect, for_real, remembering, set_clexec) /* If we are in noclobber mode, you are not allowed to overwrite existing files. Check first. */ - if (noclobber && (ri == r_output_direction || - ri == r_input_output || - ri == r_err_and_out)) + if (noclobber && OUTPUT_REDIRECT (ri)) { - struct stat finfo; - int stat_result; + r = stat (redirectee_word, &finfo); - stat_result = stat (redirectee_word, &finfo); - - if ((stat_result == 0) && (S_ISREG (finfo.st_mode))) + if (r == 0 && (S_ISREG (finfo.st_mode))) { free (redirectee_word); return (NOCLOBBER_REDIRECT); @@ -2841,12 +3415,12 @@ do_redirection_internal (redirect, for_real, remembering, set_clexec) /* If the file was not present, make sure we open it exclusively so that if it is created before we open it, our open will fail. */ - if (stat_result != 0) + if (r != 0) redirect->flags |= O_EXCL; fd = open (redirectee_word, redirect->flags, 0666); - if ((fd < 0) && (errno == EEXIST)) + if (fd < 0 && errno == EEXIST) { free (redirectee_word); return (NOCLOBBER_REDIRECT); @@ -2855,10 +3429,10 @@ do_redirection_internal (redirect, for_real, remembering, set_clexec) else { fd = open (redirectee_word, redirect->flags, 0666); -#if defined (AFS_CREATE_BUG) +#if defined (AFS) if ((fd < 0) && (errno == EACCES)) - fd = open (redirectee_word, (redirect->flags & ~O_CREAT), 0666); -#endif /* AFS_CREATE_BUG */ + fd = open (redirectee_word, redirect->flags & ~O_CREAT, 0666); +#endif /* AFS */ } free (redirectee_word); @@ -2906,8 +3480,7 @@ do_redirection_internal (redirect, for_real, remembering, set_clexec) if (fd != redirector) { #if defined (BUFFERED_INPUT) - if (ri == r_input_direction || ri == r_inputa_direction || - ri == r_input_output) + if (INPUT_REDIRECT (ri)) close_buffered_fd (fd); else #endif /* !BUFFERED_INPUT */ @@ -2934,97 +3507,34 @@ do_redirection_internal (redirect, for_real, remembering, set_clexec) the new input. Place it in a temporary file. */ if (redirectee) { - char filename[40]; - pid_t pid = getpid (); + char filename[24]; /* Make the filename for the temp file. */ - sprintf (filename, "/tmp/t%d-sh", pid); + sprintf (filename, "/tmp/t%d-sh", (int)getpid ()); fd = open (filename, O_TRUNC | O_WRONLY | O_CREAT, 0666); if (fd < 0) return (errno); - errno = 0; /* XXX */ + errno = r = 0; /* XXX */ if (redirectee->word) - { - char *document; - int document_len; - - /* Expand the text if the word that was specified had - no quoting. The text that we expand is treated - exactly as if it were surrounded by double quotes. */ - - if (redirectee->quoted) - { - document = redirectee->word; - document_len = strlen (document); - /* Set errno to something reasonable if the write fails. */ - if (write (fd, document, document_len) < document_len) - { - if (errno == 0) - errno = ENOSPC; - close (fd); - return (errno); - } - } - else - { - WORD_LIST *tlist; - tlist = expand_string (redirectee->word, Q_HERE_DOCUMENT); - if (tlist) - { - int fd2; - FILE *fp; - register WORD_LIST *t; - - /* Try using buffered I/O (stdio) and writing a word - at a time, letting stdio do the work of buffering - for us rather than managing our own strings. Most - stdios are not particularly fast, however -- this - may need to be reconsidered later. */ - if ((fd2 = dup (fd)) < 0 || - (fp = fdopen (fd2, "w")) == NULL) - { - if (fd2 >= 0) - close (fd2); - close (fd); - return (errno); - } - errno = 0; /* XXX */ - for (t = tlist; t; t = t->next) - { - /* This is essentially the body of - string_list_internal expanded inline. */ - document = t->word->word; - document_len = strlen (document); - if (t != tlist) - putc (' ', fp); /* separator */ - fwrite (document, document_len, 1, fp); - if (ferror (fp)) - { - if (errno == 0) - errno = ENOSPC; - break; - } - } - fclose (fp); - dispose_words (tlist); - } - } - } + r = write_here_document (fd, redirectee); close (fd); - if (errno) - return (errno); + if (r) + return (r); /* Make the document really temporary. Also make it the input. */ fd = open (filename, O_RDONLY, 0666); - if (unlink (filename) < 0 || fd < 0) + if (fd < 0) + return (errno); + + if (unlink (filename) < 0) { - if (fd >= 0) - close (fd); - return (errno); + r = errno; + close (fd); + return (r); } if (for_real) @@ -3039,10 +3549,11 @@ do_redirection_internal (redirect, for_real, remembering, set_clexec) #if defined (BUFFERED_INPUT) check_bash_input (redirector); #endif - if (dup2 (fd, redirector) < 0) + if (fd != redirector && dup2 (fd, redirector) < 0) { + r = errno; close (fd); - return (errno); + return (r); } #if defined (BUFFERED_INPUT) @@ -3127,47 +3638,44 @@ add_undo_redirect (fd) int fd; { int new_fd, clexec_flag; - REDIRECT *new_redirect, *closer; + REDIRECT *new_redirect, *closer, *dummy_redirect; new_fd = fcntl (fd, F_DUPFD, SHELL_FD_BASE); if (new_fd < 0) { - file_error ("redirection error"); + sys_error ("redirection error"); return (-1); } - else - { - REDIRECT *dummy_redirect; - - clexec_flag = fcntl (fd, F_GETFD, 0); - rd.dest = 0L; - closer = make_redirection (new_fd, r_close_this, rd); - dummy_redirect = copy_redirects (closer); + clexec_flag = fcntl (fd, F_GETFD, 0); - rd.dest = (long)new_fd; - new_redirect = make_redirection (fd, r_duplicating_output, rd); - new_redirect->next = closer; + rd.dest = 0L; + closer = make_redirection (new_fd, r_close_this, rd); + dummy_redirect = copy_redirects (closer); - closer->next = redirection_undo_list; - redirection_undo_list = new_redirect; + rd.dest = (long)new_fd; + new_redirect = make_redirection (fd, r_duplicating_output, rd); + new_redirect->next = closer; - /* Save redirections that need to be undone even if the undo list - is thrown away by the `exec' builtin. */ - add_exec_redirect (dummy_redirect); + closer->next = redirection_undo_list; + redirection_undo_list = new_redirect; + + /* Save redirections that need to be undone even if the undo list + is thrown away by the `exec' builtin. */ + add_exec_redirect (dummy_redirect); + + /* File descriptors used only for saving others should always be + marked close-on-exec. Unfortunately, we have to preserve the + close-on-exec state of the file descriptor we are saving, since + fcntl (F_DUPFD) sets the new file descriptor to remain open + across execs. If, however, the file descriptor whose state we + are saving is <= 2, we can just set the close-on-exec flag, + because file descriptors 0-2 should always be open-on-exec, + and the restore above in do_redirection() will take care of it. */ + if (clexec_flag || fd < 3) + SET_CLOSE_ON_EXEC (new_fd); - /* File descriptors used only for saving others should always be - marked close-on-exec. Unfortunately, we have to preserve the - close-on-exec state of the file descriptor we are saving, since - fcntl (F_DUPFD) sets the new file descriptor to remain open - across execs. If, however, the file descriptor whose state we - are saving is <= 2, we can just set the close-on-exec flag, - because file descriptors 0-2 should always be open-on-exec, - and the restore above in do_redirection() will take care of it. */ - if (clexec_flag || fd < 3) - SET_CLOSE_ON_EXEC (new_fd); - } return (0); } @@ -3193,26 +3701,6 @@ add_exec_redirect (dummy_redirect) exec_redirection_undo_list = dummy_redirect; } -intern_function (name, function) - WORD_DESC *name; - COMMAND *function; -{ - SHELL_VAR *var; - - if (!check_identifier (name, posixly_correct)) - return (EXECUTION_FAILURE); - - var = find_function (name->word); - if (var && readonly_p (var)) - { - report_error ("%s: readonly function", var->name); - return (EXECUTION_FAILURE); - } - - bind_function (name->word, function); - return (EXECUTION_SUCCESS); -} - #define u_mode_bits(x) (((x) & 0000700) >> 6) #define g_mode_bits(x) (((x) & 0000070) >> 3) #define o_mode_bits(x) (((x) & 0000007) >> 0) @@ -3236,7 +3724,7 @@ file_status (name) /* If the file is a directory, then it is not "executable" in the sense of the shell. */ if (S_ISDIR (finfo.st_mode)) - return (FS_EXISTS); + return (FS_EXISTS|FS_DIRECTORY); #if defined (AFS) /* We have to use access(2) to determine access because AFS does not @@ -3280,8 +3768,8 @@ file_status (name) since we are also `others'. */ if (X_BIT (o_mode_bits (finfo.st_mode))) return (FS_EXISTS | FS_EXECABLE); - else - return (FS_EXISTS); + + return (FS_EXISTS); #endif /* !AFS */ } @@ -3293,7 +3781,17 @@ int executable_file (file) char *file; { - return (file_status (file) & FS_EXECABLE); + int s; + + s = file_status (file); + return ((s & FS_EXECABLE) && ((s & FS_DIRECTORY) == 0)); +} + +int +is_directory (file) + char *file; +{ + return (file_status (file) & FS_DIRECTORY); } /* DOT_FOUND_IN_SEARCH becomes non-zero when find_user_command () @@ -3311,7 +3809,7 @@ char * find_user_command (name) char *name; { - return (find_user_command_internal (name, FS_EXEC_PREFERRED)); + return (find_user_command_internal (name, FS_EXEC_PREFERRED|FS_NODIRS)); } /* Locate the file referenced by NAME, searching along the contents @@ -3326,7 +3824,7 @@ find_path_file (name) } static char * -find_user_command_internal (name, flags) +_find_user_command_internal (name, flags) char *name; int flags; { @@ -3335,7 +3833,7 @@ find_user_command_internal (name, flags) /* Search for the value of PATH in both the temporary environment, and in the regular list of variables. */ - if (var = find_variable_internal ("PATH", 1)) + if (var = find_variable_internal ("PATH", 1)) /* XXX could be array? */ path_list = value_cell (var); else path_list = (char *)NULL; @@ -3346,6 +3844,27 @@ find_user_command_internal (name, flags) return (find_user_command_in_path (name, path_list, flags)); } +static char * +find_user_command_internal (name, flags) + char *name; + int flags; +{ +#ifdef __WIN32__ + char *res, *dotexe; + + dotexe = xmalloc (strlen (name) + 5); + strcpy (dotexe, name); + strcat (dotexe, ".exe"); + res = _find_user_command_internal (dotexe, flags); + free (dotexe); + if (res == 0) + res = _find_user_command_internal (name, flags); + return res; +#else + return (_find_user_command_internal (name, flags)); +#endif +} + /* Return the next element from PATH_LIST, a colon separated list of paths. PATH_INDEX_POINTER is the address of an index into PATH_LIST; the index is modified by this function. @@ -3372,60 +3891,130 @@ get_next_path_element (path_list, path_index_pointer) } char * +search_for_command (pathname) + char *pathname; +{ + char *hashed_file, *command; + int temp_path, st; + SHELL_VAR *path; + + hashed_file = command = (char *)NULL; + + /* If PATH is in the temporary environment for this command, don't use the + hash table to search for the full pathname. */ + path = find_tempenv_variable ("PATH"); + temp_path = path != 0; + + /* Don't waste time trying to find hashed data for a pathname + that is already completely specified or if we're using a command- + specific value for PATH. */ + if (path == 0 && absolute_program (pathname) == 0) + hashed_file = find_hashed_filename (pathname); + + /* If a command found in the hash table no longer exists, we need to + look for it in $PATH. Thank you Posix.2. This forces us to stat + every command found in the hash table. */ + + if (hashed_file && (posixly_correct || check_hashed_filenames)) + { + st = file_status (hashed_file); + if ((st ^ (FS_EXISTS | FS_EXECABLE)) != 0) + { + remove_hashed_filename (pathname); + hashed_file = (char *)NULL; + } + } + + if (hashed_file) + command = savestring (hashed_file); + else if (absolute_program (pathname)) + /* A command containing a slash is not looked up in PATH or saved in + the hash table. */ + command = savestring (pathname); + else + { + /* If $PATH is in the temporary environment, we've already retrieved + it, so don't bother trying again. */ + if (temp_path) + command = find_user_command_in_path (pathname, value_cell (path), + FS_EXEC_PREFERRED|FS_NODIRS); + else + command = find_user_command (pathname); + if (command && hashing_enabled && temp_path == 0) + remember_filename (pathname, command, dot_found_in_search, 1); + } + return (command); +} + +char * user_command_matches (name, flags, state) char *name; int flags, state; { register int i; - char *path_list; - int path_index; - char *path_element; - char *match; + int path_index, name_len; + char *path_list, *path_element, *match; + struct stat dotinfo; static char **match_list = NULL; static int match_list_size = 0; static int match_index = 0; - if (!state) + if (state == 0) { /* Create the list of matches. */ - if (!match_list) + if (match_list == 0) { - match_list = - (char **) xmalloc ((match_list_size = 5) * sizeof(char *)); - - for (i = 0; i < match_list_size; i++) - match_list[i] = 0; + match_list_size = 5; + match_list = (char **)xmalloc (match_list_size * sizeof(char *)); } /* Clear out the old match list. */ for (i = 0; i < match_list_size; i++) - match_list[i] = NULL; + match_list[i] = 0; /* We haven't found any files yet. */ match_index = 0; - path_list = get_string_value ("PATH"); - path_index = 0; + if (absolute_program (name)) + { + match_list[0] = find_absolute_program (name, flags); + match_list[1] = (char *)NULL; + path_list = (char *)NULL; + } + else + { + name_len = strlen (name); + file_to_lose_on = (char *)NULL; + dot_found_in_search = 0; + stat (".", &dotinfo); + path_list = get_string_value ("PATH"); + path_index = 0; + } while (path_list && path_list[path_index]) { path_element = get_next_path_element (path_list, &path_index); - if (!path_element) + if (path_element == 0) break; - match = find_user_command_in_path (name, path_element, flags); + match = find_in_path_element (name, path_element, flags, name_len, &dotinfo); free (path_element); - if (!match) + if (match == 0) continue; if (match_index + 1 == match_list_size) - match_list = (char **)xrealloc - (match_list, ((match_list_size += 10) + 1) * sizeof (char *)); + { + match_list_size += 10; + match_list = (char **)xrealloc (match_list, (match_list_size + 1) * sizeof (char *)); + } + match_list[match_index++] = match; match_list[match_index] = (char *)NULL; + FREE (file_to_lose_on); + file_to_lose_on = (char *)NULL; } /* We haven't returned any strings yet. */ @@ -3440,33 +4029,6 @@ user_command_matches (name, flags, state) return (match); } -/* Return 1 if PATH1 and PATH2 are the same file. This is kind of - expensive. If non-NULL STP1 and STP2 point to stat structures - corresponding to PATH1 and PATH2, respectively. */ -int -same_file (path1, path2, stp1, stp2) - char *path1, *path2; - struct stat *stp1, *stp2; -{ - struct stat st1, st2; - - if (stp1 == NULL) - { - if (stat (path1, &st1) != 0) - return (0); - stp1 = &st1; - } - - if (stp2 == NULL) - { - if (stat (path2, &st2) != 0) - return (0); - stp2 = &st2; - } - - return ((stp1->st_dev == stp2->st_dev) && (stp1->st_ino == stp2->st_ino)); -} - /* Turn PATH, a directory, and NAME, a filename, into a full pathname. This allocates new memory and returns it. */ static char * @@ -3484,8 +4046,92 @@ make_full_pathname (path, name, name_len) strcpy (full_path + path_len + 1, name); return (full_path); } - -/* This does the dirty work for find_path_file () and find_user_command (). + +static char * +find_absolute_program (name, flags) + char *name; + int flags; +{ + int st; + + st = file_status (name); + + /* If the file doesn't exist, quit now. */ + if ((st & FS_EXISTS) == 0) + return ((char *)NULL); + + /* If we only care about whether the file exists or not, return + this filename. Otherwise, maybe we care about whether this + file is executable. If it is, and that is what we want, return it. */ + if ((flags & FS_EXISTS) || ((flags & FS_EXEC_ONLY) && (st & FS_EXECABLE))) + return (savestring (name)); + + return ((char *)NULL); +} + +static char * +find_in_path_element (name, path, flags, name_len, dotinfop) + char *name, *path; + int flags, name_len; + struct stat *dotinfop; +{ + int status; + char *full_path, *xpath; + + xpath = (*path == '~') ? bash_tilde_expand (path) : path; + + /* Remember the location of "." in the path, in all its forms + (as long as they begin with a `.', e.g. `./.') */ + if (dot_found_in_search == 0 && *xpath == '.') + dot_found_in_search = same_file (".", xpath, dotinfop, (struct stat *)NULL); + + full_path = make_full_pathname (xpath, name, name_len); + + status = file_status (full_path); + + if (xpath != path) + free (xpath); + + if ((status & FS_EXISTS) == 0) + { + free (full_path); + return ((char *)NULL); + } + + /* The file exists. If the caller simply wants the first file, here it is. */ + if (flags & FS_EXISTS) + return (full_path); + + /* If the file is executable, then it satisfies the cases of + EXEC_ONLY and EXEC_PREFERRED. Return this file unconditionally. */ + if ((status & FS_EXECABLE) && + (((flags & FS_NODIRS) == 0) || ((status & FS_DIRECTORY) == 0))) + { + FREE (file_to_lose_on); + file_to_lose_on = (char *)NULL; + return (full_path); + } + + /* The file is not executable, but it does exist. If we prefer + an executable, then remember this one if it is the first one + we have found. */ + if ((flags & FS_EXEC_PREFERRED) && file_to_lose_on == 0) + file_to_lose_on = savestring (full_path); + + /* If we want only executable files, or we don't want directories and + this file is a directory, fail. */ + if ((flags & FS_EXEC_ONLY) || (flags & FS_EXEC_PREFERRED) || + ((flags & FS_NODIRS) && (status & FS_DIRECTORY))) + { + free (full_path); + return ((char *)NULL); + } + else + return (full_path); +} + +/* This does the dirty work for find_user_command_internal () and + user_command_matches (). NAME is the name of the file to search for. PATH_LIST is a colon separated list of directories to search. FLAGS contains bit fields which control the files which are eligible. @@ -3494,6 +4140,7 @@ make_full_pathname (path, name, name_len) FS_EXEC_PREFERRED: If we can't find an executable, then the the first file matching NAME will do. FS_EXISTS: The first file found will do. + FS_NODIRS: Don't find any directories. */ static char * find_user_command_in_path (name, path_list, flags) @@ -3501,18 +4148,9 @@ find_user_command_in_path (name, path_list, flags) char *path_list; int flags; { - char *full_path, *path, *file_to_lose_on; - int status, path_index, name_len; - struct stat finfo; - - name_len = strlen (name); - - /* The file name which we would try to execute, except that it isn't - possible to execute it. This is the first file that matches the - name that we are looking for while we are searching $PATH for a - suitable one to execute. If we cannot find a suitable executable - file, then we use this one. */ - file_to_lose_on = (char *)NULL; + char *full_path, *path; + int path_index, name_len; + struct stat dotinfo; /* We haven't started looking, so we certainly haven't seen a `.' as the directory path yet. */ @@ -3520,94 +4158,45 @@ find_user_command_in_path (name, path_list, flags) if (absolute_program (name)) { - full_path = xmalloc (1 + name_len); - strcpy (full_path, name); - - status = file_status (full_path); - - /* If the file doesn't exist, quit now. */ - if (!(status & FS_EXISTS)) - { - free (full_path); - return ((char *)NULL); - } - - /* If we only care about whether the file exists or not, return - this filename. */ - if (flags & FS_EXISTS) - return (full_path); - - /* Otherwise, maybe we care about whether this file is executable. - If it is, and that is what we want, return it. */ - if ((flags & FS_EXEC_ONLY) && (status & FS_EXECABLE)) - return (full_path); - else - { - free (full_path); - return ((char *)NULL); - } + full_path = find_absolute_program (name, flags); + return (full_path); } - /* Find out the location of the current working directory. */ - stat (".", &finfo); + if (path_list == 0 || *path_list == '\0') + return (savestring (name)); /* XXX */ + file_to_lose_on = (char *)NULL; + name_len = strlen (name); + stat (".", &dotinfo); path_index = 0; - while (path_list && path_list[path_index]) + + while (path_list[path_index]) { /* Allow the user to interrupt out of a lengthy path search. */ QUIT; path = get_next_path_element (path_list, &path_index); - - if (!path) + if (path == 0) break; - if (*path == '~') - { - char *t = tilde_expand (path); - free (path); - path = t; - } - - /* Remember the location of "." in the path, in all its forms - (as long as they begin with a `.', e.g. `./.') */ - if (!dot_found_in_search && (*path == '.') && - same_file (".", path, &finfo, (struct stat *)NULL)) - dot_found_in_search = 1; - - full_path = make_full_pathname (path, name, name_len); + /* Side effects: sets dot_found_in_search, possibly sets + file_to_lose_on. */ + full_path = find_in_path_element (name, path, flags, name_len, &dotinfo); free (path); - status = file_status (full_path); - - if (!(status & FS_EXISTS)) - goto next_file; - - /* The file exists. If the caller simply wants the first file, - here it is. */ - if (flags & FS_EXISTS) - return (full_path); - - /* If the file is executable, then it satisfies the cases of - EXEC_ONLY and EXEC_PREFERRED. Return this file unconditionally. */ - if (status & FS_EXECABLE) + /* This should really be in find_in_path_element, but there isn't the + right combination of flags. */ + if (full_path && is_directory (full_path)) { - FREE (file_to_lose_on); - - return (full_path); + free (full_path); + continue; } - /* The file is not executable, but it does exist. If we prefer - an executable, then remember this one if it is the first one - we have found. */ - if (flags & FS_EXEC_PREFERRED) + if (full_path) { - if (!file_to_lose_on) - file_to_lose_on = savestring (full_path); + FREE (file_to_lose_on); + return (full_path); } - - next_file: - free (full_path); } /* We didn't find exactly what the user was looking for. Return @@ -3616,83 +4205,3 @@ find_user_command_in_path (name, path_list, flags) search would accept a non-executable as a last resort. */ return (file_to_lose_on); } - -/* Given a string containing units of information separated by colons, - return the next one pointed to by (P_INDEX), or NULL if there are no more. - Advance (P_INDEX) to the character after the colon. */ -char * -extract_colon_unit (string, p_index) - char *string; - int *p_index; -{ - int i, start; - - i = *p_index; - - if (!string || (i >= (int)strlen (string))) - return ((char *)NULL); - - /* Each call to this routine leaves the index pointing at a colon if - there is more to the path. If I is > 0, then increment past the - `:'. If I is 0, then the path has a leading colon. Trailing colons - are handled OK by the `else' part of the if statement; an empty - string is returned in that case. */ - if (i && string[i] == ':') - i++; - - start = i; - - while (string[i] && string[i] != ':') i++; - - *p_index = i; - - if (i == start) - { - if (string[i]) - (*p_index)++; - - /* Return "" in the case of a trailing `:'. */ - return (savestring ("")); - } - else - { - char *value; - - value = xmalloc (1 + i - start); - strncpy (value, string + start, i - start); - value [i - start] = '\0'; - - return (value); - } -} - -/* Return non-zero if the characters from SAMPLE are not all valid - characters to be found in the first line of a shell script. We - check up to the first newline, or SAMPLE_LEN, whichever comes first. - All of the characters must be printable or whitespace. */ - -#if !defined (isspace) -#define isspace(c) ((c) == ' ' || (c) == '\t' || (c) == '\n' || (c) == '\f') -#endif - -#if !defined (isprint) -#define isprint(c) (isletter(c) || digit(c) || ispunct(c)) -#endif - -int -check_binary_file (sample, sample_len) - unsigned char *sample; - int sample_len; -{ - register int i; - - for (i = 0; i < sample_len; i++) - { - if (sample[i] == '\n') - break; - - if (!isspace (sample[i]) && !isprint (sample[i])) - return (1); - } - return (0); -} diff --git a/execute_cmd.h b/execute_cmd.h index e096103..19e0b63 100644 --- a/execute_cmd.h +++ b/execute_cmd.h @@ -26,18 +26,18 @@ extern struct fd_bitmap *new_fd_bitmap __P((long)); extern void dispose_fd_bitmap __P((struct fd_bitmap *)); extern void close_fd_bitmap __P((struct fd_bitmap *)); +extern int executing_line_number __P((void)); extern int execute_command __P((COMMAND *)); extern int execute_command_internal __P((COMMAND *, int, int, int, struct fd_bitmap *)); extern int shell_execve __P((char *, char **, char **)); extern char *redirection_expand __P((WORD_DESC *)); extern int file_status __P((char *)); extern int executable_file __P((char *)); +extern int is_directory __P((char *)); +extern char *search_for_command __P((char *)); extern char *find_user_command __P((char *)); extern char *find_path_file __P((char *)); extern char *user_command_matches __P((char *, int, int)); -extern int same_file __P((char *, char *, struct stat *, struct stat *)); -extern char *extract_colon_unit __P((char *, int *)); -extern int check_binary_file __P((unsigned char *, int)); extern void setup_async_signals __P((void)); #if defined (PROCESS_SUBSTITUTION) diff --git a/expr.c b/expr.c index 5f9eb6d..eb08054 100644 --- a/expr.c +++ b/expr.c @@ -37,7 +37,10 @@ "|" "&&" "||" - "=" + "expr ? expr : expr" + "=", "*=", "/=", "%=", + "+=", "-=", "<<=", ">>=", + "&=", "^=", "|=" (Note that most of these operators have special meaning to bash, and an entire expression should be quoted, e.g. "a=$a+1" or "a=a+1" to ensure @@ -61,55 +64,26 @@ chet@ins.CWRU.Edu */ +#include "config.h" + #include #include "bashansi.h" -#include "shell.h" +#if defined (HAVE_UNISTD_H) +# include +#endif -#define variable_starter(c) (isletter(c) || (c == '_')) -#define variable_character(c) (isletter(c) || (c == '_') || digit(c)) +#include "shell.h" /* Because of the $((...)) construct, expressions may include newlines. Here is a macro which accepts newlines, tabs and spaces as whitespace. */ #define cr_whitespace(c) (whitespace(c) || ((c) == '\n')) -extern char *this_command_name; - -static char *expression = (char *) NULL; /* The current expression */ -static char *tp = (char *) NULL; /* token lexical position */ -static char *lasttp; -static int curtok = 0; /* the current token */ -static int lasttok = 0; /* the previous token */ -static int assigntok = 0; /* the OP in OP= */ -static char *tokstr = (char *) NULL; /* current token string */ -static int tokval = 0; /* current token value */ -static jmp_buf evalbuf; - -static void readtok (); /* lexical analyzer */ -static long expassign (), exp0 (), exp1 (), exp2 (), exp3 (), - exp4 (), exp5 (), expshift (), expland (), explor (), - expband (), expbor (), expbxor (); -static long strlong (); -static void evalerror (); - -/* A structure defining a single expression context. */ -typedef struct { - int curtok, lasttok; - char *expression, *tp; - int tokval; - char *tokstr; -} EXPR_CONTEXT; - -/* Global var which contains the stack of expression contexts. */ -static EXPR_CONTEXT **expr_stack; -static int expr_depth = 0; /* Location in the stack. */ -static int expr_stack_size = 0; /* Number of slots already allocated. */ - /* Size be which the expression stack grows when neccessary. */ #define EXPR_STACK_GROW_SIZE 10 /* Maximum amount of recursion allowed. This prevents a non-integer variable such as "num=num+2" from infinitely adding to itself when - "let num=num+2" is given. I have to talk to Chet about this hack. */ + "let num=num+2" is given. */ #define MAX_EXPR_RECURSION_LEVEL 1024 /* The Tokens. Singing "The Lion Sleeps Tonight". */ @@ -125,6 +99,7 @@ static int expr_stack_size = 0; /* Number of slots already allocated. */ #define LSH 9 /* "<<" Left SHift */ #define RSH 10 /* ">>" Right SHift */ #define OP_ASSIGN 11 /* op= expassign as in Posix.2 */ +#define COND 12 #define EQ '=' #define GT '>' #define LT '<' @@ -137,9 +112,44 @@ static int expr_stack_size = 0; /* Number of slots already allocated. */ #define LPAR '(' #define RPAR ')' #define BAND '&' /* Bitwise AND */ -#define BOR '|' /* Either Bitwise OR, or what Chet is. */ +#define BOR '|' /* Bitwise OR. */ #define BXOR '^' /* Bitwise eXclusive OR. */ #define BNOT '~' /* Bitwise NOT; Two's complement. */ +#define QUES '?' +#define COL ':' + +static char *expression; /* The current expression */ +static char *tp; /* token lexical position */ +static char *lasttp; /* pointer to last token position */ +static int curtok; /* the current token */ +static int lasttok; /* the previous token */ +static int assigntok; /* the OP in OP= */ +static char *tokstr; /* current token string */ +static int tokval; /* current token value */ +static int noeval; /* set to 1 if no assignment to be done */ +static procenv_t evalbuf; + +static void readtok (); /* lexical analyzer */ +static long expassign (), exp0 (), exp1 (), exp2 (), exp3 (), + exp4 (), exp5 (), expshift (), expland (), explor (), + expband (), expbor (), expbxor (), expcond (); +static long strlong (); +static void evalerror (); + +/* A structure defining a single expression context. */ +typedef struct { + int curtok, lasttok; + char *expression, *tp; + int tokval; + char *tokstr; +} EXPR_CONTEXT; + +/* Global var which contains the stack of expression contexts. */ +static EXPR_CONTEXT **expr_stack; +static int expr_depth; /* Location in the stack. */ +static int expr_stack_size; /* Number of slots already allocated. */ + +extern char *this_command_name; /* Push and save away the contents of the globals describing the current expression context. */ @@ -177,7 +187,7 @@ popexp () EXPR_CONTEXT *context; if (expr_depth == 0) - evalerror ("Recursion stack underflow"); + evalerror ("recursion stack underflow"); context = expr_stack[--expr_depth]; curtok = context->curtok; @@ -194,7 +204,7 @@ popexp () The `while' loop after the longjmp is caught relies on the above implementation of pushexp and popexp leaving in expr_stack[0] the values that the variables had when the program started. That is, - the first things saved are the initial values of the variables that + the first things saved are the initial values of the variables that were assigned at program startup or by the compiler. Therefore, it is safe to let the loop terminate when expr_depth == 0, without freeing up any of the expr_depth[0] stuff. */ @@ -203,7 +213,7 @@ evalexp (expr) char *expr; { long val = 0L; - jmp_buf old_evalbuf; + procenv_t old_evalbuf; char *p; for (p = expr; p && *p && cr_whitespace (*p); p++) @@ -214,7 +224,7 @@ evalexp (expr) /* Save the value of evalbuf to protect it around possible recursive calls to evalexp (). */ - xbcopy ((char *)evalbuf, (char *)old_evalbuf, sizeof (jmp_buf)); + COPY_PROCENV (evalbuf, old_evalbuf); if (setjmp (evalbuf)) { @@ -232,7 +242,7 @@ evalexp (expr) if (expr_stack[expr_depth]->expression) free (expr_stack[expr_depth]->expression); } - longjmp (top_level, DISCARD); + jump_to_top_level (DISCARD); } pushexp (); @@ -247,7 +257,7 @@ evalexp (expr) val = expassign (); - if (curtok != 0) + if (curtok != 0) evalerror ("syntax error in expression"); if (tokstr) @@ -259,7 +269,7 @@ evalexp (expr) /* Restore the value of evalbuf so that any subsequent longjmp calls will have a valid location to jump to. */ - xbcopy ((char *)old_evalbuf, (char *)evalbuf, sizeof (jmp_buf)); + COPY_PROCENV (old_evalbuf, evalbuf); return (val); } @@ -299,15 +309,16 @@ expassign () register long value; char *lhs, *rhs; - value = explor (); + value = expcond (); if (curtok == EQ || curtok == OP_ASSIGN) { - int special = curtok == OP_ASSIGN; - int op; + int special, op; long lvalue; + special = curtok == OP_ASSIGN; + if (lasttok != STR) - evalerror ("attempted expassign to non-variable"); + evalerror ("attempted assignment to non-variable"); if (special) { @@ -351,14 +362,15 @@ expassign () lvalue |= value; break; default: - evalerror ("bug: bad expassign token %d", assigntok); + evalerror ("bug: bad expassign token"); break; } value = lvalue; } rhs = itos (value); - bind_int_variable (lhs, rhs); + if (noeval == 0) + bind_int_variable (lhs, rhs); free (rhs); free (lhs); free (tokstr); @@ -367,6 +379,42 @@ expassign () return (value); } +/* Conditional expression (expr?expr:expr) */ +static long +expcond () +{ + long cval, val1, val2, rval; + rval = cval = explor (); + if (curtok == QUES) /* found conditional expr */ + { + readtok (); + if (curtok == 0 || curtok == COL) + evalerror ("expression expected"); + if (cval == 0) + noeval++; +#if 0 + val1 = explor (); +#else + val1 = expassign (); +#endif + if (cval == 0) + noeval--; + if (curtok != COL) + evalerror ("`:' expected for conditional expression"); + readtok (); + if (curtok == 0) + evalerror ("expression expected"); + if (cval) + noeval++; + val2 = explor (); + if (cval) + noeval--; + rval = cval ? val1 : val2; + lasttok = COND; + } + return rval; +} + /* Logical OR. */ static long explor () @@ -378,7 +426,11 @@ explor () while (curtok == LOR) { readtok (); + if (val1 != 0) + noeval++; val2 = expland (); + if (val1 != 0) + noeval--; val1 = val1 || val2; } @@ -396,7 +448,11 @@ expland () while (curtok == LAND) { readtok (); + if (val1 == 0) + noeval++; val2 = expbor (); + if (val1 == 0) + noeval--; val1 = val1 && val2; } @@ -635,7 +691,7 @@ exp0 () readtok (); } else - evalerror ("syntax error in expression"); + evalerror ("syntax error: operand expected"); return (val); } @@ -647,17 +703,18 @@ exp0 () static void readtok () { - register char *cp = tp; - register int c, c1; + register char *cp; + register int c, c1, e; /* Skip leading whitespace. */ - c = 0; + cp = tp; + c = e = 0; while (cp && (c = *cp) && (cr_whitespace (c))) cp++; if (c) cp++; - + lasttp = tp = cp - 1; if (c == '\0') @@ -668,27 +725,44 @@ readtok () return; } - if (variable_starter (c)) + if (legal_variable_starter (c)) { - /* Semi-bogus K*rn shell compatibility feature -- variable - names not preceded with a dollar sign are shell variables. */ + /* Semi-bogus ksh compatibility feature -- variable names + not preceded with a dollar sign are shell variables. */ char *value; - while (variable_character (c)) + while (legal_variable_char (c)) c = *cp++; c = *--cp; + +#if defined (ARRAY_VARS) + if (c == '[') + { + e = skipsubscript (cp, 0); + if (cp[e] == ']') + { + cp += e + 1; + c = *cp; + e = ']'; + } + else + evalerror ("bad array subscript"); + } +#endif /* ARRAY_VARS */ + *cp = '\0'; - if (tokstr) - free (tokstr); + FREE (tokstr); tokstr = savestring (tp); + +#if defined (ARRAY_VARS) + value = (e == ']') ? get_array_value (tokstr, 0) : get_string_value (tokstr); +#else value = get_string_value (tokstr); +#endif - if (value && *value) - tokval = evalexp (value); - else - tokval = 0; + tokval = (value && *value) ? evalexp (value) : 0; *cp = c; lasttok = curtok; @@ -696,7 +770,7 @@ readtok () } else if (digit(c)) { - while (digit (c) || isletter (c) || c == '#') + while (digit (c) || isletter (c) || c == '#' || c == '@' || c == '_') c = *cp++; c = *--cp; @@ -710,7 +784,7 @@ readtok () else { c1 = *cp++; - if ((c == EQ) && (c1 == EQ)) + if ((c == EQ) && (c1 == EQ)) c = EQEQ; else if ((c == NOT) && (c1 == EQ)) c = NEQ; @@ -764,39 +838,47 @@ evalerror (msg) char *name, *t; name = this_command_name; - if (name == 0) - name = get_name_for_error (); for (t = expression; whitespace (*t); t++) ; - fprintf (stderr, "%s: %s: %s (remainder of expression is \"%s\")\n", - name, t, - msg, (lasttp && *lasttp) ? lasttp : ""); + internal_error ("%s%s%s: %s (error token is \"%s\")", + name ? name : "", name ? ": " : "", t, + msg, (lasttp && *lasttp) ? lasttp : ""); longjmp (evalbuf, 1); } /* Convert a string to a long integer, with an arbitrary base. 0nnn -> base 8 0xnn -> base 16 - Anything else: [base#]number (this is from the ISO Pascal spec). */ + Anything else: [base#]number (this is implemented to match ksh93) + + Base may be >=2 and <=64. If base is <= 36, the numbers are drawn + from [0-9][a-zA-Z], and lowercase and uppercase letters may be used + interchangably. If base is > 36 and <= 64, the numbers are drawn + from [0-9][a-z][A-Z]_@ (a = 10, z = 35, A = 36, Z = 61, _ = 62, @ = 63 -- + you get the picture). */ + static long strlong (num) char *num; { - register char *s = num; + register char *s; register int c; - int base = 10; + int base, foundbase; long val = 0L; + s = num; if (s == NULL || *s == '\0') return 0L; + base = 10; + foundbase = 0; if (*s == '0') { s++; if (s == NULL || *s == '\0') return 0L; - + /* Base 16? */ if (*s == 'x' || *s == 'X') { @@ -805,38 +887,46 @@ strlong (num) } else base = 8; + foundbase++; } + val = 0L; for (c = *s++; c; c = *s++) { if (c == '#') { + if (foundbase) + evalerror ("bad number"); + base = (int)val; - /* Illegal base specifications are silently reset to base 10. - I don't think that this is a good idea? */ - if (base < 2 || base > 36) - base = 10; + /* Illegal base specifications raise an evaluation error. */ + if (base < 2 || base > 64) + evalerror ("illegal arithmetic base"); val = 0L; + foundbase++; + } + else if (isletter(c) || digit(c) || (c == '_') || (c == '@')) + { + if (digit(c)) + c = digit_value(c); + else if (c >= 'a' && c <= 'z') + c -= 'a' - 10; + else if (c >= 'A' && c <= 'Z') + c -= 'A' - ((base <= 36) ? 10 : 36); + else if (c == '_') + c = 62; + else if (c == '@') + c = 63; + + if (c >= base) + evalerror ("value too great for base"); + + val = (val * base) + c; } else - if (isletter(c) || digit(c)) - { - if (digit(c)) - c = digit_value(c); - else if (c >= 'a' && c <= 'z') - c -= 'a' - 10; - else if (c >= 'A' && c <= 'Z') - c -= 'A' - 10; - - if (c >= base) - evalerror ("value too great for base"); - - val = (val * base) + c; - } - else - break; + break; } return (val); } @@ -862,7 +952,7 @@ SHELL_VAR *bind_variable () { return 0; } char *get_string_value () { return 0; } -jmp_buf top_level; +procenv_t top_level; main (argc, argv) int argc; diff --git a/externs.h b/externs.h index 8330838..e965b02 100644 --- a/externs.h +++ b/externs.h @@ -21,47 +21,115 @@ /* Make sure that this is included *after* config.h! */ -#if !defined (__EXTERNS_H__) -# define __EXTERNS_H__ +#if !defined (_EXTERNS_H_) +# define _EXTERNS_H_ #include "stdc.h" /* Functions from expr.c. */ extern long evalexp __P((char *)); +/* Functions from getcwd.c */ +#if !defined (HAVE_GETCWD) +extern char *getcwd (); +#endif + /* Functions from print_cmd.c. */ extern char *make_command_string __P((COMMAND *)); extern void print_command __P((COMMAND *)); extern void print_simple_command __P((SIMPLE_COM *)); extern char *named_function_string __P((char *, COMMAND *, int)); +extern void print_word_list __P((WORD_LIST *, char *)); +extern void xtrace_print_word_list __P((WORD_LIST *)); /* Functions from shell.c. */ -extern int maybe_execute_file __P((char *, int)); -extern char *indirection_level_string __P((void)); -extern sighandler termination_unwind_protect __P((int)); -extern sighandler sigint_sighandler __P((int)); -extern void reset_terminating_signals __P((void)); -extern char *shell_version_string __P((void)); -extern void show_shell_version __P((void)); +extern int exit_shell __P((int)); +extern void disable_priv_mode __P((void)); + +#if defined (RESTRICTED_SHELL) +extern int maybe_make_restricted __P((char *)); +#endif + +/* Functions from eval.c. */ +extern int reader_loop __P((void)); +extern int parse_command __P((void)); +extern int read_command __P((void)); /* Functions from test.c. */ extern int group_member (); +extern int test_command (); /* Functions from braces.c. */ #if defined (BRACE_EXPANSION) extern char **brace_expand __P((char *)); #endif -/* Functions from mailcheck.c */ -extern int time_to_check_mail __P((void)); -extern void reset_mail_timer __P((void)); -extern void reset_mail_files __P((void)); -extern void free_mail_files __P((void)); -extern char *make_default_mailpath __P((void)); -extern void remember_mail_dates __P((void)); -extern void check_mail __P((void)); +/* Miscellaneous functions from parse.y */ +extern int yyparse (); +extern void reset_parser (); + +/* Functions from version.c. */ +extern char *shell_version_string __P((void)); +extern void show_shell_version __P((int)); + +/* Declarations for functions defined in locale.c */ +extern void set_default_locale __P((void)); +extern void set_default_locale_vars __P((void)); +extern int set_locale_var __P((char *, char *)); +extern int set_lang __P((char *, char *)); +extern char *get_locale_var __P((char *)); +extern char *localetrans __P((char *, int, int *)); + +/* Declarations for functions defined in list.c. */ +extern void map_over_list __P((GENERIC_LIST *, Function *)); +extern void map_over_words __P((WORD_LIST *, Function *)); +extern GENERIC_LIST *reverse_list (); +extern int list_length (); +extern GENERIC_LIST *list_append (); +extern GENERIC_LIST *delete_element (); + +/* Declarations for functions defined in oslib.c */ +extern long get_clk_tck __P((void)); + +#if !defined (strerror) +extern char *strerror __P((int)); +#endif + +#if !defined (HAVE_STRCASECMP) +extern int strncasecmp __P((char *, char *, int)); +extern int strcasecmp __P((char *, char *)); +#endif /* HAVE_STRCASECMP */ + +extern int dup2 __P((int, int)); -/* Miscellaneous functions not declared anywhere but used. */ -extern char **glob_filename __P((char *)); +#if !defined (HAVE_GETHOSTNAME) +extern int gethostname __P((char *, int)); +#endif /* !HAVE_GETHOSTNAME */ + +#if !defined (HAVE_GETDTABLESIZE) +extern int getdtablesize __P((void)); +#endif /* !HAVE_GETDTABLESIZE */ + +#if !defined (HAVE_SETLINEBUF) +extern int setlinebuf (); +#endif -#endif /* __EXTERNS_H__ */ +/* Declarations for functions defined in stringlib.c */ +extern char *ansicstr __P((char *, int, int *)); +extern int find_name_in_array __P((char *, char **)); +extern int array_len __P((char **)); +extern void free_array_members __P((char **)); +extern void free_array __P((char **)); +extern char **copy_array __P((char **)); +extern int qsort_string_compare (); +extern void sort_char_array __P((char **)); +extern char **word_list_to_argv __P((WORD_LIST *, int, int, int *)); +extern WORD_LIST *argv_to_word_list __P((char **, int, int)); + +extern char *strsub __P((char *, char *, char *, int)); +extern void strip_leading __P((char *)); +extern void strip_trailing __P((char *, int)); +extern char *strindex __P((char *, char *)); +extern void xbcopy __P((char *, char *, int)); + +#endif /* _EXTERNS_H_ */ diff --git a/filecntl.h b/filecntl.h index c0b2081..cf5054d 100644 --- a/filecntl.h +++ b/filecntl.h @@ -33,4 +33,13 @@ #define SET_CLOSE_ON_EXEC(fd) (fcntl ((fd), F_SETFD, FD_CLOEXEC)) #define SET_OPEN_ON_EXEC(fd) (fcntl ((fd), F_SETFD, FD_NCLOEXEC)) +/* How to open a file in non-blocking mode, the Posix.1 way. */ +#if !defined (O_NONBLOCK) +# if defined (O_NDELAY) +# define O_NONBLOCK O_NDELAY +# else +# define O_NONBLOCK 0 +# endif +#endif + #endif /* ! _FILECNTL_H_ */ diff --git a/flags.c b/flags.c index b812ec9..856698d 100644 --- a/flags.c +++ b/flags.c @@ -20,10 +20,18 @@ with Bash; see the file COPYING. If not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ /* Flags hacking. */ +#include "config.h" +#if defined (HAVE_UNISTD_H) +# include +#endif #include "shell.h" #include "flags.h" +#if defined (JOB_CONTROL) +extern int set_job_control (); +#endif + /* **************************************************************** */ /* */ /* The Standard Sh Flags. */ @@ -45,17 +53,12 @@ int exit_immediately_on_error = 0; /* Non-zero means disable filename globbing. */ int disallow_filename_globbing = 0; -/* Non-zero means to locate and remember function commands as functions are - defined. Function commands are normally located when the function is - executed. */ -int locate_commands_in_functions = 0; - /* Non-zero means that all keyword arguments are placed into the environment for a command, not just those that appear on the line before the command name. */ int place_keywords_in_env = 0; -/* Non-zero means read commands, but don't execute tham. This is useful +/* Non-zero means read commands, but don't execute them. This is useful for debugging shell scripts that should do something hairy and possibly desctructive. */ int read_but_dont_execute = 0; @@ -97,15 +100,16 @@ int no_symbolic_links = 0; /* */ /* **************************************************************** */ - +#if 0 /* Non-zero means do lexical scoping in the body of a FOR command. */ int lexical_scoping = 0; +#endif /* Non-zero means no such thing as invisible variables. */ int no_invisible_vars = 0; -/* Non-zero means don't look up or remember command names in a hash table, */ -int hashing_disabled = 0; +/* Non-zero means look up and remember command names in a hash table, */ +int hashing_enabled = 1; #if defined (BANG_HISTORY) /* Non-zero means that we are doing history expansion. The default. @@ -114,11 +118,7 @@ int history_expansion = 1; #endif /* BANG_HISTORY */ /* Non-zero means that we allow comments to appear in interactive commands. */ -#if defined (INTERACTIVE_COMMENTS) int interactive_comments = 1; -#else -int interactive_comments = 0; -#endif /* INTERACTIVE_COMMENTS */ #if defined (RESTRICTED_SHELL) /* Non-zero means that this shell is `restricted'. A restricted shell @@ -133,6 +133,11 @@ int restricted = 0; differ. */ int privileged_mode = 0; +#if defined (BRACE_EXPANSION) +/* Zero means to disable brace expansion: foo{a,b} -> fooa foob */ +int brace_expansion = 1; +#endif + /* **************************************************************** */ /* */ /* The Flags ALIST. */ @@ -147,7 +152,7 @@ struct flags_alist shell_flags[] = { #endif /* JOB_CONTROL */ { 'e', &exit_immediately_on_error }, { 'f', &disallow_filename_globbing }, - { 'h', &locate_commands_in_functions }, /* Oh, yeah, good mnemonic. */ + { 'h', &hashing_enabled }, { 'i', &forced_interactive }, { 'k', &place_keywords_in_env }, #if defined (JOB_CONTROL) @@ -165,16 +170,18 @@ struct flags_alist shell_flags[] = { { 'C', &noclobber }, /* New flags that control non-standard things. */ +#if 0 { 'l', &lexical_scoping }, +#endif { 'I', &no_invisible_vars }, - /* I want `h', but locate_commands_in_functions has it. Great. */ - { 'd', &hashing_disabled }, - { 'P', &no_symbolic_links }, +#if defined (BRACE_EXPANSION) + { 'B', &brace_expansion }, +#endif + #if defined (BANG_HISTORY) - /* Once again, we don't have the right mnemonic. */ { 'H', &history_expansion }, #endif /* BANG_HISTORY */ @@ -187,12 +194,11 @@ int * find_flag (name) int name; { - int i = 0; - while (shell_flags[i].name) + int i; + for (i = 0; shell_flags[i].name; i++) { if (shell_flags[i].name == name) return (shell_flags[i].value); - i++; } return (FLAG_UNKNOWN); } @@ -205,8 +211,9 @@ change_flag (flag, on_or_off) int flag; int on_or_off; { - int *value = find_flag (flag); - int old_value; + int *value, old_value; + + value = find_flag (flag); #if defined (RESTRICTED_SHELL) /* Don't allow "set +r" in a shell which is `restricted'. */ @@ -216,18 +223,15 @@ change_flag (flag, on_or_off) if (value == (int *)FLAG_UNKNOWN) return (FLAG_ERROR); - else - old_value = *value; + + old_value = *value; if (on_or_off == FLAG_ON) *value = 1; + else if (on_or_off == FLAG_OFF) + *value = 0; else - { - if (on_or_off == FLAG_OFF) - *value = 0; - else - return (FLAG_ERROR); - } + return (FLAG_ERROR); /* Special cases for a few flags. */ switch (flag) @@ -240,15 +244,11 @@ change_flag (flag, on_or_off) case 'p': if (on_or_off == '+') - { - setuid (current_user.uid); - setgid (current_user.gid); - current_user.euid = current_user.uid; - current_user.egid = current_user.gid; - } + disable_priv_mode (); + break; } - + return (old_value); } @@ -257,11 +257,11 @@ change_flag (flag, on_or_off) char * which_set_flags () { - char *temp = (char *)xmalloc (1 + NUM_SHELL_FLAGS); + char *temp; + int i, string_index; - int i, string_index = 0; - - for (i = 0; shell_flags[i].name; i++) + temp = xmalloc (1 + NUM_SHELL_FLAGS); + for (i = string_index = 0; shell_flags[i].name; i++) if (*(shell_flags[i].value)) temp[string_index++] = shell_flags[i].name; diff --git a/flags.h b/flags.h index bcff4ef..d971cb8 100644 --- a/flags.h +++ b/flags.h @@ -19,8 +19,8 @@ with Bash; see the file COPYING. If not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ -#if !defined (_FLAGS_H) -#define _FLAGS_H +#if !defined (_FLAGS_H_) +#define _FLAGS_H_ #include "stdc.h" @@ -41,12 +41,20 @@ extern struct flags_alist shell_flags[]; extern int mark_modified_vars, exit_immediately_on_error, disallow_filename_globbing, - locate_commands_in_functions, place_keywords_in_env, read_but_dont_execute, + place_keywords_in_env, read_but_dont_execute, just_one_command, unbound_vars_is_error, echo_input_at_read, - echo_command_at_execute, lexical_scoping, no_invisible_vars, noclobber, - hashing_disabled, forced_interactive, privileged_mode, + echo_command_at_execute, no_invisible_vars, noclobber, + hashing_enabled, forced_interactive, privileged_mode, asynchronous_notification, interactive_comments, no_symbolic_links; +#if 0 +extern int lexical_scoping; +#endif + +#if defined (BRACE_EXPANSION) +extern int brace_expansion; +#endif + #if defined (BANG_HISTORY) extern int history_expansion; #endif /* BANG_HISTORY */ @@ -62,4 +70,4 @@ extern char *which_set_flags __P((void)); /* A macro for efficiency. */ #define change_flag_char(flag, on_or_off) change_flag (flag, on_or_off) -#endif /* _FLAGS_H */ +#endif /* _FLAGS_H_ */ diff --git a/general.c b/general.c index 9ccfce6..9623df0 100644 --- a/general.c +++ b/general.c @@ -19,28 +19,34 @@ with Bash; see the file COPYING. If not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include "config.h" /* includes unistd.h for us */ -#include -#include -#include +#include "config.h" + #include "bashtypes.h" #include -#if defined (_POSIX_VERSION) -# if defined (amiga) && defined (USGr4) -# define _POSIX_SOURCE -# endif -# include -# if defined (amiga) && defined (USGr4) -# undef _POSIX_SOURCE -# endif -#endif /* _POSIX_VERSION */ +#include "posixstat.h" + +#if defined (HAVE_UNISTD_H) +# include +#endif + #include "filecntl.h" #include "bashansi.h" +#include +#include +#include + #include "shell.h" #include -#if !defined (USG) || defined (HAVE_RESOURCE) +#if defined (TIME_WITH_SYS_TIME) # include +# include +#else +# if defined (HAVE_SYS_TIME_H) +# include +# else +# include +# endif #endif #include @@ -50,85 +56,21 @@ extern int errno; #endif /* !errno */ -/* Make the functions strchr and strrchr if they do not exist. */ -#if !defined (HAVE_STRCHR) -char * -strchr (string, c) - char *string; - int c; -{ - register int i; - - for (i = 0; string && string[i]; i++) - if (string[i] == c) - return ((char *) (string + i)); - - return ((char *) NULL); -} - -char * -strrchr (string, c) - char *string; - int c; -{ - register int i; - - if (string) - i = strlen (string) - 1; - else - i = -1; - - for (; string && i > -1; i--) - if (string[i] == c) - return ((char *) (string + i)); - - return ((char *) NULL); -} -#endif /* !HAVE_STRCHR */ - -/* **************************************************************** */ -/* */ -/* Memory Allocation and Deallocation. */ -/* */ -/* **************************************************************** */ - -char * -xmalloc (size) - int size; -{ - register char *temp = (char *)malloc (size); - - if (!temp) - fatal_error ("Out of virtual memory!"); - - return (temp); -} - -char * -xrealloc (pointer, size) - GENPTR pointer; - int size; -{ - char *temp; - - if (!pointer) - temp = xmalloc (size); - else - temp = (char *)realloc (pointer, size); - - if (!temp) - fatal_error ("Out of virtual memory!"); +#ifndef to_upper +# define to_upper(c) (islower(c) ? toupper(c) : (c)) +# define to_lower(c) (isupper(c) ? tolower(c) : (c)) +#endif - return (temp); -} +extern int interrupt_immediately; +extern int interactive_comments; +extern char *bash_getcwd_errstr; -/* Use this as the function to call when adding unwind protects so we - don't need to know what free() returns. */ +/* Do whatever is necessary to initialize `Posix mode'. */ void -xfree (string) - char *string; +posix_initialize (on) + int on; { - free (string); + interactive_comments = on != 0; } /* **************************************************************** */ @@ -161,8 +103,8 @@ itos (i) ui = (unsigned int) i; - buf[MAX_INT_LEN - 1] = '\0'; - p = &buf[MAX_INT_LEN - 2]; + p = buf + MAX_INT_LEN - 2; + p[1] = '\0'; do *p-- = (ui % 10) + '0'; @@ -176,21 +118,6 @@ itos (i) return (ret); } -/* Return non-zero if all of the characters in STRING are digits. */ -int -all_digits (string) - char *string; -{ - while (*string) - { - if (!digit (*string)) - return (0); - else - string++; - } - return (1); -} - /* atol(3) is not universal */ long string_to_long (s) @@ -211,6 +138,12 @@ string_to_long (s) return (neg ? -ret : ret); } +/* **************************************************************** */ +/* */ +/* Functions to convert to and from and display non-standard types */ +/* */ +/* **************************************************************** */ + #if defined (RLIMTYPE) RLIMTYPE string_to_rlimtype (s) @@ -258,6 +191,162 @@ print_rlimtype (n, addnl) } #endif /* RLIMTYPE */ +#if defined (HAVE_TIMEVAL) +/* Convert a pointer to a struct timeval to seconds and thousandths of a + second, returning the values in *SP and *SFP, respectively. This does + rounding on the fractional part, not just truncation to three places. */ +void +timeval_to_secs (tvp, sp, sfp) + struct timeval *tvp; + long *sp; + int *sfp; +{ + int rest; + + *sp = tvp->tv_sec; + + *sfp = tvp->tv_usec % 1000000; /* pretty much a no-op */ + rest = *sfp % 1000; + *sfp = (*sfp * 1000) / 1000000; + if (rest >= 500) + *sfp += 1; +} + +/* Print the contents of a struct timeval * in a standard way to stdio + stream FP. */ +void +print_timeval (fp, tvp) + FILE *fp; + struct timeval *tvp; +{ + int minutes, seconds_fraction; + long seconds; + + timeval_to_secs (tvp, &seconds, &seconds_fraction); + + minutes = seconds / 60; + seconds %= 60; + + fprintf (fp, "%0dm%0ld.%03ds", minutes, seconds, seconds_fraction); +} +#endif /* HAVE_TIMEVAL */ + +#if defined (HAVE_TIMES) +void +clock_t_to_secs (t, sp, sfp) + clock_t t; + long *sp; + int *sfp; +{ + static long clk_tck = 0; + + if (clk_tck == 0) + clk_tck = get_clk_tck (); + + *sfp = t % clk_tck; + *sfp = (*sfp * 1000) / clk_tck; + + *sp = t / clk_tck; +} + +/* Print the time defined by a time_t (returned by the `times' and `time' + system calls) in a standard way to stdion stream FP. This is scaled in + terms of HZ, which is what is returned by the `times' call. */ +void +print_time_in_hz (fp, t) + FILE *fp; + clock_t t; +{ + int minutes, seconds_fraction; + long seconds; + + clock_t_to_secs (t, &seconds, &seconds_fraction); + + minutes = seconds / 60; + seconds %= 60; + + fprintf (fp, "%0dm%0ld.%03ds", minutes, seconds, seconds_fraction); +} +#endif /* HAVE_TIMES */ + +/* **************************************************************** */ +/* */ +/* Input Validation Functions */ +/* */ +/* **************************************************************** */ + +/* Return non-zero if all of the characters in STRING are digits. */ +int +all_digits (string) + char *string; +{ + while (*string) + { + if (!digit (*string)) + return (0); + else + string++; + } + return (1); +} + +/* Return non-zero if the characters pointed to by STRING constitute a + valid number. Stuff the converted number into RESULT if RESULT is + a non-null pointer to a long. */ +int +legal_number (string, result) + char *string; + long *result; +{ + int sign; + long value; + + sign = 1; + value = 0; + + if (result) + *result = 0; + + /* Skip leading whitespace characters. */ + while (whitespace (*string)) + string++; + + if (!*string) + return (0); + + /* We allow leading `-' or `+'. */ + if (*string == '-' || *string == '+') + { + if (!digit (string[1])) + return (0); + + if (*string == '-') + sign = -1; + + string++; + } + + while (digit (*string)) + { + if (result) + value = (value * 10) + digit_value (*string); + string++; + } + + /* Skip trailing whitespace, if any. */ + while (whitespace (*string)) + string++; + + /* Error if not at end of string. */ + if (*string) + return (0); + + if (result) + *result = value * sign; + + return (1); +} + /* Return 1 if this token is a legal shell `identifier'; that is, it consists solely of letters, digits, and underscores, and does not begin with a digit. */ @@ -267,12 +356,12 @@ legal_identifier (name) { register char *s; - if (!name || !*name || digit (*name)) + if (!name || !*name || (legal_variable_starter (*name) == 0)) return (0); - for (s = name; s && *s; s++) + for (s = name + 1; *s; s++) { - if (!isletter (*s) && !digit (*s) && (*s != '_')) + if (legal_variable_char (*s) == 0) return (0); } return (1); @@ -283,24 +372,31 @@ legal_identifier (name) does it consist of all digits. If CHECK_WORD is non-zero, the word is checked to ensure that it consists of only letters, digits, and underscores. */ +int check_identifier (word, check_word) WORD_DESC *word; int check_word; { - if (word->dollar_present || word->quoted || all_digits (word->word)) + if ((word->flags & (W_HASDOLLAR|W_QUOTED)) || all_digits (word->word)) { - report_error ("`%s' is not a valid identifier", word->word); + internal_error ("`%s': not a valid identifier", word->word); return (0); } else if (check_word && legal_identifier (word->word) == 0) { - report_error ("`%s' is not a valid identifier", word->word); + internal_error ("`%s': not a valid identifier", word->word); return (0); } else return (1); } +/* **************************************************************** */ +/* */ +/* Functions to manage files and file descriptors */ +/* */ +/* **************************************************************** */ + /* A function to unset no-delay mode on a file descriptor. Used in shell.c to unset it on the fd passed as stdin. Should be called on stdin if readline gets an EAGAIN or EWOULDBLOCK when trying to read input. */ @@ -316,258 +412,159 @@ void unset_nodelay_mode (fd) int fd; { - int flags, set = 0; + int flags, set; if ((flags = fcntl (fd, F_GETFL, 0)) < 0) return; -#if defined (O_NONBLOCK) + set = 0; + + /* This is defined to O_NDELAY in filecntl.h if O_NONBLOCK is not present + and O_NDELAY is defined. */ if (flags & O_NONBLOCK) { flags &= ~O_NONBLOCK; set++; } -#endif /* O_NONBLOCK */ - -#if defined (O_NDELAY) - if (flags & O_NDELAY) - { - flags &= ~O_NDELAY; - set++; - } -#endif /* O_NDELAY */ if (set) fcntl (fd, F_SETFL, flags); } - -/* **************************************************************** */ -/* */ -/* Generic List Functions */ -/* */ -/* **************************************************************** */ - -/* Call FUNCTION on every member of LIST, a generic list. */ + /* There is a bug in the NeXT 2.1 rlogind that causes opens + of /dev/tty to fail. */ void -map_over_list (list, function) - GENERIC_LIST *list; - Function *function; +check_dev_tty () { - while (list) - { - (*function) (list); - list = list->next; - } -} + int tty_fd; + char *tty; -/* Call FUNCTION on every string in WORDS. */ -void -map_over_words (words, function) - WORD_LIST *words; - Function *function; -{ - while (words) - { - (*function)(words->word->word); - words = words->next; - } -} - -/* Reverse the chain of structures in LIST. Output the new head - of the chain. You should always assign the output value of this - function to something, or you will lose the chain. */ -GENERIC_LIST * -reverse_list (list) - GENERIC_LIST *list; -{ - register GENERIC_LIST *next, *prev = (GENERIC_LIST *)NULL; + tty_fd = open ("/dev/tty", O_RDWR); - while (list) + if (tty_fd < 0) { - next = list->next; - list->next = prev; - prev = list; - list = next; + tty = (char *)ttyname (fileno (stdin)); + if (tty == 0) + return; + tty_fd = open (tty, O_RDWR); } - return (prev); + close (tty_fd); } -/* Return the number of elements in LIST, a generic list. */ +/* Return 1 if PATH1 and PATH2 are the same file. This is kind of + expensive. If non-NULL STP1 and STP2 point to stat structures + corresponding to PATH1 and PATH2, respectively. */ int -list_length (list) - GENERIC_LIST *list; +same_file (path1, path2, stp1, stp2) + char *path1, *path2; + struct stat *stp1, *stp2; { - register int i; - - for (i = 0; list; list = list->next, i++); - return (i); -} + struct stat st1, st2; -/* A global variable which acts as a sentinel for an `error' list return. */ -GENERIC_LIST global_error_list; - -/* Delete the element of LIST which satisfies the predicate function COMPARER. - Returns the element that was deleted, so you can dispose of it, or -1 if - the element wasn't found. COMPARER is called with the list element and - then ARG. Note that LIST contains the address of a variable which points - to the list. You might call this function like this: - - SHELL_VAR *elt = delete_element (&variable_list, check_var_has_name, "foo"); - dispose_variable (elt); -*/ -GENERIC_LIST * -delete_element (list, comparer, arg) - GENERIC_LIST **list; - Function *comparer; - char *arg; -{ - register GENERIC_LIST *prev = (GENERIC_LIST *)NULL; - register GENERIC_LIST *temp = *list; - - while (temp) + if (stp1 == NULL) { - if ((*comparer) (temp, arg)) - { - if (prev) - prev->next = temp->next; - else - *list = temp->next; - return (temp); - } - prev = temp; - temp = temp->next; + if (stat (path1, &st1) != 0) + return (0); + stp1 = &st1; } - return ((GENERIC_LIST *)&global_error_list); -} -/* Find NAME in ARRAY. Return the index of NAME, or -1 if not present. - ARRAY should be NULL terminated. */ -int -find_name_in_list (name, array) - char *name, **array; -{ - int i; - - for (i = 0; array[i]; i++) - if (strcmp (name, array[i]) == 0) - return (i); + if (stp2 == NULL) + { + if (stat (path2, &st2) != 0) + return (0); + stp2 = &st2; + } - return (-1); + return ((stp1->st_dev == stp2->st_dev) && (stp1->st_ino == stp2->st_ino)); } -/* Return the length of ARRAY, a NULL terminated array of char *. */ +/* Move FD to a number close to the maximum number of file descriptors + allowed in the shell process, to avoid the user stepping on it with + redirection and causing us extra work. If CHECK_NEW is non-zero, + we check whether or not the file descriptors are in use before + duplicating FD onto them. */ int -array_len (array) - char **array; +move_to_high_fd (fd, check_new) + int fd, check_new; { - register int i; - for (i = 0; array[i]; i++); - return (i); -} + int script_fd, nfds, ignore; -/* Free the contents of ARRAY, a NULL terminated array of char *. */ -void -free_array (array) - char **array; -{ - register int i = 0; + nfds = getdtablesize (); + if (nfds <= 0) + nfds = 20; + if (nfds > 256) + nfds = 256; - if (!array) return; + for (nfds--; check_new && nfds > 3; nfds--) + if (fcntl (nfds, F_GETFD, &ignore) == -1) + break; - while (array[i]) - free (array[i++]); - free (array); -} - -/* Allocate and return a new copy of ARRAY and its contents. */ -char ** -copy_array (array) - char **array; -{ - register int i; - int len; - char **new_array; + if (nfds && fd != nfds && (script_fd = dup2 (fd, nfds)) != -1) + { + if (check_new == 0 || fd != fileno (stderr)) /* don't close stderr */ + close (fd); + return (script_fd); + } - len = array_len (array); + return (fd); +} + +/* Return non-zero if the characters from SAMPLE are not all valid + characters to be found in the first line of a shell script. We + check up to the first newline, or SAMPLE_LEN, whichever comes first. + All of the characters must be printable or whitespace. */ - new_array = (char **)xmalloc ((len + 1) * sizeof (char *)); - for (i = 0; array[i]; i++) - new_array[i] = savestring (array[i]); - new_array[i] = (char *)NULL; +#if !defined (isspace) +#define isspace(c) ((c) == ' ' || (c) == '\t' || (c) == '\n' || (c) == '\f') +#endif - return (new_array); -} +#if !defined (isprint) +#define isprint(c) (isletter(c) || digit(c) || ispunct(c)) +#endif -/* Comparison routine for use with qsort() on arrays of strings. */ int -qsort_string_compare (s1, s2) - register char **s1, **s2; +check_binary_file (sample, sample_len) + unsigned char *sample; + int sample_len; { - int result; - - if ((result = **s1 - **s2) == 0) - result = strcmp (*s1, *s2); - - return (result); -} + register int i; -/* Append LIST2 to LIST1. Return the header of the list. */ -GENERIC_LIST * -list_append (head, tail) - GENERIC_LIST *head, *tail; -{ - register GENERIC_LIST *t_head = head; + for (i = 0; i < sample_len; i++) + { + if (sample[i] == '\n') + return (0); - if (!t_head) - return (tail); + if (isspace (sample[i]) == 0 && isprint (sample[i]) == 0) + return (1); + } - while (t_head->next) - t_head = t_head->next; - t_head->next = tail; - return (head); + return (0); } -/* Some random string stuff. */ - -/* Remove all leading whitespace from STRING. This includes - newlines. STRING should be terminated with a zero. */ -void -strip_leading (string) - char *string; -{ - char *start = string; - - while (*string && (whitespace (*string) || *string == '\n')) - string++; - - if (string != start) - { - int len = strlen (string); - FASTCOPY (string, start, len); - start[len] = '\0'; - } -} +/* **************************************************************** */ +/* */ +/* Functions to manipulate pathnames */ +/* */ +/* **************************************************************** */ -/* Remove all trailing whitespace from STRING. This includes - newlines. If NEWLINES_ONLY is non-zero, only trailing newlines - are removed. STRING should be terminated with a zero. */ -void -strip_trailing (string, newlines_only) - char *string; - int newlines_only; +/* Return 1 if PATH corresponds to a directory. */ +static int +canon_stat (path) + char *path; { - int len = strlen (string) - 1; + int l; + char *s; + struct stat sb; - while (len >= 0) - { - if ((newlines_only && string[len] == '\n') || - (!newlines_only && whitespace (string[len]))) - len--; - else - break; - } - string[len + 1] = '\0'; + l = strlen (path); + s = xmalloc (l + 3); + strcpy (s, path); + s[l] = '/'; + s[l+1] = '.'; + s[l+2] = '\0'; + l = stat (s, &sb) == 0 && S_ISDIR (sb.st_mode); + free (s); + return l; } /* Canonicalize PATH, and return a new path. The new path differs from PATH @@ -618,8 +615,21 @@ canonicalize_pathname (path) { strcpy (result + start + 1, result + i); i = start + 1; + /* Make sure that what we have so far corresponds to a directory. + If it does not, just punt. */ + if (*result) + { + char c; + c = result[start]; + result[start] = '\0'; + if (canon_stat (result) == 0) + { + free (result); + return ((char *)NULL); + } + result[start] = c; + } } - #if 0 /* Handle backslash-quoted `/'. */ if (start > 0 && result[start - 1] == '\\') @@ -653,8 +663,27 @@ canonicalize_pathname (path) if (result[i + 1] == '.' && (result[i + 2] == '/' || !result[i + 2])) { + /* Make sure that the last component corresponds to a directory + before blindly chopping it off. */ + if (i) + { + result[i] = '\0'; + if (canon_stat (result) == 0) + { + free (result); + return ((char *)NULL); + } + result[i] = '.'; + } while (--start > -1 && result[start] != '/'); strcpy (result + start + 1, result + i + 2); +#if 0 /* Unnecessary */ + if (*result && canon_stat (result) == 0) + { + free (result); + return ((char *)NULL); + } +#endif i = (start < 0) ? 0 : start; continue; } @@ -679,16 +708,16 @@ make_absolute (string, dot_path) { char *result; int result_len; - + if (!dot_path || *string == '/') result = savestring (string); else { if (dot_path && dot_path[0]) { - result = xmalloc (2 + strlen (dot_path) + strlen (string)); + result_len = strlen (dot_path); + result = xmalloc (2 + result_len + strlen (string)); strcpy (result, dot_path); - result_len = strlen (result); if (result[result_len - 1] != '/') { result[result_len++] = '/'; @@ -721,10 +750,8 @@ absolute_pathname (string) if (*string++ == '.') { - if (!*string || *string == '/') - return (1); - - if (*string == '.' && (string[1] == '\0' || string[1] == '/')) + if (!*string || *string == '/' || + (*string == '.' && (string[1] == '\0' || string[1] == '/'))) return (1); } return (0); @@ -752,10 +779,7 @@ base_pathname (string) return (string); p = (char *)strrchr (string, '/'); - if (p) - return (++p); - else - return (string); + return (p ? ++p : string); } /* Return the full pathname of FILE. Easy. Filenames that begin @@ -767,342 +791,39 @@ full_pathname (file) char *file; { char *disposer; + char *current_dir; + int dlen; - if (*file == '~') - file = tilde_expand (file); - else - file = savestring (file); + file = (*file == '~') ? bash_tilde_expand (file) : savestring (file); if ((*file == '/') && absolute_pathname (file)) return (file); disposer = file; - { - char *current_dir = xmalloc (2 + MAXPATHLEN + strlen (file)); - int dlen; - if (getwd (current_dir) == 0) - { - report_error (current_dir); - free (current_dir); - return ((char *)NULL); - } - dlen = strlen (current_dir); - current_dir[dlen++] = '/'; - - /* Turn /foo/./bar into /foo/bar. */ - if (file[0] == '.' && file[1] == '/') - file += 2; - - strcpy (current_dir + dlen, file); - free (disposer); - return (current_dir); - } -} - -#if !defined (HAVE_STRCASECMP) - -#if !defined (to_upper) -# define to_upper(c) (islower(c) ? toupper(c) : (c)) -#endif /* to_upper */ - -/* Compare at most COUNT characters from string1 to string2. Case - doesn't matter. */ -int -strnicmp (string1, string2, count) - char *string1, *string2; - int count; -{ - register char ch1, ch2; - - while (count) - { - ch1 = *string1++; - ch2 = *string2++; - if (to_upper(ch1) == to_upper(ch2)) - count--; - else - break; - } - return (count); -} - -/* strcmp (), but caseless. */ -int -stricmp (string1, string2) - char *string1, *string2; -{ - register char ch1, ch2; - - while (*string1 && *string2) - { - ch1 = *string1++; - ch2 = *string2++; - if (to_upper(ch1) != to_upper(ch2)) - return (1); - } - return (*string1 - *string2); -} -#endif /* !HAVE_STRCASECMP */ - -/* Determine if s2 occurs in s1. If so, return a pointer to the - match in s1. The compare is case insensitive. */ -char * -strindex (s1, s2) - char *s1, *s2; -{ - register int i, l = strlen (s2); - register int len = strlen (s1); - - for (i = 0; (len - i) >= l; i++) - if (strnicmp (s1 + i, s2, l) == 0) - return (s1 + i); - return ((char *)NULL); -} - -/* Set the environment variables $LINES and $COLUMNS in response to - a window size change. */ -void -set_lines_and_columns (lines, cols) - int lines, cols; -{ - char *val; - - val = itos (lines); - bind_variable ("LINES", val); - free (val); - - val = itos (cols); - bind_variable ("COLUMNS", val); - free (val); -} - -/* A wrapper for bcopy that can be prototyped in general.h */ -void -xbcopy (s, d, n) - char *s, *d; - int n; -{ - FASTCOPY (s, d, n); -} - -/* Return a string corresponding to the error number E. From - the ANSI C spec. */ -#if defined (strerror) -# undef strerror -#endif - -#if !defined (HAVE_STRERROR) -char * -strerror (e) - int e; -{ - extern int sys_nerr; - extern char *sys_errlist[]; - static char emsg[40]; - - if (e > 0 && e < sys_nerr) - return (sys_errlist[e]); - else - { - sprintf (emsg, "Unknown error %d", e); - return (&emsg[0]); - } -} -#endif /* HAVE_STRERROR */ - -#if (defined (USG) && !defined (HAVE_TIMEVAL)) || defined (Minix) -# define TIMEVAL_MISSING -#endif - -#if !defined (TIMEVAL_MISSING) || defined (HAVE_RESOURCE) -/* Print the contents of a struct timeval * in a standard way. */ -void -print_timeval (tvp) - struct timeval *tvp; -{ - int minutes, seconds_fraction; - long seconds; - - seconds = tvp->tv_sec; - - seconds_fraction = tvp->tv_usec % 1000000; - seconds_fraction = (seconds_fraction * 100) / 1000000; - - minutes = seconds / 60; - seconds %= 60; - - printf ("%0dm%0ld.%02ds", minutes, seconds, seconds_fraction); -} -#endif /* !TIMEVAL_MISSING || HAVE_RESOURCE */ - -/* Print the time defined by a time_t (returned by the `times' and `time' - system calls) in a standard way. This is scaled in terms of HZ, which - is what is returned by the `times' call. */ - -#if !defined (BrainDeath) -# if !defined (HZ) -# if defined (USG) -# define HZ 100 /* From my Sys V.3.2 manual for times(2) */ -# else -# define HZ 60 /* HZ is always 60 on BSD systems */ -# endif /* USG */ -# endif /* HZ */ - -void -print_time_in_hz (t) - time_t t; -{ - int minutes, seconds_fraction; - long seconds; - - seconds_fraction = t % HZ; - seconds_fraction = (seconds_fraction * 100) / HZ; - - seconds = t / HZ; - - minutes = seconds / 60; - seconds %= 60; - - printf ("%0dm%0ld.%02ds", minutes, seconds, seconds_fraction); -} -#endif /* BrainDeath */ - -#if !defined (HAVE_DUP2) -/* Replacement for dup2 (), for those systems which either don't have it, - or supply one with broken behaviour. */ -int -dup2 (fd1, fd2) - int fd1, fd2; -{ - extern int getdtablesize (); - int saved_errno, r; - - /* If FD1 is not a valid file descriptor, then return immediately with - an error. */ - if (fcntl (fd1, F_GETFL, 0) == -1) - return (-1); - - if (fd2 < 0 || fd2 >= getdtablesize ()) + current_dir = xmalloc (2 + PATH_MAX + strlen (file)); + if (getcwd (current_dir, PATH_MAX) == 0) { - errno = EBADF; - return (-1); + sys_error (bash_getcwd_errstr); + free (disposer); + free (current_dir); + return ((char *)NULL); } + dlen = strlen (current_dir); + current_dir[dlen++] = '/'; - if (fd1 == fd2) - return (0); - - saved_errno = errno; - - (void) close (fd2); - r = fcntl (fd1, F_DUPFD, fd2); - - if (r >= 0) - errno = saved_errno; - else - if (errno == EINVAL) - errno = EBADF; - - /* Force the new file descriptor to remain open across exec () calls. */ - SET_OPEN_ON_EXEC (fd2); - return (r); -} -#endif /* !HAVE_DUP2 */ - -/* - * Return the total number of available file descriptors. - * - * On some systems, like 4.2BSD and its descendents, there is a system call - * that returns the size of the descriptor table: getdtablesize(). There are - * lots of ways to emulate this on non-BSD systems. - * - * On System V.3, this can be obtained via a call to ulimit: - * return (ulimit(4, 0L)); - * - * On other System V systems, NOFILE is defined in /usr/include/sys/param.h - * (this is what we assume below), so we can simply use it: - * return (NOFILE); - * - * On POSIX systems, there are specific functions for retrieving various - * configuration parameters: - * return (sysconf(_SC_OPEN_MAX)); - * - */ - -#if !defined (USG) && !defined (HPUX) && !defined (HAVE_GETDTABLESIZE) -# define HAVE_GETDTABLESIZE -#endif /* !USG && !HPUX && !HAVE_GETDTABLESIZE */ - -#if defined (hppa) && (defined (hpux_8) || defined (hpux_9)) -# undef HAVE_GETDTABLESIZE -#endif /* hppa && hpux_8 */ - -#if !defined (HAVE_GETDTABLESIZE) -int -getdtablesize () -{ -# if defined (_POSIX_VERSION) && defined (_SC_OPEN_MAX) - return (sysconf(_SC_OPEN_MAX)); /* Posix systems use sysconf */ -# else /* ! (_POSIX_VERSION && _SC_OPEN_MAX) */ -# if defined (USGr3) - return (ulimit (4, 0L)); /* System V.3 systems use ulimit(4, 0L) */ -# else /* !USGr3 */ -# if defined (NOFILE) /* Other systems use NOFILE */ - return (NOFILE); -# else /* !NOFILE */ - return (20); /* XXX - traditional value is 20 */ -# endif /* !NOFILE */ -# endif /* !USGr3 */ -# endif /* ! (_POSIX_VERSION && _SC_OPEN_MAX) */ -} -#endif /* !HAVE_GETDTABLESIZE */ - -#if defined (USG) - -#if !defined (HAVE_BCOPY) -bcopy (s,d,n) char *d,*s; { FASTCOPY (s, d, n); } -bzero (s,n) char *s; int n; { memset(s, '\0', n); } -#endif /* !HAVE_BCOPY */ - -#if !defined (HAVE_GETHOSTNAME) -#include -int -gethostname (name, namelen) - char *name; - int namelen; -{ - int i; - struct utsname ut; - - --namelen; + /* Turn /foo/./bar into /foo/bar. */ + if (file[0] == '.' && file[1] == '/') + file += 2; - uname (&ut); - i = strlen (ut.nodename) + 1; - strncpy (name, ut.nodename, i < namelen ? i : namelen); - name[namelen] = '\0'; - return (0); + strcpy (current_dir + dlen, file); + free (disposer); + return (current_dir); } -#endif /* !HAVE_GETHOSTNAME */ -#endif /* USG */ - -#if !defined (HAVE_GETWD) -char * -getwd (string) - char *string; -{ - extern char *getcwd (); - char *result; - - result = getcwd (string, MAXPATHLEN); - if (result == NULL) - strcpy (string, "getwd: cannot access parent directories"); - return (result); -} -#endif /* !HAVE_GETWD */ /* A slightly related function. Get the prettiest name of this directory possible. */ -static char tdir[MAXPATHLEN]; +static char tdir[PATH_MAX]; /* Return a pretty pathname. If the first part of the pathname is the same as $HOME, then replace that with `~'. */ @@ -1110,9 +831,11 @@ char * polite_directory_format (name) char *name; { - char *home = get_string_value ("HOME"); - int l = home ? strlen (home) : 0; + char *home; + int l; + home = get_string_value ("HOME"); + l = home ? strlen (home) : 0; if (l > 1 && strncmp (home, name, l) == 0 && (!name[l] || name[l] == '/')) { strcpy (tdir + 1, name + l); @@ -1123,64 +846,57 @@ polite_directory_format (name) return (name); } -#if defined (NO_READ_RESTART_ON_SIGNAL) -static char localbuf[128]; -static int local_index = 0, local_bufused = 0; - -/* Posix and USG systems do not guarantee to restart read () if it is - interrupted by a signal. We do the read ourselves, and restart it - if it returns EINTR. */ -int -getc_with_restart (stream) - FILE *stream; +/* Given a string containing units of information separated by colons, + return the next one pointed to by (P_INDEX), or NULL if there are no more. + Advance (P_INDEX) to the character after the colon. */ +char * +extract_colon_unit (string, p_index) + char *string; + int *p_index; { - /* Try local buffering to reduce the number of read(2) calls. */ - if (local_index == local_bufused || local_bufused == 0) - { - while (1) - { - local_bufused = read (fileno (stream), localbuf, sizeof(localbuf)); - if (local_bufused > 0) - break; - else if (local_bufused == 0 || errno != EINTR) - { - local_index = 0; - return EOF; - } - } - local_index = 0; - } - return (localbuf[local_index++]); -} + int i, start, len; + char *value; -int -ungetc_with_restart (c, fp) - int c; - FILE *fp; -{ - if (local_index == 0 || local_bufused == 0 || c == EOF) - return EOF; - return (localbuf[--local_index] = c); -} + if (string == 0) + return (string); -#endif /* NO_READ_RESTART_ON_SIGNAL */ + len = strlen (string); + if (*p_index >= len) + return ((char *)NULL); -#if defined (USG) || defined (AIX) || (defined (_POSIX_VERSION) && defined (Ultrix)) -/* USG and strict POSIX systems do not have killpg (). But we use it in - jobs.c, nojobs.c and some of the builtins. This can also be redefined - as a macro if necessary. */ -#if !defined (_POSIX_VERSION) -# define pid_t int -#endif /* _POSIX_VERSION */ + i = *p_index; -int -killpg (pgrp, sig) - pid_t pgrp; - int sig; -{ - return (kill (-pgrp, sig)); + /* Each call to this routine leaves the index pointing at a colon if + there is more to the path. If I is > 0, then increment past the + `:'. If I is 0, then the path has a leading colon. Trailing colons + are handled OK by the `else' part of the if statement; an empty + string is returned in that case. */ + if (i && string[i] == ':') + i++; + + for (start = i; string[i] && string[i] != ':'; i++) + ; + + *p_index = i; + + if (i == start) + { + if (string[i]) + (*p_index)++; + /* Return "" in the case of a trailing `:'. */ + value = xmalloc (1); + value[0] = '\0'; + } + else + { + len = i - start; + value = xmalloc (1 + len); + strncpy (value, string + start, len); + value [len] = '\0'; + } + + return (value); } -#endif /* USG || AIX || (_POSIX_VERSION && Ultrix) */ /* **************************************************************** */ /* */ @@ -1192,12 +908,13 @@ killpg (pgrp, sig) is a special shell expansion. This function is installed as the tilde_expansion_failure_hook. It knows how to expand ~- and ~+. */ static char * -bash_tilde_expand (text) +bash_tilde_expansion_failure_hook (text) char *text; { - char *result = (char *)NULL; + char *result; - if (!text[1]) + result = (char *)NULL; + if (text[1] == '\0') { if (*text == '+') result = get_string_value ("PWD"); @@ -1205,10 +922,7 @@ bash_tilde_expand (text) result = get_string_value ("OLDPWD"); } - if (result) - result = savestring (result); - - return (result); + return (result ? savestring (result) : (char *)NULL); } /* Initialize the tilde expander. In Bash, we handle `~-' and `~+', as @@ -1220,7 +934,7 @@ tilde_initialize () static int times_called = 0; /* Tell the tilde expander that we want a crack if it fails. */ - tilde_expansion_failure_hook = (CPFunction *)bash_tilde_expand; + tilde_expansion_failure_hook = (CPFunction *)bash_tilde_expansion_failure_hook; /* Tell the tilde expander about special strings which start a tilde expansion, and the special strings that end one. Only do this once. @@ -1240,34 +954,16 @@ tilde_initialize () times_called++; } -#if defined (_POSIX_VERSION) - -#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; +char * +bash_tilde_expand (s) + char *s; { - struct sigaction act, oact; + int old_immed; + char *ret; - 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); + old_immed = interrupt_immediately; + interrupt_immediately = 1; + ret = tilde_expand (s); + interrupt_immediately = old_immed; + return (ret); } -#endif /* _POSIX_VERSION */ diff --git a/general.h b/general.h index 5c8f4d1..b520c1d 100644 --- a/general.h +++ b/general.h @@ -18,22 +18,19 @@ with Bash; see the file COPYING. If not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ -#if !defined (_GENERAL_H) -#define _GENERAL_H +#if !defined (_GENERAL_H_) +#define _GENERAL_H_ #include "stdc.h" -/* just to make sure */ -#if defined (HAVE_UNISTD_H) -# ifdef CRAY -# define word __word -# endif -# include -# ifdef CRAY -# undef word -# endif +/* Generic pointer type. */ +#if defined (__STDC__) +# define PTR_T void * +#else +# define PTR_T char * #endif +/* NULL pointer type. */ #if !defined (NULL) # if defined (__STDC__) # define NULL ((void *) 0) @@ -50,14 +47,24 @@ #define pointer_to_int(x) (int)((long)(x)) +extern char *xmalloc (), *xrealloc (); + +#if defined (alpha) && defined (__GNUC__) && !defined (strchr) && !defined (__STDC__) +extern char *strchr (), *strrchr (); +#endif + +#if !defined (strcpy) +extern char *strcpy (); +#endif + #if !defined (savestring) - extern char *xmalloc (); -# if !defined (strcpy) - extern char *strcpy (); -# endif # define savestring(x) (char *)strcpy (xmalloc (1 + strlen (x)), (x)) #endif +#ifndef member +# define member(c, s) ((c) ? ((char *)strchr ((s), (c)) != (char *)NULL) : 0) +#endif + #ifndef whitespace #define whitespace(c) (((c) == ' ') || ((c) == '\t')) #endif @@ -74,21 +81,14 @@ #define digit_value(c) ((c) - '0') #endif +/* Define exactly what a legal shell identifier consists of. */ +#define legal_variable_starter(c) (isletter(c) || (c == '_')) +#define legal_variable_char(c) (isletter (c) || digit (c) || c == '_') + /* Definitions used in subst.c and by the `read' builtin for field splitting. */ #define spctabnl(c) ((c) == ' ' || (c) == '\t' || (c) == '\n') -#if !defined (__STDC__) && !defined (strchr) -extern char *strchr (), *strrchr (); -#endif /* !strchr */ - -#ifndef member -# if defined (alpha) && defined (__GNUC__) /* XXX */ - extern char *strchr (); -# endif -# define member(c, s) ((c) ? ((char *)strchr ((s), (c)) != (char *)NULL) : 0) -#endif - /* All structs which contain a `next' field should have that field as the first field in the struct. This means that functions can be written to handle the general case for linked lists. */ @@ -105,20 +105,21 @@ typedef struct { /* A macro to avoid making an uneccessary function call. */ #define REVERSE_LIST(list, type) \ - ((list && list->next) ? (type)reverse_list ((GENERIC_LIST *)list) : (type)(list)) + ((list && list->next) ? (type)reverse_list ((GENERIC_LIST *)list) \ + : (type)(list)) #if __GNUC__ > 1 # define FASTCOPY(s, d, n) __builtin_memcpy (d, s, n) #else /* !__GNUC__ */ -# if defined (USG) && !defined (HAVE_BCOPY) -# if defined (MEMMOVE_MISSING) +# if !defined (HAVE_BCOPY) +# if !defined (HAVE_MEMMOVE) # define FASTCOPY(s, d, n) memcpy (d, s, n) # else # define FASTCOPY(s, d, n) memmove (d, s, n) -# endif /* !MEMMOVE_MISSING */ -# else +# endif /* !HAVE_MEMMOVE */ +# else /* HAVE_BCOPY */ # define FASTCOPY(s, d, n) bcopy (s, d, n) -# endif /* !USG || HAVE_BCOPY */ +# endif /* HAVE_BCOPY */ #endif /* !__GNUC__ */ /* String comparisons that possibly save a function call each. */ @@ -130,17 +131,27 @@ typedef struct { #define FREE(s) do { if (s) free (s); } while (0) #define MEMBER(c, s) (((c) && !(s)[1] && c == s[0]) || (member(c, s))) -/* What type is a `generic' pointer? This is used as the first argument - to xrealloc. */ -#if defined (__STDC__) -typedef void *GENPTR; -#else -typedef char *GENPTR; -#endif +/* A fairly hairy macro to check whether an allocated string has more room, + and to resize it using xrealloc if it does not. + STR is the string (char *) + CIND is the current index into the string (int) + ROOM is the amount of additional room we need in the string (int) + CSIZE is the currently-allocated size of STR (int) + SINCR is how much to increment CSIZE before calling xrealloc (int) */ + +#define RESIZE_MALLOCED_BUFFER(str, cind, room, csize, sincr) \ + do { \ + if ((cind) + (room) >= csize) \ + { \ + while ((cind) + (room) >= csize) \ + csize += (sincr); \ + str = xrealloc (str, csize); \ + } \ + } while (0) /* Function pointers can be declared as (Function *)foo. */ -#if !defined (__FUNCTION_DEF) -# define __FUNCTION_DEF +#if !defined (_FUNCTION_DEF) +# define _FUNCTION_DEF typedef int Function (); typedef void VFunction (); typedef char *CPFunction (); @@ -154,94 +165,52 @@ typedef char **CPPFunction (); #define FS_EXECABLE 0x2 #define FS_EXEC_PREFERRED 0x4 #define FS_EXEC_ONLY 0x8 +#define FS_DIRECTORY 0x10 +#define FS_NODIRS 0x20 -/* Posix and USG systems do not guarantee to restart a read () that is - interrupted by a signal. */ -#if defined (USG) || defined (_POSIX_VERSION) -# define NO_READ_RESTART_ON_SIGNAL -#endif /* USG || _POSIX_VERSION */ - -/* Here is a definition for set_signal_handler () which simply expands to - a call to signal () for non-Posix systems. The code for set_signal_handler - in the Posix case resides in general.c. */ +/* Declarations for functions defined in xmalloc.c */ +extern char *xmalloc __P((size_t)); +extern char *xrealloc __P((void *, size_t)); +extern void xfree __P((char *)); -#if defined (VOID_SIGHANDLER) -# define sighandler void -#else -# define sighandler int -#endif /* !VOID_SIGHANDLER */ +/* Declarations for functions defined in general.c */ +extern void posix_initialize __P((int)); -typedef sighandler SigHandler (); +extern char *itos __P((int)); +extern long string_to_long __P((char *)); -#if !defined (_POSIX_VERSION) -# define set_signal_handler(sig, handler) (SigHandler *)signal (sig, handler) -#else -extern SigHandler *set_signal_handler (); -#endif /* _POSIX_VERSION */ +#if defined (RLIMTYPE) +extern RLIMTYPE string_to_rlimtype __P((char *)); +extern void print_rlimtype __P((RLIMTYPE, int)); +#endif -/* This function is defined in trap.c. */ -extern SigHandler *set_sigint_handler __P((void)); +extern void timeval_to_secs (); +extern void print_timeval (); +extern void clock_t_to_secs (); +extern void print_time_in_hz (); -/* Declarations for functions defined in general.c */ -extern char *xmalloc __P((int)); -extern char *xrealloc __P((void *, int)); -extern void xfree __P((char *)); -extern char *itos __P((int)); extern int all_digits __P((char *)); -extern long string_to_long __P((char *)); +extern int legal_number __P((char *, long *)); extern int legal_identifier __P((char *)); extern int check_identifier __P((WORD_DESC *, int)); + extern void unset_nodelay_mode __P((int)); -extern void map_over_words __P((WORD_LIST *, Function *)); - -extern void map_over_list __P((GENERIC_LIST *, Function *)); -extern GENERIC_LIST *reverse_list (); -extern GENERIC_LIST *delete_element (); -extern GENERIC_LIST *list_append (); -extern int list_length (); -extern int qsort_string_compare (); - -extern int find_name_in_list __P((char *, char **)); -extern int array_len __P((char **)); -extern void free_array __P((char **)); -extern char **copy_array __P((char **)); -extern void strip_leading __P((char *)); -extern void strip_trailing __P((char *, int)); +extern void check_dev_tty __P((void)); +extern int same_file (); /* too many problems with prototype */ +extern int move_to_high_fd __P((int, int)); +extern int check_binary_file __P((unsigned char *, int)); + extern char *canonicalize_pathname __P((char *)); extern char *make_absolute __P((char *, char *)); extern int absolute_pathname __P((char *)); extern int absolute_program __P((char *)); extern char *base_pathname __P((char *)); extern char *full_pathname __P((char *)); -extern char *strindex __P((char *, char *)); -extern void set_lines_and_columns __P((int, int)); -extern void xbcopy __P((char *, char *, int)); extern char *polite_directory_format __P((char *)); -extern void tilde_initialize __P((void)); - -#if !defined (strerror) -extern char *strerror __P((int)); -#endif - -#if defined (RLIMTYPE) -extern RLIMTYPE string_to_rlimtype __P((char *)); -extern void print_rlimtype __P((RLIMTYPE, int)); -#endif - -#if !defined (HAVE_STRCASECMP) -extern int strnicmp __P((char *, char *, int)); -extern int stricmp __P((char *, char *)); -#else /* HAVE_STRCASECMP */ -# define stricmp strcasecmp -# define strnicmp strncasecmp -#endif /* HAVE_STRCASECMP */ -extern int dup2 __P((int, int)); -extern char *getwd __P((char *)); -extern int getdtablesize __P((void)); +extern char *extract_colon_unit __P((char *, int *)); -#if defined (USG) && !defined (HAVE_GETHOSTNAME) -extern int gethostname __P((char *, int)); -#endif /* USG && !HAVE_GETHOSTNAME */ +extern void tilde_initialize __P((void)); +extern char *bash_tilde_expand __P((char *)); -#endif /* _GENERAL_H */ +#endif /* _GENERAL_H_ */ diff --git a/getcwd.c b/getcwd.c index 6f6eed3..40ae586 100644 --- a/getcwd.c +++ b/getcwd.c @@ -18,6 +18,10 @@ not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include "config.h" + +#if !defined (HAVE_GETCWD) + #include "bashtypes.h" #include @@ -25,22 +29,14 @@ # include #endif -#if defined (HAVE_DIRENT_H) -# include -#else -# include -# if !defined (dirent) -# define dirent direct -# endif /* !dirent */ -#endif /* !HAVE_DIRENT_H */ - #if defined (HAVE_UNISTD_H) # include #endif +#include "posixdir.h" #include "posixstat.h" #include "maxpath.h" -#include "config.h" +#include "memalloc.h" #if defined (HAVE_STDLIB_H) # include @@ -54,7 +50,6 @@ # include #endif /* !HAVE_STRING_H */ -/* Not all systems declare ERRNO in errno.h... and some systems #define it! */ #if !defined (errno) extern int errno; #endif /* !errno */ @@ -75,29 +70,7 @@ extern int errno; # endif /* !MAXPATHLEN */ #endif /* !PATH_MAX */ -#if defined (_POSIX_VERSION) || defined (USGr3) || defined (HAVE_DIRENT_H) -# if !defined (HAVE_DIRENT) -# define HAVE_DIRENT -# endif /* !HAVE_DIRENT */ -#endif /* _POSIX_VERSION || USGr3 || HAVE_DIRENT_H */ - -#if defined (HAVE_DIRENT) -# define D_NAMLEN(d) (strlen ((d)->d_name)) -#else -# define D_NAMLEN(d) ((d)->d_namlen) -#endif /* ! (_POSIX_VERSION || USGr3) */ - -#if defined (USG) || defined (USGr3) -# define d_fileno d_ino -#endif - -#if !defined (alloca) -extern char *alloca (); -#endif /* alloca */ - -/* Heuristic to tell whether or not the current machine has lstat(2). - Can probably be fooled easily. */ -#if !defined (S_ISLNK) +#if !defined (HAVE_LSTAT) # define lstat stat #endif @@ -342,3 +315,4 @@ main (argc, argv) } } #endif /* TEST */ +#endif /* !HAVE_GETCWD */ diff --git a/hash.c b/hashlib.c similarity index 82% rename from hash.c rename to hashlib.c index b955b3f..37e4dc9 100644 --- a/hash.c +++ b/hashlib.c @@ -1,4 +1,4 @@ -/* Hash.c -- Where hashing for bash is done. */ +/* hashlib.c -- functions to manage and access hash tables for bash. */ /* Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc. @@ -18,8 +18,7 @@ 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, 675 Mass Ave, Cambridge, MA 02139, USA. */ -/* There appears to be library functions for this stuff, but it seems like - a lot of overhead, so I just implemented this hashing stuff on my own. */ +#include "config.h" #if defined (HAVE_STRING_H) # include @@ -33,12 +32,12 @@ Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ # include "ansi_stdlib.h" #endif /* HAVE_STDLIB_H */ -#include "shell.h" -#include "hash.h" - -HASH_TABLE *hashed_filenames; +#if defined (HAVE_UNISTD_H) +# include +#endif -#define FILENAME_HASH_BUCKETS 107 +#include "shell.h" +#include "hashlib.h" /* Zero the buckets in TABLE. */ static void @@ -56,8 +55,9 @@ HASH_TABLE * make_hash_table (buckets) int buckets; { - HASH_TABLE *new_table = (HASH_TABLE *)xmalloc (sizeof (HASH_TABLE)); + HASH_TABLE *new_table; + new_table = (HASH_TABLE *)xmalloc (sizeof (HASH_TABLE)); if (buckets == 0) buckets = DEFAULT_HASH_BUCKETS; @@ -69,15 +69,6 @@ make_hash_table (buckets) return (new_table); } -#if 0 -/* UNUSED */ -/* Create the hash table for filenames that we use in the shell. */ -initialize_hashed_filenames () -{ - hashed_filenames = make_hash_table (FILENAME_HASH_BUCKETS); -} -#endif - /* Return the location of the bucket which should contain the data for STRING. TABLE is a pointer to a HASH_TABLE. */ @@ -107,21 +98,18 @@ find_hash_item (string, table) BUCKET_CONTENTS *list; int which_bucket; - if (!table) + if (table == 0) return (BUCKET_CONTENTS *)NULL; which_bucket = hash_string (string, table); - list = table->bucket_array[which_bucket]; - - while (list) + for (list = table->bucket_array[which_bucket]; list; list = list->next) { if (STREQ (list->key, string)) { list->times_found++; return (list); } - else list = list->next; } return (BUCKET_CONTENTS *)NULL; } @@ -137,14 +125,12 @@ remove_hash_item (string, table) int the_bucket; BUCKET_CONTENTS *prev, *temp; - if (!table) + if (table == 0) return (BUCKET_CONTENTS *)NULL; the_bucket = hash_string (string, table); prev = (BUCKET_CONTENTS *)NULL; - temp = table->bucket_array[the_bucket]; - - while (temp) + for (temp = table->bucket_array[the_bucket]; temp; temp = temp->next) { if (STREQ (temp->key, string)) { @@ -157,7 +143,6 @@ remove_hash_item (string, table) return (temp); } prev = temp; - temp = temp->next; } return ((BUCKET_CONTENTS *) NULL); } @@ -170,13 +155,14 @@ add_hash_item (string, table) HASH_TABLE *table; { BUCKET_CONTENTS *item; + int bucket; - if (!table) + if (table == 0) table = make_hash_table (0); if ((item = find_hash_item (string, table)) == 0) { - int bucket = hash_string (string, table); + bucket = hash_string (string, table); item = table->bucket_array[bucket]; while (item && item->next) @@ -204,6 +190,37 @@ add_hash_item (string, table) return (item); } +/* Remove and discard all entries in TABLE. If FREE_DATA is non-null, it + is a function to call to dispose of a hash item's data. Otherwise, + free() is called. */ +void +flush_hash_table (table, free_data) + HASH_TABLE *table; + VFunction *free_data; +{ + int i; + register BUCKET_CONTENTS *bucket, *item; + + for (i = 0; i < table->nbuckets; i++) + { + bucket = table->bucket_array[i]; + + while (bucket) + { + item = bucket; + bucket = bucket->next; + + if (free_data) + (*free_data) (item->data); + else + free (item->data); + free (item->key); + free (item); + } + table->bucket_array[i] = (BUCKET_CONTENTS *)NULL; + } +} + /* Return the bucket_contents list of bucket BUCKET in TABLE. If TABLE doesn't have BUCKET buckets, return NULL. */ #undef get_hash_bucket @@ -233,7 +250,7 @@ xmalloc (bytes) char *result = (char *)malloc (bytes); if (!result) { - fprintf (stderr, "Out of memory!"); + fprintf (stderr, "hash: out of virtual memory\n"); abort (); } return (result); @@ -246,7 +263,7 @@ main () BUCKET_CONTENTS *tt; table = make_hash_table (NBUCKETS); - + for (;;) { char *temp_string; @@ -266,7 +283,7 @@ main () count++; } } - + printf ("You have entered %d (%d) items. The distribution is:\n", table->nentries, count); @@ -276,7 +293,7 @@ main () { int bcount; register BUCKET_CONTENTS *list = get_hash_bucket (count, table); - + printf ("slot %3d: ", count); bcount = 0; @@ -289,9 +306,3 @@ main () } #endif /* TEST_HASHING */ - -/* - * Local variables: - * compile-command: "gcc -g -DTEST_HASHING -o hash hash.c" - * end: - */ diff --git a/hash.h b/hashlib.h similarity index 92% rename from hash.h rename to hashlib.h index 5458787..95a9164 100644 --- a/hash.h +++ b/hashlib.h @@ -1,4 +1,4 @@ -/* hash.h -- the data structures used in hashing in Bash. */ +/* hashlib.h -- the data structures used in hashing in Bash. */ /* Copyright (C) 1993 Free Software Foundation, Inc. @@ -18,8 +18,8 @@ with Bash; see the file COPYING. If not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ -#if !defined (_HASH_H_) -#define _HASH_H_ +#if !defined (_HASHLIB_H_) +#define _HASHLIB_H_ typedef struct bucket_contents { struct bucket_contents *next; /* Link to next hashed key in this bucket. */ @@ -40,6 +40,7 @@ extern BUCKET_CONTENTS *find_hash_item (); extern BUCKET_CONTENTS *remove_hash_item (); extern BUCKET_CONTENTS *add_hash_item (); extern BUCKET_CONTENTS *get_hash_bucket (); +extern void flush_hash_table (); /* Redefine the function as a macro for speed. */ #define get_hash_bucket(bucket, table) \ @@ -58,4 +59,4 @@ extern BUCKET_CONTENTS *get_hash_bucket (); # endif /* !__STDC__ */ #endif /* !NULL */ -#endif /* _HASH_H */ +#endif /* _HASHLIB_H */ diff --git a/input.c b/input.c index 852d369..c543ce7 100644 --- a/input.c +++ b/input.c @@ -18,7 +18,7 @@ with Bash; see the file COPYING. If not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ -/* similar to stdio, but input-only. */ +#include "config.h" #include "bashtypes.h" #include @@ -27,16 +27,69 @@ #include #include +#if defined (HAVE_UNISTD_H) +# include +#endif + #include "bashansi.h" -#include "config.h" #include "command.h" #include "general.h" #include "input.h" +#include "error.h" +#include "externs.h" #if !defined (errno) extern int errno; #endif /* !errno */ +/* Functions to handle reading input on systems that don't restart read(2) + if a signal is received. */ + +#if !defined (HAVE_RESTARTABLE_SYSCALLS) +static unsigned char localbuf[128]; +static int local_index, local_bufused; + +/* Posix and USG systems do not guarantee to restart read () if it is + interrupted by a signal. We do the read ourselves, and restart it + if it returns EINTR. */ +int +getc_with_restart (stream) + FILE *stream; +{ + /* Try local buffering to reduce the number of read(2) calls. */ + if (local_index == local_bufused || local_bufused == 0) + { + while (1) + { + local_bufused = read (fileno (stream), localbuf, sizeof(localbuf)); + if (local_bufused > 0) + break; + else if (local_bufused == 0 || errno != EINTR) + { + local_index = 0; + return EOF; + } + } + local_index = 0; + } + return (localbuf[local_index++]); +} + +int +ungetc_with_restart (c, stream) + int c; + FILE *stream; +{ + if (local_index == 0 || c == EOF) + return EOF; + return (localbuf[--local_index] = c); +} +#endif /* !HAVE_RESTARTABLE_SYSCALLS */ + +#if defined (BUFFERED_INPUT) + +/* A facility similar to stdio, but input-only. */ + #define MAX_INPUT_BUFFER_SIZE 8192 #if !defined (SEEK_CUR) @@ -45,16 +98,19 @@ extern int errno; void free_buffered_stream (); +extern int return_EOF (); + extern int interactive_shell; int bash_input_fd_changed; + /* This provides a way to map from a file descriptor to the buffer associated with that file descriptor, rather than just the other way around. This is needed so that buffers are managed properly in constructs like 3<&4. buffers[x]->b_fd == x -- that is how the correspondence is maintained. */ BUFFERED_STREAM **buffers = (BUFFERED_STREAM **)NULL; -static int nbuffers = 0; +static int nbuffers; #define max(a, b) (((a) > (b)) ? (a) : (b)) @@ -94,9 +150,7 @@ make_buffered_stream (fd, buffer, bufsize) bp->b_fd = fd; bp->b_buffer = buffer; bp->b_size = bufsize; - bp->b_used = 0; - bp->b_inputp = 0; - bp->b_flag = 0; + bp->b_used = bp->b_inputp = bp->b_flag = 0; if (bufsize == 1) bp->b_flag |= B_UNBUFF; return (bp); @@ -145,9 +199,7 @@ check_bash_input (fd) if (nfd == -1) { if (fcntl (fd, F_GETFD, 0) == 0) - report_error - ("cannot allocate new file descriptor for bash input from fd %d: %s", - fd, strerror (errno)); + sys_error ("cannot allocate new file descriptor for bash input from fd %d", fd); return -1; } @@ -155,7 +207,7 @@ check_bash_input (fd) { /* What's this? A stray buffer without an associated open file descriptor? Free up the buffer and report the error. */ - report_error ("check_bash_input: buffer already exists for new fd %d", nfd); + internal_error ("check_bash_input: buffer already exists for new fd %d", nfd); free_buffered_stream (buffers[nfd]); } @@ -185,6 +237,7 @@ check_bash_input (fd) BUFFERED_STREAM corresponding to fd2 is deallocated, if one exists. BUFFERS[fd1] is copied to BUFFERS[fd2]. This is called by the redirect code for constructs like 4<&0 and 3b_fd = fd2; - if (is_bash_input) - { - if (!buffers[fd2]) - fd_to_buffered_stream (fd2); - } + if (is_bash_input && !buffers[fd2]) + fd_to_buffered_stream (fd2); + return (fd2); } @@ -256,9 +307,7 @@ open_buffered_stream (file) int fd; fd = open (file, O_RDONLY); - if (fd == -1) - return ((BUFFERED_STREAM *)NULL); - return (fd_to_buffered_stream (fd)); + return ((fd >= 0) ? fd_to_buffered_stream (fd) : (BUFFERED_STREAM *)NULL); } /* Deallocate a buffered stream and free up its resources. Make sure we @@ -354,7 +403,7 @@ sync_buffered_stream (bfd) int bfd; { BUFFERED_STREAM *bp; - int chars_left; + off_t chars_left; bp = buffers[bfd]; if (!bp) @@ -386,15 +435,16 @@ with_input_from_buffered_stream (bfd, name) char *name; { INPUT_STREAM location; + BUFFERED_STREAM *bp; location.buffered_fd = bfd; /* Make sure the buffered stream exists. */ - fd_to_buffered_stream (bfd); - init_yy_io (buffered_getchar, buffered_ungetchar, st_bstream, name, location); + bp = fd_to_buffered_stream (bfd); + init_yy_io (bp == 0 ? return_EOF : buffered_getchar, + buffered_ungetchar, st_bstream, name, location); } #if defined (TEST) - char * xmalloc(s) int s; @@ -461,4 +511,5 @@ char **argv; } exit(0); } -#endif +#endif /* TEST */ +#endif /* BUFFERED_INPUT */ diff --git a/input.h b/input.h index 1824b40..64f66be 100644 --- a/input.h +++ b/input.h @@ -17,28 +17,23 @@ with Bash; see the file COPYING. If not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ -#if !defined (_INPUT_H) -#define _INPUT_H +#if !defined (_INPUT_H_) +#define _INPUT_H_ #include "stdc.h" /* Function pointers can be declared as (Function *)foo. */ -#if !defined (__FUNCTION_DEF) -# define __FUNCTION_DEF +#if !defined (_FUNCTION_DEF) +# define _FUNCTION_DEF typedef int Function (); typedef void VFunction (); typedef char *CPFunction (); typedef char **CPPFunction (); #endif /* _FUNCTION_DEF */ -/* Some stream `types'. */ -#define st_none 0 -#define st_stream 1 -#define st_string 2 -#define st_stdin 3 +enum stream_type {st_none, st_stdin, st_stream, st_string, st_bstream}; #if defined (BUFFERED_INPUT) -#define st_bstream 4 /* Possible values for b_flag. */ #define B_EOF 0x1 @@ -74,7 +69,7 @@ typedef union { } INPUT_STREAM; typedef struct { - int type; + enum stream_type type; char *name; INPUT_STREAM location; Function *getter; @@ -89,14 +84,19 @@ extern void init_yy_io __P((Function *, Function *, int, char *, INPUT_STREAM)); extern void with_input_from_stdin __P((void)); extern void with_input_from_string __P((char *, char *)); extern void with_input_from_stream __P((FILE *, char *)); -extern int push_stream __P((void)); -extern int pop_stream __P((void)); +extern void push_stream __P((int)); +extern void pop_stream __P((void)); +extern int stream_on_stack __P((enum stream_type)); extern char *read_secondary_line __P((int)); extern int find_reserved_word __P((char *)); extern char *decode_prompt_string __P((char *)); extern void gather_here_documents __P((void)); extern void execute_prompt_command __P((char *)); +/* Functions from input.c */ +extern int getc_with_restart (); +extern int ungetc_with_restart (); + #if defined (BUFFERED_INPUT) /* Functions from input.c. */ extern int check_bash_input __P((int)); @@ -112,4 +112,4 @@ extern int buffered_ungetchar __P((int)); extern void with_input_from_buffered_stream __P((int, char *)); #endif /* BUFFERED_INPUT */ -#endif /* _INPUT_H */ +#endif /* _INPUT_H_ */ diff --git a/jobs.c b/jobs.c index 40e7f7d..28e4548 100644 --- a/jobs.c +++ b/jobs.c @@ -1,6 +1,7 @@ /* The thing that makes children, remembers them, and contains wait loops. */ -/* This file works with both POSIX and BSD systems. */ +/* This file works with both POSIX and BSD systems. It implements job + control. */ /* Copyright (C) 1989, 1992 Free Software Foundation, Inc. @@ -20,30 +21,25 @@ with Bash; see the file COPYING. If not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ -/* Something that can be ignored. */ -#define IGNORE_ARG (char *)0 - #include "config.h" -#if !defined (JOB_CONTROL) -#include "nojobs.c" -#else /* JOB_CONTROL */ - #include "bashtypes.h" #include "trap.h" #include #include #include -#if !defined (USG) || defined (HAVE_RESOURCE) -#include -#endif /* USG */ +#if defined (HAVE_UNISTD_H) +# include +#endif -#if !defined (_POSIX_VERSION) -# if defined (HAVE_RESOURCE) -# include -# endif -#endif /* _POSIX_VERSION */ +#if defined (HAVE_SYS_TIME_H) +# include +#endif + +#if defined (HAVE_SYS_RESOURCE_H) && defined (HAVE_WAIT3) && !defined (_POSIX_VERSION) +# include +#endif /* !_POSIX_VERSION && HAVE_SYS_RESOURCE_H && HAVE_WAIT3 */ #include #include "filecntl.h" @@ -54,68 +50,105 @@ # include "input.h" #endif -/* Terminal handling stuff, to save and restore tty state. */ -#define NEW_TTY_DRIVER +/* Need to include this up here for *_TTY_DRIVER definitions. */ +#include "bashtty.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 */ -#if defined (_POSIX_VERSION) && !defined (TERMIOS_MISSING) -# undef NEW_TTY_DRIVER -# define TERMIOS_TTY_DRIVER -# if defined (sun) && !defined (_POSIX_SOURCE) /* XXX - SunOS4, SunOS5? */ +/* The _POSIX_SOURCE define is to avoid multiple symbol definitions + between sys/ioctl.h and termios.h. Ditto for the test against SunOS4 + and the undefining of several symbols. */ +#if defined (TERMIOS_TTY_DRIVER) +# if (defined (SunOS4) || defined (SunOS5)) && !defined (_POSIX_SOURCE) # define _POSIX_SOURCE # endif -#else /* !_POSIX_VERSION */ -# if defined (USG) || defined (hpux) || defined (Xenix) || defined (sgi) -# undef NEW_TTY_DRIVER -# define TERMIO_TTY_DRIVER -# endif /* USG | hpux | Xenix | sgi */ -#endif /* !_POSIX_VERSION */ - -/* Include the right header file for the specific type of terminal - handler installed on this system. */ -#if defined (NEW_TTY_DRIVER) -#include -#endif - -#if defined (TERMIO_TTY_DRIVER) -#include -#endif - -#if defined (TERMIOS_TTY_DRIVER) -/* For Sun workstations we undefine a couple of defines so that - the inclusion of termios.h won't cause complaints. */ # if defined (SunOS4) # undef ECHO # undef NOFLSH # undef TOSTOP # endif /* SunOS4 */ # include -#endif /* TERMIOS_TTY_DRIVER */ +#else /* !TERMIOS_TTY_DRIVER */ +# if defined (TERMIO_TTY_DRIVER) +# include +# else +# include +# endif +#endif /* !TERMIOS_TTY_DRIVER */ /* For the TIOCGPGRP and TIOCSPGRP ioctl parameters on HP-UX */ - #if defined (hpux) && !defined (TERMIOS_TTY_DRIVER) # include #endif /* hpux && !TERMIOS_TTY_DRIVER */ +/* For struct winsize on SCO */ +/* sys/ptem.h has winsize but needs mblk_t from sys/stream.h */ +#if defined (HAVE_SYS_PTEM_H) && defined (TIOCGWINSZ) && defined (SIGWINCH) +# if defined (HAVE_SYS_STREAM_H) +# include +# endif +# include +#endif + #include "bashansi.h" #include "shell.h" #include "jobs.h" +#include "flags.h" +#include "error.h" #include "builtins/builtext.h" #include "builtins/common.h" -/* Not all systems declare errno in errno.h... and some systems #define it! */ #if !defined (errno) extern int errno; #endif /* !errno */ +/* 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 */ + +/* The number of additional slots to allocate when we run out. */ +#define JOB_SLOTS 8 + /* Variables used here but defined in other files. */ extern int interactive, interactive_shell, asynchronous_notification; -extern int subshell_environment; +extern int startup_state, subshell_environment, line_number; extern int posixly_correct, no_symbolic_links, shell_level; extern int interrupt_immediately, last_command_exit_value; extern int loop_level, breaking; @@ -123,15 +156,20 @@ extern Function *this_shell_builtin; extern char *shell_name, *this_command_name; extern sigset_t top_level_mask; +#if defined (ARRAY_VARS) +static int *pstatuses; /* list of pipeline statuses */ +static int statsize; +static void set_pipestatus_array (); +#endif +static void setjstatus (); +static void get_new_window_size (); + /* The array of known jobs. */ JOB **jobs = (JOB **)NULL; /* The number of slots currently allocated to JOBS. */ int job_slots = 0; -/* The number of additional slots to allocate when we run out. */ -#define JOB_SLOTS 5 - /* The controlling tty for this shell. */ int shell_tty = -1; @@ -153,7 +191,7 @@ pid_t pipeline_pgrp = (pid_t)0; process leader is allowed to continue. */ int pgrp_pipe[2] = { -1, -1 }; #endif - + /* The job which is current; i.e. the one that `%+' stands for. */ int current_job = NO_JOB; @@ -175,9 +213,13 @@ 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 sighandler flush_child (); -static int waitchld(); +static sighandler sigchld_handler (); +static int waitchld (); static PROCESS *find_pipeline (); static char *current_working_directory (); static char *job_working_directory (); @@ -186,19 +228,26 @@ static int set_new_line_discipline (), map_over_jobs (), last_running_job (); static int most_recent_job_in_state (), last_stopped_job (), find_job (); static void notify_of_job_status (), cleanup_dead_jobs (), discard_pipeline (); static void add_process (), set_current_job (), reset_current (); +static void print_pipeline (); static void pretty_print_job (); static void mark_dead_jobs_as_notified (); #if defined (PGRP_PIPE) static void pipe_read (), pipe_close (); #endif -static int waiting_for_job, sigchld; +/* Used to synchronize between wait_for and the SIGCHLD signal handler. */ +static int sigchld; +static int waiting_for_job; + +/* 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 freeze_jobs_list; +static int jobs_list_frozen; #if !defined (_POSIX_VERSION) @@ -219,34 +268,6 @@ tcgetpgrp (fd) return (pgrp); } -/* 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 ("Bad code in jobs.c: sigprocmask"); - } - - if (oldset) - *oldset = old; -} #endif /* !_POSIX_VERSION */ /* Return the working directory for the current process. Unlike @@ -257,24 +278,21 @@ static char * current_working_directory () { char *dir; - static char d[MAXPATHLEN]; + static char d[PATH_MAX]; dir = get_string_value ("PWD"); - if (!dir && the_current_working_directory && no_symbolic_links) + if (dir == 0 && the_current_working_directory && no_symbolic_links) dir = the_current_working_directory; - if (!dir) + if (dir == 0) { - dir = getwd (d); + dir = getcwd (d, sizeof(d)); if (dir) dir = d; } - if (!dir) - return (""); - else - return (dir); + return (dir == 0) ? "" : dir; } /* Return the working directory for the current process. */ @@ -320,14 +338,36 @@ cleanup_the_pipeline () } } +void +save_pipeline (clear) + int clear; +{ + saved_pipeline = the_pipeline; + saved_already_making_children = already_making_children; + if (clear) + the_pipeline = (PROCESS *)NULL; +} + +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) { - discard_pipeline (the_pipeline); - the_pipeline = (PROCESS *)NULL; + cleanup_the_pipeline (); pipeline_pgrp = 0; #if defined (PGRP_PIPE) pipe_close (pgrp_pipe); @@ -338,7 +378,7 @@ start_pipeline () if (job_control) { if (pipe (pgrp_pipe) == -1) - internal_error ("start_pipeline: pgrp pipe"); + sys_error ("start_pipeline: pgrp pipe"); } #endif } @@ -353,7 +393,7 @@ stop_pipeline (async, deferred) COMMAND *deferred; { register int i, j; - JOB *newjob = (JOB *)NULL; + JOB *newjob; sigset_t set, oset; BLOCK_CHILD (set, oset); @@ -362,13 +402,13 @@ stop_pipeline (async, deferred) /* The parent closes the process group synchronization pipe. */ pipe_close (pgrp_pipe); #endif - + cleanup_dead_jobs (); - if (!job_slots) + if (job_slots == 0) { - jobs = - (JOB **)xmalloc ((job_slots = JOB_SLOTS) * sizeof (JOB *)); + job_slots = JOB_SLOTS; + jobs = (JOB **)xmalloc (job_slots * sizeof (JOB *)); /* Now blank out these new entries. */ for (i = 0; i < job_slots; i++) @@ -390,7 +430,7 @@ stop_pipeline (async, deferred) us from continuously reallocating the jobs array when running certain kinds of shell loops, and saves time spent searching. */ for (i = 0; i < job_slots; i++) - if (!jobs[i]) + if (jobs[i] == 0) break; } @@ -408,13 +448,16 @@ stop_pipeline (async, deferred) if (the_pipeline) { register PROCESS *p; + int any_alive, any_stopped; newjob = (JOB *)xmalloc (sizeof (JOB)); - for (p = the_pipeline; p->next != the_pipeline; p = p->next); + for (p = the_pipeline; p->next != the_pipeline; p = p->next) + ; p->next = (PROCESS *)NULL; newjob->pipe = REVERSE_LIST (the_pipeline, PROCESS *); - for (p = newjob->pipe; p->next; p = p->next); + for (p = newjob->pipe; p->next; p = p->next) + ; p->next = newjob->pipe; the_pipeline = (PROCESS *)NULL; @@ -428,37 +471,29 @@ stop_pipeline (async, deferred) newjob->flags |= J_JOBCONTROL; /* Set the state of this pipeline. */ - { - register PROCESS *p = newjob->pipe; - register int any_alive = 0; - register int any_stopped = 0; - - do - { - any_alive |= p->running; - any_stopped |= WIFSTOPPED (p->status); - p = p->next; - } - while (p != newjob->pipe); - - if (any_alive) - { - newjob->state = JRUNNING; - } - else - { - if (any_stopped) - newjob->state = JSTOPPED; - else - newjob->state = JDEAD; - } - } + p = newjob->pipe; + any_alive = any_stopped = 0; + do + { + any_alive |= p->running; + any_stopped |= WIFSTOPPED (p->status); + p = p->next; + } + while (p != newjob->pipe); + newjob->state = any_alive ? JRUNNING : (any_stopped ? JSTOPPED : JDEAD); newjob->wd = job_working_directory (); newjob->deferred = deferred; + newjob->j_cleanup = (VFunction *)NULL; + newjob->cleanarg = (PTR_T) NULL; + jobs[i] = newjob; + if (newjob->state == JDEAD && (newjob->flags & J_FOREGROUND)) + setjstatus (i); } + else + newjob = (JOB *)NULL; if (async) { @@ -497,13 +532,13 @@ cleanup_dead_jobs () register int i; sigset_t set, oset; - if (!job_slots || freeze_jobs_list) + if (job_slots == 0 || jobs_list_frozen) return; BLOCK_CHILD (set, oset); for (i = 0; i < job_slots; i++) - if (jobs[i] && JOBSTATE (i) == JDEAD && (jobs[i]->flags & J_NOTIFIED)) + if (jobs[i] && DEADJOB (i) && IS_NOTIFIED (i)) delete_job (i); UNBLOCK_CHILD (oset); @@ -517,7 +552,7 @@ delete_job (job_index) { register JOB *temp; - if (freeze_jobs_list) + if (jobs_list_frozen) return; temp = jobs[job_index]; @@ -535,6 +570,18 @@ delete_job (job_index) free (temp); } +/* Must be called with SIGCHLD blocked. */ +void +nohup_job (job_index) + int job_index; +{ + register JOB *temp; + + temp = jobs[job_index]; + if (temp) + temp->flags |= J_NOHUP; +} + /* Get rid of the data structure associated with a process chain. */ static void discard_pipeline (chain) @@ -546,8 +593,7 @@ discard_pipeline (chain) do { next = this->next; - if (this->command) - free (this->command); + FREE (this->command); free (this); this = next; } @@ -562,8 +608,9 @@ add_process (name, pid) char *name; pid_t pid; { - PROCESS *t = (PROCESS *)xmalloc (sizeof (PROCESS)); + PROCESS *t, *p; + t = (PROCESS *)xmalloc (sizeof (PROCESS)); t->next = the_pipeline; t->pid = pid; WSTATUS (t->status) = 0; @@ -571,12 +618,11 @@ add_process (name, pid) t->command = name; the_pipeline = t; - if (!(t->next)) + if (t->next == 0) t->next = t; else { - register PROCESS *p = t->next; - + p = t->next; while (p->next != t->next) p = p->next; p->next = t; @@ -586,6 +632,7 @@ add_process (name, pid) #if 0 /* Take the last job and make it the first job. Must be called with SIGCHLD blocked. */ +int rotate_the_pipeline () { PROCESS *p; @@ -599,6 +646,7 @@ rotate_the_pipeline () /* Reverse the order of the processes in the_pipeline. Must be called with SIGCHLD blocked. */ +int reverse_the_pipeline () { PROCESS *p, *n; @@ -633,9 +681,8 @@ map_over_jobs (func, arg1, arg2) sigset_t set, oset; BLOCK_CHILD (set, oset); - result = 0; - for (i = 0; i < job_slots; i++) + for (i = result = 0; i < job_slots; i++) { if (jobs[i]) { @@ -646,6 +693,7 @@ map_over_jobs (func, arg1, arg2) } UNBLOCK_CHILD (oset); + return (result); } @@ -668,7 +716,7 @@ terminate_stopped_jobs () for (i = 0; i < job_slots; i++) { - if (jobs[i] && (JOBSTATE (i) == JSTOPPED)) + if (jobs[i] && STOPPED (i)) { killpg (jobs[i]->pgrp, SIGTERM); killpg (jobs[i]->pgrp, SIGCONT); @@ -676,7 +724,8 @@ terminate_stopped_jobs () } } -/* Cause all jobs, running or stopped, to receive a hangup signal. */ +/* 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 () { @@ -686,8 +735,9 @@ hangup_all_jobs () { if (jobs[i]) { - killpg (jobs[i]->pgrp, SIGHUP); - if (JOBSTATE (i) == JSTOPPED) + if ((jobs[i]->flags & J_NOHUP) == 0) + killpg (jobs[i]->pgrp, SIGHUP); + if (STOPPED (i)) killpg (jobs[i]->pgrp, SIGCONT); } } @@ -707,12 +757,12 @@ find_pipeline (pid) pid_t pid; { int job; + register PROCESS *p; /* See if this process is in the pipeline that we are building. */ if (the_pipeline) { - register PROCESS *p = the_pipeline; - + p = the_pipeline; do { /* Return it if we found it. */ @@ -726,10 +776,7 @@ find_pipeline (pid) job = find_job (pid); - if (job == NO_JOB) - return ((PROCESS *)NULL); - else - return (jobs[job]->pipe); + return (job == NO_JOB) ? (PROCESS *)NULL : jobs[job]->pipe; } /* Return the job index that PID belongs to, or NO_JOB if it doesn't @@ -774,9 +821,9 @@ describe_pid (pid) job = find_job (pid); if (job != NO_JOB) - printf ("[%d] %d\n", job + 1, pid); + printf ("[%d] %d\n", job + 1, (int)pid); else - programming_error ("describe_pid: No such pid (%d)!\n", pid); + programming_error ("describe_pid: %d: no such pid", (int)pid); UNBLOCK_CHILD (oset); } @@ -797,67 +844,49 @@ describe_pid (pid) 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 -pretty_print_job (job_index, format, stream) +print_pipeline (p, job_index, format, stream) + PROCESS *p; int job_index, format; FILE *stream; { - register PROCESS *p, *first, *last; - int name_padding; - char retcode_name_buffer[20]; - sigset_t set, oset; - - BLOCK_CHILD (set, oset); + PROCESS *first, *last, *show; + int es, name_padding; + char retcode_name_buffer[20], *temp; - /* Format only pid information about the process group leader? */ - if (format == JLIST_PID_ONLY) - { - fprintf (stream, "%d\n", jobs[job_index]->pipe->pid); - UNBLOCK_CHILD (oset); - return; - } - - if (format == JLIST_CHANGED_ONLY) - { - if (jobs[job_index]->flags & J_NOTIFIED) - { - UNBLOCK_CHILD (oset); - return; - } - format = JLIST_STANDARD; - } - - fprintf (stream, "[%d]%c ", job_index + 1, - (job_index == current_job) ? '+': - (job_index == previous_job) ? '-' : ' '); + if (p == 0) + return; - first = last = p = jobs[job_index]->pipe; + first = last = p; while (last->next != first) last = last->next; - /* 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; - for (;;) { if (p != first) fprintf (stream, format ? " " : " |"); - if (format) - fprintf (stream, "%5d", p->pid); + if (format != JLIST_STANDARD) + fprintf (stream, "%5d", (int)p->pid); fprintf (stream, " "); - if (format > -1) + if (format > -1 && job_index >= 0) { - PROCESS *show = format ? p : last; - char *temp = "Done"; + show = format ? p : last; + temp = "Done"; - if (JOBSTATE (job_index) == JSTOPPED && !format) + if (STOPPED (job_index) && format == 0) temp = "Stopped"; - if (JOBSTATE (job_index) == JRUNNING) + else if (RUNNING (job_index)) temp = "Running"; else { @@ -867,17 +896,15 @@ pretty_print_job (job_index, format, stream) temp = strsignal (WTERMSIG (show->status)); else if (WIFEXITED (show->status)) { - int exit_status; - temp = retcode_name_buffer; - exit_status = WEXITSTATUS (show->status); + es = WEXITSTATUS (show->status); - if (!exit_status) + if (es == 0) strcpy (temp, "Done"); else if (posixly_correct) - sprintf (temp, "Done(%d)", exit_status); + sprintf (temp, "Done(%d)", es); else - sprintf (temp, "Exit %d", exit_status); + sprintf (temp, "Exit %d", es); } else temp = "Unknown status"; @@ -897,17 +924,16 @@ pretty_print_job (job_index, format, stream) if (temp) { - int templ = strlen (temp); fprintf (stream, "%s", temp); - if (templ) - name_padding = LONGEST_SIGNAL_DESC - templ; - else - name_padding = LONGEST_SIGNAL_DESC - 2; /* strlen ("| ") */ + 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) && (WIFCORED (show->status))) + if ((WIFSTOPPED (show->status) == 0) && WIFCORED (show->status)) fprintf (stream, "(core dumped) "); } } @@ -918,17 +944,16 @@ pretty_print_job (job_index, format, stream) if (p->command) fprintf (stream, "%s", p->command); - if (p == last) + if (p == last && job_index >= 0) { - char *wd = current_working_directory (); + temp = current_working_directory (); - if (JOBSTATE (job_index) == JRUNNING && - !(jobs[job_index]->flags & J_FOREGROUND)) + if (RUNNING (job_index) && (IS_FOREGROUND (job_index) == 0)) fprintf (stream, " &"); - if (strcmp (wd, jobs[job_index]->wd) != 0) + if (strcmp (temp, jobs[job_index]->wd) != 0) fprintf (stream, - " (wd: %s)", polite_directory_format (jobs[job_index]->wd)); + " (wd: %s)", polite_directory_format (jobs[job_index]->wd)); } if (format || (p == last)) @@ -938,28 +963,98 @@ pretty_print_job (job_index, format, stream) break; p = p->next; } - fflush (stream); +} + +static void +pretty_print_job (job_index, format, stream) + int job_index, format; + FILE *stream; +{ + register PROCESS *p; + sigset_t set, oset; + + BLOCK_CHILD (set, oset); + + /* Format only pid information about the process group leader? */ + if (format == JLIST_PID_ONLY) + { + fprintf (stream, "%d\n", (int)jobs[job_index]->pipe->pid); + UNBLOCK_CHILD (oset); + return; + } + + if (format == JLIST_CHANGED_ONLY) + { + if (IS_NOTIFIED (job_index)) + { + UNBLOCK_CHILD (oset); + return; + } + format = JLIST_STANDARD; + } + + if (format != JLIST_NONINTERACTIVE) + fprintf (stream, "[%d]%c ", job_index + 1, + (job_index == current_job) ? '+': + (job_index == previous_job) ? '-' : ' '); + + if (format == JLIST_NONINTERACTIVE) + format = JLIST_LONG; + + p = jobs[job_index]->pipe; + + /* 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; + + print_pipeline (p, job_index, format, stream); + UNBLOCK_CHILD (oset); } -int +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); - return (0); + print_job (job, format, -1, job_index); +} + +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_jobs (format) +list_all_jobs (format) int format; { cleanup_dead_jobs (); - map_over_jobs (list_one_job, format, (int)IGNORE_ARG); + map_over_jobs (print_job, format, -1); } /* Fork, handling errors. Returns the pid of the newly made child, or 0. @@ -995,7 +1090,7 @@ make_child (command, async_p) /* Create the child, handle severe errors. */ if ((pid = fork ()) < 0) { - internal_error ("fork: %s", strerror (errno)); + sys_error ("fork"); /* Kill all of the processes in the current pipeline. */ terminate_current_pipeline (); @@ -1011,8 +1106,9 @@ make_child (command, async_p) { /* In the child. Give this child the right process group, set the signals to the default state for a new process. */ - pid_t mine = getpid (); + pid_t mine; + mine = 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, @@ -1032,22 +1128,14 @@ make_child (command, async_p) /* All processes in this pipeline belong in the same process group. */ - if (!pipeline_pgrp) /* Then this is the first child. */ + if (pipeline_pgrp == 0) /* This is the first child. */ pipeline_pgrp = mine; /* Check for running command in backquotes. */ if (pipeline_pgrp == shell_pgrp) - { - set_signal_handler (SIGTSTP, SIG_IGN); - set_signal_handler (SIGTTOU, SIG_IGN); - set_signal_handler (SIGTTIN, SIG_IGN); - } + ignore_tty_job_signals (); else - { - set_signal_handler (SIGTSTP, SIG_DFL); - set_signal_handler (SIGTTOU, SIG_DFL); - set_signal_handler (SIGTTIN, SIG_DFL); - } + default_tty_job_signals (); /* Set the process group before trying to mess with the terminal's process group. This is mandated by POSIX. */ @@ -1058,13 +1146,12 @@ make_child (command, async_p) B.4.3.3, p. 237 also covers this, in the context of job control shells. */ if (setpgid (mine, pipeline_pgrp) < 0) - internal_error ("child setpgid (%d to %d) error %d: %s\n", - mine, pipeline_pgrp, errno, strerror (errno)); + sys_error ("child setpgid (%d to %d)", mine, pipeline_pgrp); #if defined (PGRP_PIPE) if (pipeline_pgrp == mine) { #endif - if (!async_p) + if (async_p == 0) give_terminal_to (pipeline_pgrp); #if defined (PGRP_PIPE) @@ -1074,7 +1161,7 @@ make_child (command, async_p) } else /* Without job control... */ { - if (!pipeline_pgrp) + if (pipeline_pgrp == 0) pipeline_pgrp = shell_pgrp; /* If these signals are set to SIG_DFL, we encounter the curious @@ -1084,9 +1171,7 @@ make_child (command, async_p) are set to SIG_IGN, jobs started from scripts do not stop when the shell running the script gets a SIGTSTP and stops. */ - set_signal_handler (SIGTSTP, SIG_DFL); - set_signal_handler (SIGTTOU, SIG_DFL); - set_signal_handler (SIGTTIN, SIG_DFL); + default_tty_job_signals (); } #if defined (PGRP_PIPE) @@ -1105,7 +1190,7 @@ make_child (command, async_p) if (job_control) { - if (!pipeline_pgrp) + if (pipeline_pgrp == 0) { pipeline_pgrp = pid; /* Don't twiddle terminal pgrps in the parent! This is the bug, @@ -1120,7 +1205,7 @@ make_child (command, async_p) } else { - if (!pipeline_pgrp) + if (pipeline_pgrp == 0) pipeline_pgrp = shell_pgrp; } @@ -1140,6 +1225,22 @@ make_child (command, async_p) return (pid); } +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. */ @@ -1205,10 +1306,12 @@ draino (fd, ospeed) #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 = input_tty (); + int tty; + tty = input_tty (); if (tty != -1) { #if defined (NEW_TTY_DRIVER) @@ -1228,17 +1331,19 @@ get_tty_state () /* Only print an error message if we're really interactive at this time. */ if (interactive) - internal_error ("[%d: %d] tcgetattr: %s", - getpid (), shell_level, strerror (errno)); + sys_error ("[%d: %d] tcgetattr", getpid (), shell_level); #endif return -1; } #endif /* TERMIOS_TTY_DRIVER */ + if (check_window_size) + get_new_window_size (0); } return 0; } /* Make the current tty use the state in shell_tty_info. */ +int set_tty_state () { int tty = input_tty (); @@ -1264,8 +1369,7 @@ set_tty_state () /* Only print an error message if we're really interactive at this time. */ if (interactive) - internal_error ("[%d: %d] tcsetattr: %s", - getpid (), shell_level, strerror (errno)); + sys_error ("[%d: %d] tcsetattr", getpid (), shell_level); return -1; } #endif /* TERMIOS_TTY_DRIVER */ @@ -1301,18 +1405,15 @@ wait_for_single_pid (pid) pid_t pid; { register PROCESS *child; + sigset_t set, oset; - { - sigset_t set, oset; - - BLOCK_CHILD (set, oset); - child = find_pipeline (pid); - UNBLOCK_CHILD (oset); - } + BLOCK_CHILD (set, oset); + child = find_pipeline (pid); + UNBLOCK_CHILD (oset); - if (!child) + if (child == 0) { - report_error ("wait: pid %d is not a child of this shell", pid); + internal_error ("wait: pid %d is not a child of this shell", pid); return (127); } @@ -1323,32 +1424,32 @@ wait_for_single_pid (pid) void wait_for_background_pids () { - while (1) - { - register int i, count = 0; - sigset_t set, oset; + register int i, count; + sigset_t set, oset; + pid_t pid; + for (;;) + { BLOCK_CHILD (set, oset); + count = 0; for (i = 0; i < job_slots; i++) - if (jobs[i] && (JOBSTATE (i) == JRUNNING) && - (jobs[i]->flags & J_FOREGROUND) == 0) + if (jobs[i] && RUNNING (i) && IS_FOREGROUND (i) == 0) { count++; break; } - if (!count) + if (count == 0) { UNBLOCK_CHILD (oset); break; } for (i = 0; i < job_slots; i++) - if (jobs[i] && (JOBSTATE (i) == JRUNNING) && - (jobs[i]->flags & J_FOREGROUND) == 0) + if (jobs[i] && RUNNING (i) && IS_FOREGROUND (i) == 0) { - pid_t pid = last_pid (i); + pid = last_pid (i); UNBLOCK_CHILD (oset); QUIT; wait_for_single_pid (pid); @@ -1371,7 +1472,7 @@ restore_sigint_handler () } } -static int wait_sigint_received = 0; +static int wait_sigint_received; /* Handle SIGINT while we are waiting for children in a script to exit. The `wait' builtin should be interruptible, but all others should be @@ -1385,16 +1486,17 @@ wait_sigint_handler (sig) { last_command_exit_value = EXECUTION_FAILURE; restore_sigint_handler (); - interrupt_state++; + ADDINTERRUPT; QUIT; } - wait_sigint_received = 1; /* XXX - should this be interrupt_state? */ + /* 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. */ -#if !defined (VOID_SIGHANDLER) - return (0); -#endif /* !VOID_SIGHANDLER */ + SIGRETURN (0); } static int @@ -1403,14 +1505,39 @@ process_exit_status (status) { if (WIFSIGNALED (status)) return (128 + WTERMSIG (status)); - else if (!WIFSTOPPED (status)) + else if (WIFSTOPPED (status) == 0) return (WEXITSTATUS (status)); else return (EXECUTION_SUCCESS); } +static int +job_exit_status (job) + int job; +{ + register PROCESS *p; + for (p = jobs[job]->pipe; p->next != jobs[job]->pipe; p = p->next) + ; + return (process_exit_status (p->status)); +} + /* Wait for pid (one of our children) to terminate, then return the termination state. */ +#define FIND_CHILD(pid, child) \ + do \ + { \ + child = find_pipeline (pid); \ + if (child == 0) \ + { \ + give_terminal_to (shell_pgrp); \ + UNBLOCK_CHILD (oset); \ + internal_error ("wait_for: No record of process %d", pid); \ + restore_sigint_handler (); \ + return (termination_state = 127); \ + } \ + } \ + while (0) + int wait_for (pid) pid_t pid; @@ -1418,6 +1545,10 @@ wait_for (pid) int job, termination_state; register PROCESS *child; sigset_t set, oset; +#if 0 + register PROCESS *p; + int job_state, any_stopped; +#endif /* 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 @@ -1427,112 +1558,105 @@ wait_for (pid) /* 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 + 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) + if (job_control == 0) old_sigint_handler = set_signal_handler (SIGINT, wait_sigint_handler); termination_state = last_command_exit_value; - /* If we say wait_for (), then we have a record of this child somewhere. - If this child and all of its peers are not running, then don't - sigpause (), since there is no need to. */ - wait_loop: - - /* 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) + if (interactive && job_control == 0) QUIT; - child = find_pipeline (pid); + /* 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(). */ - if (!child) + job = NO_JOB; + do { - give_terminal_to (shell_pgrp); - UNBLOCK_CHILD (oset); - programming_error ("wait_for: No record of pid %d", pid); - } + 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. */ + /* 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); - job = find_job (pid); - - if (job != NO_JOB) - { - register int job_state = 0, any_stopped = 0; - register PROCESS *p = jobs[job]->pipe; - - do +#if 0 + /* XXX - let waitchld take care of setting this. If the job has + already exited before this is called, sigchld_handler will have + called waitchld and this will be set to JDEAD. */ + if (job != NO_JOB && JOBSTATE (job) != JDEAD) { - job_state |= p->running; - if (!p->running) - any_stopped |= WIFSTOPPED (p->status); - p = p->next; - } - while (p != jobs[job]->pipe); + job_state = any_stopped = 0; + p = jobs[job]->pipe; + do + { + job_state |= p->running; + if (p->running == 0) + any_stopped |= WIFSTOPPED (p->status); + p = p->next; + } + while (p != jobs[job]->pipe); - if (job_state == 0) - { - if (any_stopped) - jobs[job]->state = JSTOPPED; - else - jobs[job]->state = JDEAD; + if (job_state == 0) + jobs[job]->state = any_stopped ? JSTOPPED : JDEAD; } - } +#endif - if (child->running || ((job != NO_JOB) && (JOBSTATE (job) == JRUNNING))) - { -#if defined (WAITPID_BROKEN) /* SCOv4 */ - sigset_t suspend_set; - sigemptyset (&suspend_set); - sigsuspend (&suspend_set); + if (child->running || (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_CHILD) /* SCO */ - 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); +# 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 - waiting_for_job = 1; - waitchld (0); - waiting_for_job = 0; -# if defined (MUST_UNBLOCK_CHILD) - sigaction (SIGCHLD, &oact, (struct sigaction *)NULL); - sigprocmask (SIG_SETMASK, &chldset, (sigset_t *)NULL); + waiting_for_job = 1; + waitchld (pid, 1); +# if defined (MUST_UNBLOCK_CHLD) + sigaction (SIGCHLD, &oact, (struct sigaction *)NULL); + sigprocmask (SIG_SETMASK, &chldset, (sigset_t *)NULL); # endif -#endif /* !WAITPID_BROKEN */ - goto wait_loop; + waiting_for_job = 0; +#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 (child->running || (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 (job != NO_JOB) - { - register PROCESS *p = jobs[job]->pipe; - - while (p->next != jobs[job]->pipe) - p = p->next; - termination_state = process_exit_status (p->status); - } + termination_state = job_exit_status (job); else termination_state = process_exit_status (child->status); - if (job == NO_JOB || (jobs[job]->flags & J_JOBCONTROL)) + if (job == NO_JOB || IS_JOBCONTROL (job)) give_terminal_to (shell_pgrp); /* If the command did not exit cleanly, or the job is just @@ -1542,7 +1666,7 @@ wait_for (pid) interactive. Clean up any dead jobs in either case. */ if (job != NO_JOB) { - if (interactive_shell && !subshell_environment) + if (interactive_shell && subshell_environment == 0) { if (WIFSIGNALED (child->status) || WIFSTOPPED (child->status)) set_tty_state (); @@ -1553,23 +1677,20 @@ wait_for (pid) 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 && (jobs[job]->flags & J_JOBCONTROL) && - (jobs[job]->flags & J_FOREGROUND) && + if (job_control && IS_JOBCONTROL (job) && IS_FOREGROUND (job) && WIFSIGNALED (child->status) && WTERMSIG (child->status) == SIGINT) { - /* If SIGINT is not trapped, set the interrupt state if in a - loop so the loop will be broken. If not in a loop, print - the newline that the kernel does not. */ - if (signal_is_trapped (SIGINT) == 0) + /* 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 { - if (loop_level) - interrupt_state++; - else - { - putchar ('\n'); - fflush (stdout); - } + putchar ('\n'); + fflush (stdout); } } @@ -1581,12 +1702,16 @@ wait_for (pid) 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. */ - if (JOBSTATE(job) == JDEAD) +#if 0 + if (DEADJOB (job)) jobs[job]->flags |= J_NOTIFIED; cleanup_dead_jobs (); +#else + notify_and_cleanup (); +#endif } } - + UNBLOCK_CHILD (oset); /* Restore the original SIGINT signal handler before we return. */ @@ -1600,7 +1725,9 @@ int wait_for_job (job) int job; { - pid_t pid = last_pid (job); + pid_t pid; + + pid = last_pid (job); return (wait_for (pid)); } @@ -1611,10 +1738,10 @@ wait_for_job (job) void notify_and_cleanup () { - if (freeze_jobs_list) + if (jobs_list_frozen) return; - if (interactive) + if (interactive || interactive_shell == 0) notify_of_job_status (); cleanup_dead_jobs (); @@ -1641,20 +1768,16 @@ most_recent_job_in_state (job, state) sigset_t set, oset; BLOCK_CHILD (set, oset); - result = NO_JOB; - - for (i = job - 1; i >= 0; i--) + for (result = NO_JOB, i = job - 1; i >= 0; i--) { - if (jobs[i]) + if (jobs[i] && (JOBSTATE (i) == state)) { - if (JOBSTATE (i) == state) - { - result = i; - break; - } + result = i; + break; } } UNBLOCK_CHILD (oset); + return (result); } @@ -1682,7 +1805,7 @@ static void set_current_job (job) int job; { - int candidate = NO_JOB; + int candidate; if (current_job != job) { @@ -1694,12 +1817,13 @@ set_current_job (job) if (previous_job != current_job && previous_job != NO_JOB && jobs[previous_job] && - JOBSTATE (previous_job) == JSTOPPED) + STOPPED (previous_job)) return; /* Second choice: Newest stopped job that is older than the current job. */ - if (JOBSTATE (current_job) == JSTOPPED) + candidate = NO_JOB; + if (STOPPED (current_job)) { candidate = last_stopped_job (current_job); @@ -1717,10 +1841,8 @@ set_current_job (job) alternative to use based on whether or not JOBSTATE(current_job) is JSTOPPED. */ - if (JOBSTATE (current_job) == JRUNNING) - candidate = last_running_job (current_job); - else - candidate = last_running_job (job_slots); + candidate = RUNNING (current_job) ? last_running_job (current_job) + : last_running_job (job_slots); if (candidate != NO_JOB) { @@ -1739,33 +1861,29 @@ set_current_job (job) stopped job, the previous_job 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 = NO_JOB; + int candidate; - if (current_job != NO_JOB && - job_slots && jobs[current_job] && - JOBSTATE (current_job) == JSTOPPED) - { - candidate = current_job; - } + if (job_slots && current_job != NO_JOB && jobs[current_job] && STOPPED (current_job)) + candidate = current_job; else { - /* First choice: the previous job! */ - if (previous_job != NO_JOB && jobs[previous_job] && - JOBSTATE (previous_job) == JSTOPPED) + candidate = NO_JOB; + + /* First choice: the previous job. */ + if (previous_job != NO_JOB && jobs[previous_job] && STOPPED (previous_job)) candidate = previous_job; /* Second choice: the most recently stopped job. */ if (candidate == NO_JOB) candidate = last_stopped_job (job_slots); + /* Third choice: the newest running job. */ if (candidate == NO_JOB) - { - /* Third choice: the newest running job. */ - candidate = last_running_job (job_slots); - } + candidate = last_running_job (job_slots); } /* If we found a job to use, then use it. Otherwise, there @@ -1791,28 +1909,27 @@ start_job (job, foreground) #if defined (NEW_TTY_DRIVER) static struct sgttyb save_stty; #endif - #if defined (TERMIO_TTY_DRIVER) static struct termio save_stty; #endif - #if defined (TERMIOS_TTY_DRIVER) static struct termios save_stty; #endif BLOCK_CHILD (set, oset); - already_running = (JOBSTATE (job) == JRUNNING); - if (JOBSTATE (job) == JDEAD) + if (DEADJOB (job)) { - report_error ("%s: job has terminated", this_command_name); + internal_error ("%s: job has terminated", this_command_name); UNBLOCK_CHILD (oset); return (-1); } - if (!foreground && already_running) + already_running = RUNNING (job); + + if (foreground == 0 && already_running) { - report_error ("%s: bg background job?", this_command_name); + internal_error ("%s: bg background job?", this_command_name); UNBLOCK_CHILD (oset); return (-1); } @@ -1831,7 +1948,7 @@ start_job (job, foreground) /* Tell the outside world what we're doing. */ p = jobs[job]->pipe; - if (!foreground) + if (foreground == 0) fprintf (stderr, "[%d]%c ", job + 1, (job == current_job) ? '+': ((job == previous_job) ? '-' : ' ')); @@ -1844,7 +1961,7 @@ start_job (job, foreground) } while (p != jobs[job]->pipe); - if (!foreground) + if (foreground == 0) fprintf (stderr, " &"); if (strcmp (wd, jobs[job]->wd) != 0) @@ -1853,7 +1970,7 @@ start_job (job, foreground) fprintf (stderr, "\n"); /* Run the job. */ - if (!already_running) + if (already_running == 0) { /* Each member of the pipeline is now running. */ p = jobs[job]->pipe; @@ -1875,19 +1992,15 @@ start_job (job, foreground) { get_tty_state (); save_stty = shell_tty_info; - } - - /* Give the terminal to this job. */ - if (foreground) - { - if (jobs[job]->flags & J_JOBCONTROL) + /* Give the terminal to this job. */ + if (IS_JOBCONTROL (job)) give_terminal_to (jobs[job]->pgrp); } else jobs[job]->flags &= ~J_FOREGROUND; /* If the job is already running, then don't bother jump-starting it. */ - if (!already_running) + if (already_running == 0) { jobs[job]->flags |= J_NOTIFIED; killpg (jobs[job]->pgrp, SIGCONT); @@ -1897,9 +2010,11 @@ start_job (job, foreground) if (foreground) { - pid_t pid = last_pid (job); - int s = wait_for (pid); + pid_t pid; + int s; + pid = last_pid (job); + s = wait_for (pid); shell_tty_info = save_stty; set_tty_state (); return (s); @@ -1923,13 +2038,14 @@ kill_pid (pid, sig, group) int sig, group; { register PROCESS *p; - int job, result = EXECUTION_SUCCESS; + int job, result; sigset_t set, oset; BLOCK_CHILD (set, oset); p = find_pipeline (pid); job = find_job (pid); + result = EXECUTION_SUCCESS; if (group) { if (job != NO_JOB) @@ -1953,8 +2069,7 @@ kill_pid (pid, sig, group) else { result = killpg (jobs[job]->pgrp, sig); - if (p && (JOBSTATE (job) == JSTOPPED) && - (sig == SIGTERM || sig == SIGHUP)) + if (p && STOPPED (job) && (sig == SIGTERM || sig == SIGHUP)) killpg (jobs[job]->pgrp, SIGCONT); } } @@ -1968,195 +2083,204 @@ kill_pid (pid, sig, group) return (result); } -/* 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) -# define WAITPID(pid, statusp, options) \ - waitpid ((pid_t)pid, statusp, options) -# else -# if defined (hpux) -# define WAITPID(pid, statusp, options) \ - wait3 (statusp, options, (int *)0) -# else -# define WAITPID(pid, statusp, options) \ - wait3 (statusp, options, (struct rusage *)0) -# endif /* !hpux */ -# endif /* !_POSIX_VERSION */ -#endif /* !(Ultrix && mips && _POSIX_VERSION) */ - -/* If the system needs it, REINSTALL_SIGCHLD_HANDLER will reinstall the - handler for SIGCHLD. */ - -#if defined (hpux) && !defined (_POSIX_VERSION) -# define REINSTALL_SIGCHLD_HANDLER signal (SIGCHLD, flush_child) -#else -# define REINSTALL_SIGCHLD_HANDLER -#endif /* !hpux || _POSIX_VERSION */ - -/* Flush_child () flushes at least one of the children that we are waiting for. - It gets run when we have gotten a SIGCHLD signal, and stops when there - aren't any children terminating any more. If SIG is 0, this is to be a - blocking wait for a single child. */ +/* 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 -flush_child (sig) +sigchld_handler (sig) int sig; { + int n; + REINSTALL_SIGCHLD_HANDLER; sigchld++; + n = 0; if (waiting_for_job == 0) - waitchld (sig); - -#if !defined (VOID_SIGHANDLER) - return (0); -#endif /* VOID_SIGHANDLER */ + n = waitchld (-1, 0); + SIGRETURN (n); } - + +/* waitchld() reaps dead or stopped children. It's called by wait_for and + flush_child, 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. */ static int -waitchld (s) - int s; +waitchld (wpid, block) + pid_t wpid; + int block; { WAIT status; PROCESS *child; pid_t pid; - int call_set_current = 0, last_stopped_job = NO_JOB; - int children_exited = 0, flag; + int call_set_current, last_stopped_job, job, children_exited; + int job_state, any_stopped, any_tstped, waitpid_flags, tstatus; + + call_set_current = children_exited = 0; + last_stopped_job = NO_JOB; do { - flag = WUNTRACED; - if (sigchld || s) - flag |= WNOHANG; - pid = WAITPID (-1, &status, flag); - if (sigchld && (flag & WNOHANG)) - sigchld--; + /* We don't want to be notified about jobs stopping if we're not + interactive. */ + waitpid_flags = (interactive_shell && subshell_environment == 0) + ? WUNTRACED + : 0; + if (sigchld || block == 0) + waitpid_flags |= WNOHANG; + pid = WAITPID (-1, &status, waitpid_flags); + /* 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 0, there are running children. */ + if (pid <= 0) + continue; /* jumps right to the test */ + + children_exited++; + + /* Locate our PROCESS for this pid. */ + child = find_pipeline (pid); + + /* 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; + + while (child->pid != pid) + child = child->next; + + /* Remember status, and fact that process is not running. */ + child->status = status; + child->running = 0; + + job = find_job (pid); + if (job == NO_JOB) + continue; + + /* Note that we're resetting `child' here because we now want to + deal with the job. */ + child = jobs[job]->pipe; + jobs[job]->flags &= ~J_NOTIFIED; - if (pid > 0) + /* 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 { - /* Locate our PROCESS for this pid. */ - child = find_pipeline (pid); + job_state |= child->running; + if (child->running == 0 && (WIFSTOPPED (child->status))) + { + any_stopped = 1; + any_tstped |= interactive && job_control && + (WSTOPSIG (child->status) == SIGTSTP); + } + child = child->next; + } + while (child != jobs[job]->pipe); - /* 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. */ - if (child) + /* If job_state != 0, the job is still running, so don't bother with + setting the process exit status and job state. */ + if (job_state != 0) + continue; + + /* 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++; + last_stopped_job = job; + /* Suspending a job with SIGTSTP breaks all active loops. */ + if (any_tstped && loop_level) + breaking = loop_level; + } + else + { + /* ASSERT(child == jobs[job]->pipe); */ + jobs[job]->state = JDEAD; + if (job == last_stopped_job) + last_stopped_job = NO_JOB; + + if (IS_FOREGROUND (job)) + setjstatus (job); /* XXX */ + + /* 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) { - int job = find_job (pid); + (*jobs[job]->j_cleanup) (jobs[job]->cleanarg); + jobs[job]->j_cleanup = (VFunction *)NULL; + } - while (child->pid != pid) - child = child->next; + /* XXX + 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)) + { + wait_sigint_received = 0; + last_command_exit_value = process_exit_status (child->status); - /* Remember status, and fact that process is not running. */ - child->status = status; - child->running = 0; + jobs_list_frozen = 1; + tstatus = maybe_call_trap_handler (SIGINT); + jobs_list_frozen = 0; + } - if (job != NO_JOB) + /* 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) + { + 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. Watch out for this. */ + jobs_list_frozen = 1; + tstatus = maybe_call_trap_handler (SIGINT); + jobs_list_frozen = 0; + if (tstatus == 0 && old_sigint_handler != INVALID_SIGNAL_HANDLER) { - int job_state = 0; - int any_stopped = 0; - int any_tstped = 0; - - child = jobs[job]->pipe; - jobs[job]->flags &= ~J_NOTIFIED; - - /* If all children are not running, but any of them is - stopped, then the job is stopped, not dead. */ - do - { - job_state |= child->running; - if (!child->running) - { - any_stopped |= WIFSTOPPED (child->status); - any_tstped |= interactive && job_control && - WIFSTOPPED (child->status) && - WSTOPSIG (child->status) == SIGTSTP; - } - child = child->next; - } - while (child != jobs[job]->pipe); - - if (job_state == 0) - { - if (any_stopped) - { - jobs[job]->state = JSTOPPED; - jobs[job]->flags &= ~J_FOREGROUND; - call_set_current++; - last_stopped_job = job; - /* Suspending a job in a loop from the keyboard - breaks out of all active loops. */ - if (any_tstped && loop_level) - breaking = loop_level; - } - else - { - jobs[job]->state = JDEAD; - - if (job == last_stopped_job) - last_stopped_job = NO_JOB; - - /* 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. */ - if ((WTERMSIG (jobs[job]->pipe->status) == SIGINT) && - (jobs[job]->flags & J_FOREGROUND) && - (jobs[job]->flags & J_JOBCONTROL) == 0 && - wait_sigint_received) - { - 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 - (jobs[job]->pipe->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. Watch out for - this. */ - if (maybe_call_trap_handler (SIGINT) == 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. */ - SigHandler *temp_handler; - temp_handler = old_sigint_handler; - restore_sigint_handler (); - if (temp_handler != SIG_IGN) - (*temp_handler) (SIGINT); - } - } - } - } + /* wait_sigint_handler () has already seen SIGINT and + allowed the wait builtin to jump out. We need to + call the original SIGINT handler. */ + SigHandler *temp_handler; + temp_handler = old_sigint_handler; + restore_sigint_handler (); + if (temp_handler != SIG_IGN) + (*temp_handler) (SIGINT); } } - /* If we have caught a child, and a trap was set for SIGCHLD, then - bump up the count of the number of children that have exited, - so we know how many times to call it. */ - children_exited++; } } - while ((s || sigchld) && pid > (pid_t)0); + 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. */ @@ -2171,6 +2295,7 @@ waitchld (s) trap_list[SIGCHLD] != (char *)IGNORE_SIG) { 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 @@ -2180,9 +2305,12 @@ waitchld (s) begin_unwind_frame ("SIGCHLD trap"); unwind_protect_int (last_command_exit_value); - unwind_protect_int (last_made_pid); + if (sizeof (pid_t) == sizeof (short)) + unwind_protect_short (last_made_pid); + else + unwind_protect_int (last_made_pid); unwind_protect_int (interrupt_immediately); - unwind_protect_int (freeze_jobs_list); + unwind_protect_int (jobs_list_frozen); unwind_protect_pointer (the_pipeline); /* We have to add the commands this way because they will be run @@ -2193,8 +2321,8 @@ waitchld (s) the_pipeline = (PROCESS *)NULL; restore_default_signal (SIGCHLD); - freeze_jobs_list = 1; - while (children_exited--) + jobs_list_frozen = 1; + for (i = 0; i < children_exited; i++) { interrupt_immediately = 1; parse_and_execute (savestring (trap_command), "trap", -1); @@ -2210,6 +2338,7 @@ waitchld (s) if (asynchronous_notification && interactive) notify_of_job_status (); + return (children_exited); } /* Function to call when you want to notify people of changes @@ -2222,6 +2351,7 @@ notify_of_job_status () register int job, termsig; char *dir; sigset_t set, oset; + WAIT s; sigemptyset (&set); sigaddset (&set, SIGCHLD); @@ -2229,35 +2359,39 @@ notify_of_job_status () sigemptyset (&oset); sigprocmask (SIG_BLOCK, &set, &oset); - dir = (char *)NULL; - - for (job = 0; job < job_slots; job++) + for (job = 0, dir = (char *)NULL; job < job_slots; job++) { - if (jobs[job] && (jobs[job]->flags & J_NOTIFIED) == 0) + if (jobs[job] && IS_NOTIFIED (job) == 0) { - WAIT s; - s = jobs[job]->pipe->status; termsig = WTERMSIG (s); /* If job control is disabled, don't print the status messages. - Mark dead jobs as notified so that they get cleaned up. */ - if (!job_control) + 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 the shell is not interactive, don't + print anything unless the job was killed by a signal. */ + if ((job_control == 0 && interactive_shell) || startup_state == 2 || + (startup_state == 0 && WIFSIGNALED (s) == 0)) { - if (JOBSTATE (job) == JDEAD) + if (DEADJOB (job)) 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. */ switch (JOBSTATE (job)) { - /* Print info on jobs that are running in the background, - and on foreground jobs that were killed by anything - except SIGINT. */ - case JDEAD: - - if (jobs[job]->flags & J_FOREGROUND) + if (interactive_shell == 0 && termsig && WIFSIGNALED (s) && + signal_is_trapped (termsig) == 0) + { + fprintf (stderr, "%s: line %d: ", get_name_for_error (), line_number); + pretty_print_job (job, JLIST_NONINTERACTIVE, stderr); + } + else if (IS_FOREGROUND (job)) { if (termsig && WIFSIGNALED (s) && termsig != SIGINT) { @@ -2271,9 +2405,9 @@ notify_of_job_status () } else { - if (!dir) + if (dir == 0) dir = current_working_directory (); - pretty_print_job (job, 0, stderr); + 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)); @@ -2284,9 +2418,9 @@ notify_of_job_status () case JSTOPPED: fprintf (stderr, "\n"); - if (!dir) + if (dir == 0) dir = current_working_directory (); - pretty_print_job (job, 0, stderr); + 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)); @@ -2305,81 +2439,49 @@ notify_of_job_status () sigprocmask (SIG_SETMASK, &oset, (sigset_t *)NULL); } -/* getpgrp () varies between systems. Even systems that claim to be - Posix.1 compatible lie sometimes (Ultrix, SunOS4, apollo). */ -#if defined (_POSIX_VERSION) && !defined (BSD_GETPGRP) -# define getpgid(p) getpgrp () -#else -# define getpgid(p) getpgrp (p) -#endif /* !_POSIX_VERSION || BSD_GETPGRP */ - /* Initialize the job control mechanism, and set up the tty stuff. */ +int initialize_jobs () { shell_pgrp = getpgid (0); if (shell_pgrp == -1) { - internal_error ("initialize_jobs: getpgrp failed: %s", strerror (errno)); + sys_error ("initialize_jobs: getpgrp failed"); exit (1); } - /* We can only have job control if we are interactive? - I guess that makes sense. */ - - if (!interactive) + /* We can only have job control if we are interactive. */ + if (interactive == 0) { job_control = 0; original_pgrp = NO_PID; } else { - /* Make sure that we are using the new line discipline. */ - /* Get our controlling terminal. If job_control is set, or interactive is set, then this is an interactive shell no - matter what. */ - shell_tty = dup (fileno (stderr)); - - /* Find the highest unused file descriptor we can. */ - { - int ignore, nds = getdtablesize (); - - if (nds <= 0) - nds = 20; - else if (nds > 256) - nds = 256; - - while (--nds > 3) - { - if (fcntl (nds, F_GETFD, &ignore) == -1) - break; - } + matter where fd 2 is directed. */ + shell_tty = dup (fileno (stderr)); /* fd 2 */ - if (nds && shell_tty != nds && (dup2 (shell_tty, nds) != -1)) - { - if (shell_tty != fileno (stderr)) - close (shell_tty); - shell_tty = nds; - } - } + shell_tty = move_to_high_fd (shell_tty, 1); -#if defined (RLOGIN_PGRP_BUG) /* Compensate for a bug in systems that compiled the BSD - /usr/etc/rlogind with DEBUG defined, like NeXT and Alliant. */ + rlogind with DEBUG defined, like NeXT and Alliant. */ if (shell_pgrp == 0) { shell_pgrp = getpid (); setpgid (0, shell_pgrp); tcsetpgrp (shell_tty, shell_pgrp); } -#endif /* RLOGIN_PGRP_BUG */ while ((terminal_pgrp = tcgetpgrp (shell_tty)) != -1) { if (shell_pgrp != terminal_pgrp) { - SigHandler *old_ttin = (SigHandler *)set_signal_handler (SIGTTIN, SIG_DFL); + SigHandler *old_ttin; + + old_ttin = set_signal_handler(SIGTTIN, SIG_DFL); kill (0, SIGTTIN); set_signal_handler (SIGTTIN, old_ttin); continue; @@ -2387,10 +2489,10 @@ initialize_jobs () break; } + /* Make sure that we are using the new line discipline. */ if (set_new_line_discipline (shell_tty) < 0) { - internal_error ("initialize_jobs: line discipline: %s", - strerror (errno)); + sys_error ("initialize_jobs: line discipline"); job_control = 0; } else @@ -2400,13 +2502,28 @@ initialize_jobs () if ((original_pgrp != shell_pgrp) && (setpgid (0, shell_pgrp) < 0)) { - internal_error ("initialize_jobs: setpgid: %s", strerror (errno)); + sys_error ("initialize_jobs: setpgid"); shell_pgrp = original_pgrp; } job_control = 1; - if (give_terminal_to (shell_pgrp) < 0) /* XXX */ - /* job_control = 0 */; /* XXX */ + + /* 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) /* XXX */ + { + setpgid (0, original_pgrp); /* XXX */ + shell_pgrp = original_pgrp; /* XXX */ + job_control = 0; /* XXX */ + } + } } if (job_control == 0) internal_error ("no job control in this shell"); /* XXX */ @@ -2415,12 +2532,13 @@ initialize_jobs () if (shell_tty != fileno (stderr)) SET_CLOSE_ON_EXEC (shell_tty); - set_signal_handler (SIGCHLD, flush_child); + set_signal_handler (SIGCHLD, sigchld_handler); change_flag ('m', job_control ? '-' : '+'); if (interactive) get_tty_state (); + return job_control; } @@ -2447,7 +2565,7 @@ set_new_line_discipline (tty) #endif /* NEW_TTY_DRIVER */ #if defined (TERMIO_TTY_DRIVER) -# if defined (NTTYDISC) +# if defined (TERMIO_LDISC) && (NTTYDISC) if (ioctl (tty, TCGETA, &shell_tty_info) < 0) return (-1); @@ -2457,12 +2575,12 @@ set_new_line_discipline (tty) if (ioctl (tty, TCSETAW, &shell_tty_info) < 0) return (-1); } -# endif /* NTTYDISC */ +# endif /* TERMIO_LDISC && NTTYDISC */ return (0); #endif /* TERMIO_TTY_DRIVER */ #if defined (TERMIOS_TTY_DRIVER) -# if defined (TERMIOS_LDISC) +# if defined (TERMIOS_LDISC) && defined (NTTYDISC) if (tcgetattr (tty, &shell_tty_info) < 0) return (-1); @@ -2472,7 +2590,7 @@ set_new_line_discipline (tty) if (tcsetattr (tty, TCSADRAIN, &shell_tty_info) < 0) return (-1); } -# endif /* TERMIOS_LDISC */ +# endif /* TERMIOS_LDISC && NTTYDISC */ return (0); #endif /* TERMIOS_TTY_DRIVER */ @@ -2485,18 +2603,15 @@ static SigHandler *old_tstp, *old_ttou, *old_ttin; static SigHandler *old_cont = (SigHandler *)SIG_DFL; static sighandler stop_signal_handler (), cont_signal_handler (); -#if !defined (READLINE) && defined (TIOCGWINSZ) && defined (SIGWINCH) -static SigHandler *old_winch; +#if defined (TIOCGWINSZ) && defined (SIGWINCH) +static SigHandler *old_winch = (SigHandler *)SIG_DFL; -static sighandler -sigwinch_sighandler (sig) - int sig; +static void +get_new_window_size (from_sig) + int from_sig; { struct winsize win; -#if defined (USG) && !defined (_POSIX_VERSION) - set_signal_handler (SIGWINCH, sigwinch_sighandler); -#endif /* USG && !_POSIX_VERSION */ if ((ioctl (shell_tty, TIOCGWINSZ, &win) == 0) && win.ws_row > 0 && win.ws_col > 0) { @@ -2504,9 +2619,44 @@ sigwinch_sighandler (sig) shell_tty_info.c_winsize = win; /* structure copying */ #endif set_lines_and_columns (win.ws_row, win.ws_col); +#if defined (READLINE) + _rl_set_screen_size (win.ws_row, win.ws_col); +#endif } } -#endif /* !READLINE && TIOCGWINSZ && SIGWINCH */ + +static sighandler +sigwinch_sighandler (sig) + int sig; +{ +#if defined (MUST_REINSTALL_SIGHANDLERS) + set_signal_handler (SIGWINCH, sigwinch_sighandler); +#endif /* MUST_REINSTALL_SIGHANDLERS */ + get_new_window_size (1); +} +#else +static void +get_new_window_size (from_sig) + int from_sig; +{ +} +#endif /* TIOCGWINSZ && SIGWINCH */ + +void +set_sigwinch_handler () +{ +#if defined (TIOCGWINSZ) && defined (SIGWINCH) + old_winch = set_signal_handler (SIGWINCH, sigwinch_sighandler); +#endif +} + +void +unset_sigwinch_handler () +{ +#if defined (TIOCGWINSZ) && defined (SIGWINCH) + set_signal_handler (SIGWINCH, old_winch); +#endif +} /* Setup this shell to handle C-C, etc. */ void @@ -2518,9 +2668,7 @@ initialize_job_signals () set_signal_handler (SIGTSTP, SIG_IGN); set_signal_handler (SIGTTOU, SIG_IGN); set_signal_handler (SIGTTIN, SIG_IGN); -#if !defined (READLINE) && defined (TIOCGWINSZ) && defined (SIGWINCH) - old_winch = set_signal_handler (SIGWINCH, sigwinch_sighandler); -#endif /* !READLINE && TIOCGWINSZ && SIGWINCH */ + set_sigwinch_handler (); } else if (job_control) { @@ -2541,9 +2689,7 @@ cont_signal_handler (sig) set_signal_handler (SIGCONT, old_cont); kill (getpid (), SIGCONT); -#if !defined (VOID_SIGHANDLER) - return (0); -#endif /* VOID_SIGHANDLER */ + SIGRETURN (0); } /* Here we handle stop signals while we are running not as a login shell. */ @@ -2561,18 +2707,18 @@ stop_signal_handler (sig) kill (getpid (), sig); -#if !defined (VOID_SIGHANDLER) - return (0); -#endif /* VOID_SIGHANDLER */ + SIGRETURN (0); } /* Give the terminal to PGRP. */ +int give_terminal_to (pgrp) pid_t pgrp; { sigset_t set, oset; - int r = 0; + int r; + r = 0; if (job_control) { sigemptyset (&set); @@ -2586,13 +2732,14 @@ give_terminal_to (pgrp) if (tcsetpgrp (shell_tty, pgrp) < 0) { /* Maybe we should print an error message? */ -/* internal_error ("tcsetpgrp(%d) failed: pid %d to pgrp %d: %s", - shell_tty, getpid(), pgrp, strerror (errno)); */ +#if 0 + sys_error ("tcsetpgrp(%d) failed: pid %d to pgrp %d", + shell_tty, getpid(), pgrp); +#endif r = -1; } else terminal_pgrp = pgrp; - sigprocmask (SIG_SETMASK, &oset, (sigset_t *)NULL); } @@ -2609,24 +2756,21 @@ delete_all_jobs () register int i; sigset_t set, oset; + BLOCK_CHILD (set, oset); + if (job_slots) { - BLOCK_CHILD (set, oset); - - if (job_slots) - { - current_job = previous_job = NO_JOB; + current_job = previous_job = NO_JOB; - for (i = 0; i < job_slots; i++) - if (jobs[i] != (JOB *) NULL) - delete_job (i); - - free ((char *)jobs); - job_slots = 0; - } + for (i = 0; i < job_slots; i++) + if (jobs[i]) + delete_job (i); - UNBLOCK_CHILD (oset); + free ((char *)jobs); + job_slots = 0; } + + UNBLOCK_CHILD (oset); } /* Mark all dead jobs as notified, so delete_job () cleans them out @@ -2642,13 +2786,21 @@ mark_dead_jobs_as_notified () BLOCK_CHILD (set, oset); for (i = 0; i < job_slots; i++) - if (jobs[i] && JOBSTATE (i) == JDEAD) + if (jobs[i] && DEADJOB (i)) 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 @@ -2705,7 +2857,7 @@ restart_job_control () void set_sigchld_handler () { - set_signal_handler (SIGCHLD, flush_child); + set_signal_handler (SIGCHLD, sigchld_handler); } #if defined (PGRP_PIPE) @@ -2745,6 +2897,7 @@ pipe_close (pp) } /* Functional interface closes our local-to-job-control pipes. */ +void close_pgrp_pipe () { pipe_close (pgrp_pipe); @@ -2752,4 +2905,59 @@ close_pgrp_pipe () #endif /* PGRP_PIPE */ -#endif /* JOB_CONTROL */ +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); +#endif +} + +#if defined (ARRAY_VARS) +static void +set_pipestatus_array (ps) + int *ps; +{ + SHELL_VAR *v; + ARRAY *a; + register int i; + char *t; + + v = find_variable ("PIPESTATUS"); + if (v == 0) + v = make_new_array_variable ("PIPESTATUS"); + if (array_p (v) == 0) + return; /* Do nothing if not an array variable. */ + a = array_cell (v); + if (a) + empty_array (a); + for (i = 0; ps[i] != -1; i++) + { + t = itos (ps[i]); + array_add_element (a, i, t); + free (t); + } +} +#endif diff --git a/jobs.h b/jobs.h index 18d3d73..f80047e 100644 --- a/jobs.h +++ b/jobs.h @@ -18,8 +18,8 @@ with Bash; see the file COPYING. If not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ -#if !defined (__JOBS_H__) -# define __JOBS_H__ +#if !defined (_JOBS_H_) +# define _JOBS_H_ #include "quit.h" #include "siglist.h" @@ -27,93 +27,26 @@ #include "stdc.h" /* Defines controlling the fashion in which jobs are listed. */ -#define JLIST_STANDARD 0 -#define JLIST_LONG 1 -#define JLIST_PID_ONLY 2 -#define JLIST_CHANGED_ONLY 3 - -#if defined (HAVE_WAIT_H) +#define JLIST_STANDARD 0 +#define JLIST_LONG 1 +#define JLIST_PID_ONLY 2 +#define JLIST_CHANGED_ONLY 3 +#define JLIST_NONINTERACTIVE 4 + +/* If _POSIX_VERSION is not defined, we assume that defines + a `union wait' and various macros used to manipulate it. Look in + bashwait.h for the things we expect to find. */ +#if defined (HAVE_SYS_WAIT_H) # include -#else /* !HAVE_WAIT_H */ - -# include "bash_endian.h" - +#else /* !HAVE_SYS_WAIT_H */ # if !defined (_POSIX_VERSION) -# if defined (LITTLE_ENDIAN) -union wait - { - int w_status; /* used in syscall */ - - /* Terminated process status. */ - struct - { - unsigned short - w_Termsig : 7, /* termination signal */ - w_Coredump : 1, /* core dump indicator */ - w_Retcode : 8, /* exit code if w_termsig==0 */ - w_Fill1 : 16; /* high 16 bits unused */ - } w_T; - - /* Stopped process status. Returned - only for traced children unless requested - with the WUNTRACED option bit. */ - struct - { - unsigned short - w_Stopval : 8, /* == W_STOPPED if stopped */ - w_Stopsig : 8, /* actually zero on XENIX */ - w_Fill2 : 16; /* high 16 bits unused */ - } w_S; - }; - -# else /* !LITTLE_ENDIAN */ - -/* This is for big-endian machines like the IBM RT, HP 9000, or Sun-3 */ - -union wait - { - int w_status; /* used in syscall */ - - /* Terminated process status. */ - struct - { - unsigned short w_Fill1 : 16; /* high 16 bits unused */ - unsigned w_Retcode : 8; /* exit code if w_termsig==0 */ - unsigned w_Coredump : 1; /* core dump indicator */ - unsigned w_Termsig : 7; /* termination signal */ - } w_T; - - /* Stopped process status. Returned - only for traced children unless requested - with the WUNTRACED option bit. */ - struct - { - unsigned short w_Fill2 : 16; /* high 16 bits unused */ - unsigned w_Stopsig : 8; /* signal that stopped us */ - unsigned w_Stopval : 8; /* == W_STOPPED if stopped */ - } w_S; - }; - -# endif /* !LITTLE_ENDIAN */ - -# define w_termsig w_T.w_Termsig -# define w_coredump w_T.w_Coredump -# define w_retcode w_T.w_Retcode -# define w_stopval w_S.w_Stopval -# define w_stopsig w_S.w_Stopsig - -/* Note that sys/wait.h defines these for Posix systems. */ -# define WSTOPPED 0177 -# define WIFSTOPPED(x) (((x) . w_stopval) == WSTOPPED) -# define WIFEXITED(x) ((! (WIFSTOPPED (x))) && (((x) . w_termsig) == 0)) -# define WIFSIGNALED(x) ((! (WIFSTOPPED (x))) && (((x) . w_termsig) != 0)) -# endif /* !_POSIX_VERSION */ -#endif /* !HAVE_WAIT_H */ +# include "bashwait.h" +# endif +#endif /* !HAVE_SYS_WAIT_H */ /* How to get the status of a job. For Posix, this is just an int, but for other systems we have to crack the union wait. */ #if !defined (_POSIX_VERSION) -# define pid_t int typedef union wait WAIT; # define WSTATUS(t) (t.w_status) #else /* _POSIX_VERSION */ @@ -200,10 +133,19 @@ typedef struct process { typedef enum { JRUNNING, JSTOPPED, JDEAD, JMIXED } JOB_STATE; #define JOBSTATE(job) (jobs[(job)]->state) +#define STOPPED(j) (jobs[(j)]->state == JSTOPPED) +#define RUNNING(j) (jobs[(j)]->state == JRUNNING) +#define DEADJOB(j) (jobs[(j)]->state == JDEAD) + /* Values for the FLAGS field in the JOB struct below. */ #define J_FOREGROUND 0x01 /* Non-zero if this is running in the foreground. */ #define J_NOTIFIED 0x02 /* Non-zero if already notified about job state. */ #define J_JOBCONTROL 0x04 /* Non-zero if this job started under job control. */ +#define J_NOHUP 0x08 /* Don't send SIGHUP to job if shell gets SIGHUP. */ + +#define IS_FOREGROUND(j) ((jobs[j]->flags & J_FOREGROUND) != 0) +#define IS_NOTIFIED(j) ((jobs[j]->flags & J_NOTIFIED) != 0) +#define IS_JOBCONTROL(j) ((jobs[j]->flags & J_JOBCONTROL) != 0) typedef struct job { char *wd; /* The working directory at time of invocation. */ @@ -213,6 +155,8 @@ typedef struct job { int flags; /* Flags word: J_NOTIFIED, J_FOREGROUND, or J_JOBCONTROL. */ #if defined (JOB_CONTROL) COMMAND *deferred; /* Commands that will execute when this job is done. */ + VFunction *j_cleanup; /* Cleanup function to call when job marked JDEAD */ + PTR_T cleanarg; /* Argument passed to (*j_cleanup)() */ #endif /* JOB_CONTROL */ } JOB; @@ -222,69 +166,10 @@ typedef struct job { /* A value which cannot be a process ID. */ #define NO_PID (pid_t)-1 -#if !defined (_POSIX_VERSION) && !defined (sigmask) -# define sigmask(x) (1 << ((x)-1)) -#endif /* !POSIX && !sigmask */ - -#if !defined (SIGABRT) -# define SIGABRT SIGIOT -#endif /* !SIGABRT */ - -#if !defined (SIGCHLD) -# define SIGCHLD SIGCLD -#endif /* !SIGCHLD */ - -#if !defined (_POSIX_VERSION) -# if !defined (SIG_BLOCK) -# define SIG_BLOCK 2 -# define SIG_SETMASK 3 -# endif /* SIG_BLOCK */ - -/* Type of a signal set. */ -# define sigset_t int - -/* Make sure there is nothing inside the signal set. */ -# define sigemptyset(set) (*(set) = 0) - -/* Initialize the signal set to hold all signals. */ -# define sigfillset(set) (*set) = sigmask (NSIG) - 1 - -/* Add SIG to the contents of SET. */ -# define sigaddset(set, sig) *(set) |= sigmask (sig) - -/* Delete SIG from signal set SET. */ -# define sigdelset(set, sig) *(set) &= ~sigmask (sig) - -/* Is SIG a member of the signal set SET? */ -# define sigismember(set, sig) ((*(set) & sigmask (sig)) != 0) - -/* Suspend the process until the reception of one of the signals - not present in SET. */ -# define sigsuspend(set) sigpause (*(set)) -#endif /* !_POSIX_VERSION */ - -/* These definitions are used both in POSIX and non-POSIX implementations. */ - -#define BLOCK_SIGNAL(sig, nvar, ovar) \ - sigemptyset (&nvar); \ - sigaddset (&nvar, sig); \ - sigemptyset (&ovar); \ - sigprocmask (SIG_BLOCK, &nvar, &ovar) - -#if defined (_POSIX_VERSION) -# define BLOCK_CHILD(nvar, ovar) \ - BLOCK_SIGNAL (SIGCHLD, nvar, ovar) -# define UNBLOCK_CHILD(ovar) \ - sigprocmask (SIG_SETMASK, &ovar, (sigset_t *) NULL) -#else /* !_POSIX_VERSION */ -# define BLOCK_CHILD(nvar, ovar) ovar = sigblock (sigmask (SIGCHLD)) -# define UNBLOCK_CHILD(ovar) sigsetmask (ovar) -#endif /* !_POSIX_VERSION */ - /* System calls. */ -#if !defined (SunOS5) && !defined (USGr4_2) && !defined (__BSD_4_4__) +#if !defined (HAVE_UNISTD_H) extern pid_t fork (), getpid (), getpgrp (); -#endif /* !SunOS5 && !USGr4_2 && !__BSD_4_4__ */ +#endif /* !HAVE_UNISTD_H */ /* Stuff from the jobs.c file. */ extern pid_t original_pgrp, shell_pgrp, pipeline_pgrp; @@ -297,9 +182,12 @@ extern int job_slots; extern void making_children __P((void)); extern void stop_making_children __P((void)); extern void cleanup_the_pipeline __P((void)); +extern void save_pipeline __P((int)); +extern void restore_pipeline __P((int)); extern void start_pipeline __P((void)); extern int stop_pipeline __P((int, COMMAND *)); extern void delete_job __P((int)); +extern void nohup_job __P((int)); extern void terminate_current_pipeline __P((void)); extern void terminate_stopped_jobs __P((void)); @@ -312,8 +200,10 @@ extern void describe_pid __P((int)); extern void describe_pid __P((pid_t)); #endif -extern int list_one_job __P((JOB *, int, int, int)); -extern void list_jobs __P((int)); +extern void list_one_job __P((JOB *, int, int, int)); +extern void list_all_jobs __P((int)); +extern void list_stopped_jobs __P((int)); +extern void list_running_jobs __P((int)); extern pid_t make_child __P((char *, int)); extern int get_tty_state __P((void)); @@ -332,14 +222,20 @@ extern int initialize_jobs __P((void)); extern void initialize_job_signals __P((void)); extern int give_terminal_to __P((pid_t)); +extern void set_sigwinch_handler __P((void)); +extern void unset_sigwinch_handler __P((void)); + +extern void unfreeze_jobs_list __P((void)); extern int set_job_control __P((int)); extern void without_job_control __P((void)); extern void end_job_control __P((void)); extern void restart_job_control __P((void)); extern void set_sigchld_handler __P((void)); +extern void ignore_tty_job_signals __P((void)); +extern void default_tty_job_signals __P((void)); #if defined (JOB_CONTROL) extern int job_control; #endif -#endif /* __JOBS_H__ */ +#endif /* _JOBS_H_ */ diff --git a/lib/doc-support/Makefile b/lib/doc-support/Makefile deleted file mode 100644 index 553b61f..0000000 --- a/lib/doc-support/Makefile +++ /dev/null @@ -1,23 +0,0 @@ -GETOPT = ${topdir}/builtins/getopt.o -OBJECTS = texindex.o $(GETOPT) -SOURCES = texindex.c - -LDFLAGS = -g - -srcdir = . -VPATH = .:$(srcdir) - -.c.o: - rm -f $@ - $(CC) $(CFLAGS) -c $< - -all: texindex - -texindex: texindex.o - $(CC) $(LDFLAGS) -o $@ $(OBJECTS) $(LIBS) - -clean: - rm -f texindex.o - -realclean distclean maintainer-clean: clean - rm -f texindex diff --git a/lib/doc-support/getopt.h b/lib/doc-support/getopt.h deleted file mode 100644 index 45541f5..0000000 --- a/lib/doc-support/getopt.h +++ /dev/null @@ -1,129 +0,0 @@ -/* Declarations for getopt. - Copyright (C) 1989, 1990, 1991, 1992, 1993 Free Software Foundation, Inc. - - This program 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. - - This program 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 this program; if not, write to the Free Software - Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ - -#ifndef _GETOPT_H -#define _GETOPT_H 1 - -#ifdef __cplusplus -extern "C" { -#endif - -/* For communication from `getopt' to the caller. - When `getopt' finds an option that takes an argument, - the argument value is returned here. - Also, when `ordering' is RETURN_IN_ORDER, - each non-option ARGV-element is returned here. */ - -extern char *optarg; - -/* Index in ARGV of the next element to be scanned. - This is used for communication to and from the caller - and for communication between successive calls to `getopt'. - - On entry to `getopt', zero means this is the first call; initialize. - - When `getopt' returns EOF, this is the index of the first of the - non-option elements that the caller should itself scan. - - Otherwise, `optind' communicates from one call to the next - how much of ARGV has been scanned so far. */ - -extern int optind; - -/* Callers store zero here to inhibit the error message `getopt' prints - for unrecognized options. */ - -extern int opterr; - -/* Set to an option character which was unrecognized. */ - -extern int optopt; - -/* Describe the long-named options requested by the application. - The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector - of `struct option' terminated by an element containing a name which is - zero. - - The field `has_arg' is: - no_argument (or 0) if the option does not take an argument, - required_argument (or 1) if the option requires an argument, - optional_argument (or 2) if the option takes an optional argument. - - If the field `flag' is not NULL, it points to a variable that is set - to the value given in the field `val' when the option is found, but - left unchanged if the option is not found. - - To have a long-named option do something other than set an `int' to - a compiled-in constant, such as set a value from `optarg', set the - option's `flag' field to zero and its `val' field to a nonzero - value (the equivalent single-letter option character, if there is - one). For long options that have a zero `flag' field, `getopt' - returns the contents of the `val' field. */ - -struct option -{ -#if __STDC__ - const char *name; -#else - char *name; -#endif - /* has_arg can't be an enum because some compilers complain about - type mismatches in all the code that assumes it is an int. */ - int has_arg; - int *flag; - int val; -}; - -/* Names for the values of the `has_arg' field of `struct option'. */ - -#define no_argument 0 -#define required_argument 1 -#define optional_argument 2 - -#if __STDC__ -#if defined(__GNU_LIBRARY__) -/* Many other libraries have conflicting prototypes for getopt, with - differences in the consts, in stdlib.h. To avoid compilation - errors, only prototype getopt for the GNU C library. */ -extern int getopt (int argc, char *const *argv, const char *shortopts); -#else /* not __GNU_LIBRARY__ */ -extern int getopt (); -#endif /* not __GNU_LIBRARY__ */ -extern int getopt_long (int argc, char *const *argv, const char *shortopts, - const struct option *longopts, int *longind); -extern int getopt_long_only (int argc, char *const *argv, - const char *shortopts, - const struct option *longopts, int *longind); - -/* Internal only. Users should not call this directly. */ -extern int _getopt_internal (int argc, char *const *argv, - const char *shortopts, - const struct option *longopts, int *longind, - int long_only); -#else /* not __STDC__ */ -extern int getopt (); -extern int getopt_long (); -extern int getopt_long_only (); - -extern int _getopt_internal (); -#endif /* not __STDC__ */ - -#ifdef __cplusplus -} -#endif - -#endif /* _GETOPT_H */ diff --git a/lib/doc-support/texindex.c b/lib/doc-support/texindex.c deleted file mode 100644 index 9233bab..0000000 --- a/lib/doc-support/texindex.c +++ /dev/null @@ -1,1666 +0,0 @@ -/* Prepare TeX index dribble output into an actual index. - - Version 1.45 - - Copyright (C) 1987, 1991, 1992 Free Software Foundation, Inc. - - This program 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. - - This program 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 this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ - - -#include -#include -#include -#include "getopt.h" -#include "bashansi.h" - -#if !defined (errno) -extern int errno; -#endif - -#if defined (HAVE_UNISTD_H) -# include -#else /* !HAVE_UNISTD_H */ -extern long lseek (); -#endif /* !HAVE_UNISTD_H */ - -extern char *mktemp (); - -#if !defined (HAVE_STRERROR) -extern int sys_nerr; -extern char *sys_errlist[]; -#endif - -#include - -#if defined (_AIX) || !defined (_POSIX_VERSION) -# include -#endif - -#include - -#define TI_NO_ERROR 0 -#define TI_FATAL_ERROR 1 - -#if !defined (SEEK_SET) -# define SEEK_SET 0 -# define SEEK_CUR 1 -# define SEEK_END 2 -#endif /* !SEEK_SET */ - -/* When sorting in core, this structure describes one line - and the position and length of its first keyfield. */ -struct lineinfo -{ - char *text; /* The actual text of the line. */ - union { - char *text; /* The start of the key (for textual comparison). */ - long number; /* The numeric value (for numeric comparison). */ - } key; - long keylen; /* Length of KEY field. */ -}; - -/* This structure describes a field to use as a sort key. */ -struct keyfield -{ - int startwords; /* Number of words to skip. */ - int startchars; /* Number of additional chars to skip. */ - int endwords; /* Number of words to ignore at end. */ - int endchars; /* Ditto for characters of last word. */ - char ignore_blanks; /* Non-zero means ignore spaces and tabs. */ - char fold_case; /* Non-zero means case doesn't matter. */ - char reverse; /* Non-zero means compare in reverse order. */ - char numeric; /* Non-zeros means field is ASCII numeric. */ - char positional; /* Sort according to file position. */ - char braced; /* Count balanced-braced groupings as fields. */ -}; - -/* Vector of keyfields to use. */ -struct keyfield keyfields[3]; - -/* Number of keyfields stored in that vector. */ -int num_keyfields = 3; - -/* Vector of input file names, terminated with a null pointer. */ -char **infiles; - -/* Vector of corresponding output file names, or NULL, meaning default it - (add an `s' to the end). */ -char **outfiles; - -/* Length of `infiles'. */ -int num_infiles; - -/* Pointer to the array of pointers to lines being sorted. */ -char **linearray; - -/* The allocated length of `linearray'. */ -long nlines; - -/* Directory to use for temporary files. On Unix, it ends with a slash. */ -char *tempdir; - -/* Start of filename to use for temporary files. */ -char *tempbase; - -/* Number of last temporary file. */ -int tempcount; - -/* Number of last temporary file already deleted. - Temporary files are deleted by `flush_tempfiles' in order of creation. */ -int last_deleted_tempcount; - -/* During in-core sort, this points to the base of the data block - which contains all the lines of data. */ -char *text_base; - -/* Additional command switches .*/ - -/* Nonzero means do not delete tempfiles -- for debugging. */ -int keep_tempfiles; - -/* The name this program was run with. */ -char *program_name; - -/* Forward declarations of functions in this file. */ - -void decode_command (); -void sort_in_core (); -void sort_offline (); -char **parsefile (); -char *find_field (); -char *find_pos (); -long find_value (); -char *find_braced_pos (); -char *find_braced_end (); -void writelines (); -int compare_field (); -int compare_full (); -long readline (); -int merge_files (); -int merge_direct (); -void pfatal_with_name (); -void fatal (); -void error (); -void *xmalloc (), *xrealloc (); -char *concat (); -char *maketempname (); -void flush_tempfiles (); -char *tempcopy (); - -#define MAX_IN_CORE_SORT 500000 - -void -main (argc, argv) - int argc; - char **argv; -{ - int i; - - tempcount = 0; - last_deleted_tempcount = 0; - program_name = argv[0]; - - /* Describe the kind of sorting to do. */ - /* The first keyfield uses the first braced field and folds case. */ - keyfields[0].braced = 1; - keyfields[0].fold_case = 1; - keyfields[0].endwords = -1; - keyfields[0].endchars = -1; - - /* The second keyfield uses the second braced field, numerically. */ - keyfields[1].braced = 1; - keyfields[1].numeric = 1; - keyfields[1].startwords = 1; - keyfields[1].endwords = -1; - keyfields[1].endchars = -1; - - /* The third keyfield (which is ignored while discarding duplicates) - compares the whole line. */ - keyfields[2].endwords = -1; - keyfields[2].endchars = -1; - - decode_command (argc, argv); - - tempbase = mktemp (concat ("txiXXXXXX", "", "")); - - /* Process input files completely, one by one. */ - - for (i = 0; i < num_infiles; i++) - { - int desc; - long ptr; - char *outfile; - - desc = open (infiles[i], O_RDONLY, 0); - if (desc < 0) - pfatal_with_name (infiles[i]); - lseek (desc, 0L, SEEK_END); - ptr = lseek (desc, 0L, SEEK_CUR); - - close (desc); - - outfile = outfiles[i]; - if (!outfile) - { - outfile = concat (infiles[i], "s", ""); - } - - if (ptr < MAX_IN_CORE_SORT) - /* Sort a small amount of data. */ - sort_in_core (infiles[i], ptr, outfile); - else - sort_offline (infiles[i], ptr, outfile); - } - - flush_tempfiles (tempcount); - exit (TI_NO_ERROR); -} - -void -usage () -{ - fprintf (stderr, "\ -Usage: %s [-k] infile [-o outfile] ...\n", program_name); - exit (1); -} - -/* Decode the command line arguments to set the parameter variables - and set up the vector of keyfields and the vector of input files. */ - -void -decode_command (argc, argv) - int argc; - char **argv; -{ - int optc; - char **ip; - char **op; - - /* Store default values into parameter variables. */ - - tempdir = getenv ("TMPDIR"); - if (tempdir == NULL) - tempdir = "/tmp/"; - else - tempdir = concat (tempdir, "/", ""); - - keep_tempfiles = 0; - - /* Allocate ARGC input files, which must be enough. */ - - infiles = (char **) xmalloc (argc * sizeof (char *)); - outfiles = (char **) xmalloc (argc * sizeof (char *)); - ip = infiles; - op = outfiles; - - while ((optc = getopt (argc, argv, "-ko:")) != EOF) - { - switch (optc) - { - case 1: /* Non-option filename. */ - *ip++ = optarg; - *op++ = NULL; - break; - - case 'k': - keep_tempfiles = 1; - break; - - case 'o': - if (op > outfiles) - *(op - 1) = optarg; - break; - - default: - usage (); - } - } - - /* Record number of keyfields and terminate list of filenames. */ - num_infiles = ip - infiles; - *ip = 0; - if (num_infiles == 0) - usage (); -} - -/* Return a name for a temporary file. */ - -char * -maketempname (count) - int count; -{ - char tempsuffix[10]; - sprintf (tempsuffix, "%d", count); - return concat (tempdir, tempbase, tempsuffix); -} - -/* Delete all temporary files up to TO_COUNT. */ - -void -flush_tempfiles (to_count) - int to_count; -{ - if (keep_tempfiles) - return; - while (last_deleted_tempcount < to_count) - unlink (maketempname (++last_deleted_tempcount)); -} - -/* Copy the input file open on IDESC into a temporary file - and return the temporary file name. */ - -#define BUFSIZE 1024 - -char * -tempcopy (idesc) - int idesc; -{ - char *outfile = maketempname (++tempcount); - int odesc; - char buffer[BUFSIZE]; - - odesc = open (outfile, O_WRONLY | O_CREAT, 0666); - - if (odesc < 0) - pfatal_with_name (outfile); - - while (1) - { - int nread = read (idesc, buffer, BUFSIZE); - write (odesc, buffer, nread); - if (!nread) - break; - } - - close (odesc); - - return outfile; -} - -/* Compare LINE1 and LINE2 according to the specified set of keyfields. */ - -int -compare_full (line1, line2) - char **line1, **line2; -{ - int i; - - /* Compare using the first keyfield; - if that does not distinguish the lines, try the second keyfield; - and so on. */ - - for (i = 0; i < num_keyfields; i++) - { - long length1, length2; - char *start1 = find_field (&keyfields[i], *line1, &length1); - char *start2 = find_field (&keyfields[i], *line2, &length2); - int tem = compare_field (&keyfields[i], start1, length1, *line1 - text_base, - start2, length2, *line2 - text_base); - if (tem) - { - if (keyfields[i].reverse) - return -tem; - return tem; - } - } - - return 0; /* Lines match exactly. */ -} - -/* Compare LINE1 and LINE2, described by structures - in which the first keyfield is identified in advance. - For positional sorting, assumes that the order of the lines in core - reflects their nominal order. */ - -int -compare_prepared (line1, line2) - struct lineinfo *line1, *line2; -{ - int i; - int tem; - char *text1, *text2; - - /* Compare using the first keyfield, which has been found for us already. */ - if (keyfields->positional) - { - if (line1->text - text_base > line2->text - text_base) - tem = 1; - else - tem = -1; - } - else if (keyfields->numeric) - tem = line1->key.number - line2->key.number; - else - tem = compare_field (keyfields, line1->key.text, line1->keylen, 0, - line2->key.text, line2->keylen, 0); - if (tem) - { - if (keyfields->reverse) - return -tem; - return tem; - } - - text1 = line1->text; - text2 = line2->text; - - /* Compare using the second keyfield; - if that does not distinguish the lines, try the third keyfield; - and so on. */ - - for (i = 1; i < num_keyfields; i++) - { - long length1, length2; - char *start1 = find_field (&keyfields[i], text1, &length1); - char *start2 = find_field (&keyfields[i], text2, &length2); - int tem = compare_field (&keyfields[i], start1, length1, text1 - text_base, - start2, length2, text2 - text_base); - if (tem) - { - if (keyfields[i].reverse) - return -tem; - return tem; - } - } - - return 0; /* Lines match exactly. */ -} - -/* Like compare_full but more general. - You can pass any strings, and you can say how many keyfields to use. - POS1 and POS2 should indicate the nominal positional ordering of - the two lines in the input. */ - -int -compare_general (str1, str2, pos1, pos2, use_keyfields) - char *str1, *str2; - long pos1, pos2; - int use_keyfields; -{ - int i; - - /* Compare using the first keyfield; - if that does not distinguish the lines, try the second keyfield; - and so on. */ - - for (i = 0; i < use_keyfields; i++) - { - long length1, length2; - char *start1 = find_field (&keyfields[i], str1, &length1); - char *start2 = find_field (&keyfields[i], str2, &length2); - int tem = compare_field (&keyfields[i], start1, length1, pos1, - start2, length2, pos2); - if (tem) - { - if (keyfields[i].reverse) - return -tem; - return tem; - } - } - - return 0; /* Lines match exactly. */ -} - -/* Find the start and length of a field in STR according to KEYFIELD. - A pointer to the starting character is returned, and the length - is stored into the int that LENGTHPTR points to. */ - -char * -find_field (keyfield, str, lengthptr) - struct keyfield *keyfield; - char *str; - long *lengthptr; -{ - char *start; - char *end; - char *(*fun) (); - - if (keyfield->braced) - fun = find_braced_pos; - else - fun = find_pos; - - start = (*fun) (str, keyfield->startwords, keyfield->startchars, - keyfield->ignore_blanks); - if (keyfield->endwords < 0) - { - if (keyfield->braced) - end = find_braced_end (start); - else - { - end = start; - while (*end && *end != '\n') - end++; - } - } - else - { - end = (*fun) (str, keyfield->endwords, keyfield->endchars, 0); - if (end - str < start - str) - end = start; - } - *lengthptr = end - start; - return start; -} - -/* Return a pointer to a specified place within STR, - skipping (from the beginning) WORDS words and then CHARS chars. - If IGNORE_BLANKS is nonzero, we skip all blanks - after finding the specified word. */ - -char * -find_pos (str, words, chars, ignore_blanks) - char *str; - int words, chars; - int ignore_blanks; -{ - int i; - char *p = str; - - for (i = 0; i < words; i++) - { - char c; - /* Find next bunch of nonblanks and skip them. */ - while ((c = *p) == ' ' || c == '\t') - p++; - while ((c = *p) && c != '\n' && !(c == ' ' || c == '\t')) - p++; - if (!*p || *p == '\n') - return p; - } - - while (*p == ' ' || *p == '\t') - p++; - - for (i = 0; i < chars; i++) - { - if (!*p || *p == '\n') - break; - p++; - } - return p; -} - -/* Like find_pos but assumes that each field is surrounded by braces - and that braces within fields are balanced. */ - -char * -find_braced_pos (str, words, chars, ignore_blanks) - char *str; - int words, chars; - int ignore_blanks; -{ - int i; - int bracelevel; - char *p = str; - char c; - - for (i = 0; i < words; i++) - { - bracelevel = 1; - while ((c = *p++) != '{' && c != '\n' && c) - /* Do nothing. */ ; - if (c != '{') - return p - 1; - while (bracelevel) - { - c = *p++; - if (c == '{') - bracelevel++; - if (c == '}') - bracelevel--; - if (c == 0 || c == '\n') - return p - 1; - } - } - - while ((c = *p++) != '{' && c != '\n' && c) - /* Do nothing. */ ; - - if (c != '{') - return p - 1; - - if (ignore_blanks) - while ((c = *p) == ' ' || c == '\t') - p++; - - for (i = 0; i < chars; i++) - { - if (!*p || *p == '\n') - break; - p++; - } - return p; -} - -/* Find the end of the balanced-brace field which starts at STR. - The position returned is just before the closing brace. */ - -char * -find_braced_end (str) - char *str; -{ - int bracelevel; - char *p = str; - char c; - - bracelevel = 1; - while (bracelevel) - { - c = *p++; - if (c == '{') - bracelevel++; - if (c == '}') - bracelevel--; - if (c == 0 || c == '\n') - return p - 1; - } - return p - 1; -} - -long -find_value (start, length) - char *start; - long length; -{ - while (length != 0L) - { - if (isdigit (*start)) - return atol (start); - length--; - start++; - } - return 0l; -} - -/* Vector used to translate characters for comparison. - This is how we make all alphanumerics follow all else, - and ignore case in the first sorting. */ -int char_order[256]; - -void -init_char_order () -{ - int i; - for (i = 1; i < 256; i++) - char_order[i] = i; - - for (i = '0'; i <= '9'; i++) - char_order[i] += 512; - - for (i = 'a'; i <= 'z'; i++) - { - char_order[i] = 512 + i; - char_order[i + 'A' - 'a'] = 512 + i; - } -} - -/* Compare two fields (each specified as a start pointer and a character count) - according to KEYFIELD. - The sign of the value reports the relation between the fields. */ - -int -compare_field (keyfield, start1, length1, pos1, start2, length2, pos2) - struct keyfield *keyfield; - char *start1; - long length1; - long pos1; - char *start2; - long length2; - long pos2; -{ - if (keyfields->positional) - { - if (pos1 > pos2) - return 1; - else - return -1; - } - if (keyfield->numeric) - { - long value = find_value (start1, length1) - find_value (start2, length2); - if (value > 0) - return 1; - if (value < 0) - return -1; - return 0; - } - else - { - char *p1 = start1; - char *p2 = start2; - char *e1 = start1 + length1; - char *e2 = start2 + length2; - - while (1) - { - int c1, c2; - - if (p1 == e1) - c1 = 0; - else - c1 = *p1++; - if (p2 == e2) - c2 = 0; - else - c2 = *p2++; - - if (char_order[c1] != char_order[c2]) - return char_order[c1] - char_order[c2]; - if (!c1) - break; - } - - /* Strings are equal except possibly for case. */ - p1 = start1; - p2 = start2; - while (1) - { - int c1, c2; - - if (p1 == e1) - c1 = 0; - else - c1 = *p1++; - if (p2 == e2) - c2 = 0; - else - c2 = *p2++; - - if (c1 != c2) - /* Reverse sign here so upper case comes out last. */ - return c2 - c1; - if (!c1) - break; - } - - return 0; - } -} - -/* A `struct linebuffer' is a structure which holds a line of text. - `readline' reads a line from a stream into a linebuffer - and works regardless of the length of the line. */ - -struct linebuffer -{ - long size; - char *buffer; -}; - -/* Initialize LINEBUFFER for use. */ - -void -initbuffer (linebuffer) - struct linebuffer *linebuffer; -{ - linebuffer->size = 200; - linebuffer->buffer = (char *) xmalloc (200); -} - -/* Read a line of text from STREAM into LINEBUFFER. - Return the length of the line. */ - -long -readline (linebuffer, stream) - struct linebuffer *linebuffer; - FILE *stream; -{ - char *buffer = linebuffer->buffer; - char *p = linebuffer->buffer; - char *end = p + linebuffer->size; - - while (1) - { - int c = getc (stream); - if (p == end) - { - buffer = (char *) xrealloc (buffer, linebuffer->size *= 2); - p += buffer - linebuffer->buffer; - end += buffer - linebuffer->buffer; - linebuffer->buffer = buffer; - } - if (c < 0 || c == '\n') - { - *p = 0; - break; - } - *p++ = c; - } - - return p - buffer; -} - -/* Sort an input file too big to sort in core. */ - -void -sort_offline (infile, nfiles, total, outfile) - char *infile; - int nfiles; - long total; - char *outfile; -{ - /* More than enough. */ - int ntemps = 2 * (total + MAX_IN_CORE_SORT - 1) / MAX_IN_CORE_SORT; - char **tempfiles = (char **) xmalloc (ntemps * sizeof (char *)); - FILE *istream = fopen (infile, "r"); - int i; - struct linebuffer lb; - long linelength; - int failure = 0; - - initbuffer (&lb); - - /* Read in one line of input data. */ - - linelength = readline (&lb, istream); - - if (lb.buffer[0] != '\\' && lb.buffer[0] != '@') - { - error ("%s: not a texinfo index file", infile); - return; - } - - /* Split up the input into `ntemps' temporary files, or maybe fewer, - and put the new files' names into `tempfiles' */ - - for (i = 0; i < ntemps; i++) - { - char *outname = maketempname (++tempcount); - FILE *ostream = fopen (outname, "w"); - long tempsize = 0; - - if (!ostream) - pfatal_with_name (outname); - tempfiles[i] = outname; - - /* Copy lines into this temp file as long as it does not make file - "too big" or until there are no more lines. */ - - while (tempsize + linelength + 1 <= MAX_IN_CORE_SORT) - { - tempsize += linelength + 1; - fputs (lb.buffer, ostream); - putc ('\n', ostream); - - /* Read another line of input data. */ - - linelength = readline (&lb, istream); - if (!linelength && feof (istream)) - break; - - if (lb.buffer[0] != '\\' && lb.buffer[0] != '@') - { - error ("%s: not a texinfo index file", infile); - failure = 1; - goto fail; - } - } - fclose (ostream); - if (feof (istream)) - break; - } - - free (lb.buffer); - -fail: - /* Record number of temp files we actually needed. */ - - ntemps = i; - - /* Sort each tempfile into another tempfile. - Delete the first set of tempfiles and put the names of the second - into `tempfiles'. */ - - for (i = 0; i < ntemps; i++) - { - char *newtemp = maketempname (++tempcount); - sort_in_core (&tempfiles[i], MAX_IN_CORE_SORT, newtemp); - if (!keep_tempfiles) - unlink (tempfiles[i]); - tempfiles[i] = newtemp; - } - - if (failure) - return; - - /* Merge the tempfiles together and indexify. */ - - merge_files (tempfiles, ntemps, outfile); -} - -/* Sort INFILE, whose size is TOTAL, - assuming that is small enough to be done in-core, - then indexify it and send the output to OUTFILE (or to stdout). */ - -void -sort_in_core (infile, total, outfile) - char *infile; - long total; - char *outfile; -{ - char **nextline; - char *data = (char *) xmalloc (total + 1); - char *file_data; - long file_size; - int i; - FILE *ostream = stdout; - struct lineinfo *lineinfo; - - /* Read the contents of the file into the moby array `data'. */ - - int desc = open (infile, O_RDONLY, 0); - - if (desc < 0) - fatal ("failure reopening %s", infile); - for (file_size = 0;;) - { - i = read (desc, data + file_size, total - file_size); - if (i <= 0) - break; - file_size += i; - } - file_data = data; - data[file_size] = 0; - - close (desc); - - if (file_size > 0 && data[0] != '\\' && data[0] != '@') - { - error ("%s: not a texinfo index file", infile); - return; - } - - init_char_order (); - - /* Sort routines want to know this address. */ - - text_base = data; - - /* Create the array of pointers to lines, with a default size - frequently enough. */ - - nlines = total / 50; - if (!nlines) - nlines = 2; - linearray = (char **) xmalloc (nlines * sizeof (char *)); - - /* `nextline' points to the next free slot in this array. - `nlines' is the allocated size. */ - - nextline = linearray; - - /* Parse the input file's data, and make entries for the lines. */ - - nextline = parsefile (infile, nextline, file_data, file_size); - if (nextline == 0) - { - error ("%s: not a texinfo index file", infile); - return; - } - - /* Sort the lines. */ - - /* If we have enough space, find the first keyfield of each line in advance. - Make a `struct lineinfo' for each line, which records the keyfield - as well as the line, and sort them. */ - - lineinfo = (struct lineinfo *) malloc ((nextline - linearray) * sizeof (struct lineinfo)); - - if (lineinfo) - { - struct lineinfo *lp; - char **p; - - for (lp = lineinfo, p = linearray; p != nextline; lp++, p++) - { - lp->text = *p; - lp->key.text = find_field (keyfields, *p, &lp->keylen); - if (keyfields->numeric) - lp->key.number = find_value (lp->key.text, lp->keylen); - } - - qsort (lineinfo, nextline - linearray, sizeof (struct lineinfo), compare_prepared); - - for (lp = lineinfo, p = linearray; p != nextline; lp++, p++) - *p = lp->text; - - free (lineinfo); - } - else - qsort (linearray, nextline - linearray, sizeof (char *), compare_full); - - /* Open the output file. */ - - if (outfile) - { - ostream = fopen (outfile, "w"); - if (!ostream) - pfatal_with_name (outfile); - } - - writelines (linearray, nextline - linearray, ostream); - if (outfile) - fclose (ostream); - - free (linearray); - free (data); -} - -/* Parse an input string in core into lines. - DATA is the input string, and SIZE is its length. - Data goes in LINEARRAY starting at NEXTLINE. - The value returned is the first entry in LINEARRAY still unused. - Value 0 means input file contents are invalid. */ - -char ** -parsefile (filename, nextline, data, size) - char *filename; - char **nextline; - char *data; - long size; -{ - char *p, *end; - char **line = nextline; - - p = data; - end = p + size; - *end = 0; - - while (p != end) - { - if (p[0] != '\\' && p[0] != '@') - return 0; - - *line = p; - while (*p && *p != '\n') - p++; - if (p != end) - p++; - - line++; - if (line == linearray + nlines) - { - char **old = linearray; - linearray = (char **) xrealloc (linearray, sizeof (char *) * (nlines *= 4)); - line += linearray - old; - } - } - - return line; -} - -/* Indexification is a filter applied to the sorted lines - as they are being written to the output file. - Multiple entries for the same name, with different page numbers, - get combined into a single entry with multiple page numbers. - The first braced field, which is used for sorting, is discarded. - However, its first character is examined, folded to lower case, - and if it is different from that in the previous line fed to us - a \initial line is written with one argument, the new initial. - - If an entry has four braced fields, then the second and third - constitute primary and secondary names. - In this case, each change of primary name - generates a \primary line which contains only the primary name, - and in between these are \secondary lines which contain - just a secondary name and page numbers. */ - -/* The last primary name we wrote a \primary entry for. - If only one level of indexing is being done, this is the last name seen. */ -char *lastprimary; -/* Length of storage allocated for lastprimary. */ -int lastprimarylength; - -/* Similar, for the secondary name. */ -char *lastsecondary; -int lastsecondarylength; - -/* Zero if we are not in the middle of writing an entry. - One if we have written the beginning of an entry but have not - yet written any page numbers into it. - Greater than one if we have written the beginning of an entry - plus at least one page number. */ -int pending; - -/* The initial (for sorting purposes) of the last primary entry written. - When this changes, a \initial {c} line is written */ - -char *lastinitial; - -int lastinitiallength; - -/* When we need a string of length 1 for the value of lastinitial, - store it here. */ - -char lastinitial1[2]; - -/* Initialize static storage for writing an index. */ - -static void -xbzero(s, n) - char *s; - int n; -{ - register char *p; - for (p = s; n--; ) - *p++ = '\0'; -} - -void -init_index () -{ - pending = 0; - lastinitial = lastinitial1; - lastinitial1[0] = 0; - lastinitial1[1] = 0; - lastinitiallength = 0; - lastprimarylength = 100; - lastprimary = (char *) xmalloc (lastprimarylength + 1); - xbzero (lastprimary, lastprimarylength + 1); - lastsecondarylength = 100; - lastsecondary = (char *) xmalloc (lastsecondarylength + 1); - xbzero (lastsecondary, lastsecondarylength + 1); -} - -/* Indexify. Merge entries for the same name, - insert headers for each initial character, etc. */ - -void -indexify (line, ostream) - char *line; - FILE *ostream; -{ - char *primary, *secondary, *pagenumber; - int primarylength, secondarylength = 0, pagelength; - int nosecondary; - int initiallength; - char *initial; - char initial1[2]; - register char *p; - - /* First, analyze the parts of the entry fed to us this time. */ - - p = find_braced_pos (line, 0, 0, 0); - if (*p == '{') - { - initial = p; - /* Get length of inner pair of braces starting at `p', - including that inner pair of braces. */ - initiallength = find_braced_end (p + 1) + 1 - p; - } - else - { - initial = initial1; - initial1[0] = *p; - initial1[1] = 0; - initiallength = 1; - - if (initial1[0] >= 'a' && initial1[0] <= 'z') - initial1[0] -= 040; - } - - pagenumber = find_braced_pos (line, 1, 0, 0); - pagelength = find_braced_end (pagenumber) - pagenumber; - if (pagelength == 0) - abort (); - - primary = find_braced_pos (line, 2, 0, 0); - primarylength = find_braced_end (primary) - primary; - - secondary = find_braced_pos (line, 3, 0, 0); - nosecondary = !*secondary; - if (!nosecondary) - secondarylength = find_braced_end (secondary) - secondary; - - /* If the primary is different from before, make a new primary entry. */ - if (strncmp (primary, lastprimary, primarylength)) - { - /* Close off current secondary entry first, if one is open. */ - if (pending) - { - fputs ("}\n", ostream); - pending = 0; - } - - /* If this primary has a different initial, include an entry for - the initial. */ - if (initiallength != lastinitiallength || - strncmp (initial, lastinitial, initiallength)) - { - fprintf (ostream, "\\initial {"); - fwrite (initial, 1, initiallength, ostream); - fprintf (ostream, "}\n", initial); - if (initial == initial1) - { - lastinitial = lastinitial1; - *lastinitial1 = *initial1; - } - else - { - lastinitial = initial; - } - lastinitiallength = initiallength; - } - - /* Make the entry for the primary. */ - if (nosecondary) - fputs ("\\entry {", ostream); - else - fputs ("\\primary {", ostream); - fwrite (primary, primarylength, 1, ostream); - if (nosecondary) - { - fputs ("}{", ostream); - pending = 1; - } - else - fputs ("}\n", ostream); - - /* Record name of most recent primary. */ - if (lastprimarylength < primarylength) - { - lastprimarylength = primarylength + 100; - lastprimary = (char *) xrealloc (lastprimary, - 1 + lastprimarylength); - } - strncpy (lastprimary, primary, primarylength); - lastprimary[primarylength] = 0; - - /* There is no current secondary within this primary, now. */ - lastsecondary[0] = 0; - } - - /* Should not have an entry with no subtopic following one with a subtopic. */ - - if (nosecondary && *lastsecondary) - error ("entry %s follows an entry with a secondary name", line); - - /* Start a new secondary entry if necessary. */ - if (!nosecondary && strncmp (secondary, lastsecondary, secondarylength)) - { - if (pending) - { - fputs ("}\n", ostream); - pending = 0; - } - - /* Write the entry for the secondary. */ - fputs ("\\secondary {", ostream); - fwrite (secondary, secondarylength, 1, ostream); - fputs ("}{", ostream); - pending = 1; - - /* Record name of most recent secondary. */ - if (lastsecondarylength < secondarylength) - { - lastsecondarylength = secondarylength + 100; - lastsecondary = (char *) xrealloc (lastsecondary, - 1 + lastsecondarylength); - } - strncpy (lastsecondary, secondary, secondarylength); - lastsecondary[secondarylength] = 0; - } - - /* Here to add one more page number to the current entry. */ - if (pending++ != 1) - fputs (", ", ostream); /* Punctuate first, if this is not the first. */ - fwrite (pagenumber, pagelength, 1, ostream); -} - -/* Close out any unfinished output entry. */ - -void -finish_index (ostream) - FILE *ostream; -{ - if (pending) - fputs ("}\n", ostream); - free (lastprimary); - free (lastsecondary); -} - -/* Copy the lines in the sorted order. - Each line is copied out of the input file it was found in. */ - -void -writelines (linearray, nlines, ostream) - char **linearray; - int nlines; - FILE *ostream; -{ - char **stop_line = linearray + nlines; - char **next_line; - - init_index (); - - /* Output the text of the lines, and free the buffer space. */ - - for (next_line = linearray; next_line != stop_line; next_line++) - { - /* If -u was specified, output the line only if distinct from previous one. */ - if (next_line == linearray - /* Compare previous line with this one, using only the - explicitly specd keyfields. */ - || compare_general (*(next_line - 1), *next_line, 0L, 0L, num_keyfields - 1)) - { - char *p = *next_line; - char c; - - while ((c = *p++) && c != '\n') - /* Do nothing. */ ; - *(p - 1) = 0; - indexify (*next_line, ostream); - } - } - - finish_index (ostream); -} - -/* Assume (and optionally verify) that each input file is sorted; - merge them and output the result. - Returns nonzero if any input file fails to be sorted. - - This is the high-level interface that can handle an unlimited - number of files. */ - -#define MAX_DIRECT_MERGE 10 - -int -merge_files (infiles, nfiles, outfile) - char **infiles; - int nfiles; - char *outfile; -{ - char **tempfiles; - int ntemps; - int i; - int value = 0; - int start_tempcount = tempcount; - - if (nfiles <= MAX_DIRECT_MERGE) - return merge_direct (infiles, nfiles, outfile); - - /* Merge groups of MAX_DIRECT_MERGE input files at a time, - making a temporary file to hold each group's result. */ - - ntemps = (nfiles + MAX_DIRECT_MERGE - 1) / MAX_DIRECT_MERGE; - tempfiles = (char **) xmalloc (ntemps * sizeof (char *)); - for (i = 0; i < ntemps; i++) - { - int nf = MAX_DIRECT_MERGE; - if (i + 1 == ntemps) - nf = nfiles - i * MAX_DIRECT_MERGE; - tempfiles[i] = maketempname (++tempcount); - value |= merge_direct (&infiles[i * MAX_DIRECT_MERGE], nf, tempfiles[i]); - } - - /* All temporary files that existed before are no longer needed - since their contents have been merged into our new tempfiles. - So delete them. */ - flush_tempfiles (start_tempcount); - - /* Now merge the temporary files we created. */ - - merge_files (tempfiles, ntemps, outfile); - - free (tempfiles); - - return value; -} - -/* Assume (and optionally verify) that each input file is sorted; - merge them and output the result. - Returns nonzero if any input file fails to be sorted. - - This version of merging will not work if the number of - input files gets too high. Higher level functions - use it only with a bounded number of input files. */ - -int -merge_direct (infiles, nfiles, outfile) - char **infiles; - int nfiles; - char *outfile; -{ - struct linebuffer *lb1, *lb2; - struct linebuffer **thisline, **prevline; - FILE **streams; - int i; - int nleft; - int lossage = 0; - int *file_lossage; - struct linebuffer *prev_out = 0; - FILE *ostream = stdout; - - if (outfile) - { - ostream = fopen (outfile, "w"); - } - if (!ostream) - pfatal_with_name (outfile); - - init_index (); - - if (nfiles == 0) - { - if (outfile) - fclose (ostream); - return 0; - } - - /* For each file, make two line buffers. - Also, for each file, there is an element of `thisline' - which points at any time to one of the file's two buffers, - and an element of `prevline' which points to the other buffer. - `thisline' is supposed to point to the next available line from the file, - while `prevline' holds the last file line used, - which is remembered so that we can verify that the file is properly sorted. */ - - /* lb1 and lb2 contain one buffer each per file. */ - lb1 = (struct linebuffer *) xmalloc (nfiles * sizeof (struct linebuffer)); - lb2 = (struct linebuffer *) xmalloc (nfiles * sizeof (struct linebuffer)); - - /* thisline[i] points to the linebuffer holding the next available line in file i, - or is zero if there are no lines left in that file. */ - thisline = (struct linebuffer **) - xmalloc (nfiles * sizeof (struct linebuffer *)); - /* prevline[i] points to the linebuffer holding the last used line - from file i. This is just for verifying that file i is properly - sorted. */ - prevline = (struct linebuffer **) - xmalloc (nfiles * sizeof (struct linebuffer *)); - /* streams[i] holds the input stream for file i. */ - streams = (FILE **) xmalloc (nfiles * sizeof (FILE *)); - /* file_lossage[i] is nonzero if we already know file i is not - properly sorted. */ - file_lossage = (int *) xmalloc (nfiles * sizeof (int)); - - /* Allocate and initialize all that storage. */ - - for (i = 0; i < nfiles; i++) - { - initbuffer (&lb1[i]); - initbuffer (&lb2[i]); - thisline[i] = &lb1[i]; - prevline[i] = &lb2[i]; - file_lossage[i] = 0; - streams[i] = fopen (infiles[i], "r"); - if (!streams[i]) - pfatal_with_name (infiles[i]); - - readline (thisline[i], streams[i]); - } - - /* Keep count of number of files not at eof. */ - nleft = nfiles; - - while (nleft) - { - struct linebuffer *best = 0; - struct linebuffer *exch; - int bestfile = -1; - int i; - - /* Look at the next avail line of each file; choose the least one. */ - - for (i = 0; i < nfiles; i++) - { - if (thisline[i] && - (!best || - 0 < compare_general (best->buffer, thisline[i]->buffer, - (long) bestfile, (long) i, num_keyfields))) - { - best = thisline[i]; - bestfile = i; - } - } - - /* Output that line, unless it matches the previous one and we - don't want duplicates. */ - - if (!(prev_out && - !compare_general (prev_out->buffer, - best->buffer, 0L, 1L, num_keyfields - 1))) - indexify (best->buffer, ostream); - prev_out = best; - - /* Now make the line the previous of its file, and fetch a new - line from that file. */ - - exch = prevline[bestfile]; - prevline[bestfile] = thisline[bestfile]; - thisline[bestfile] = exch; - - while (1) - { - /* If the file has no more, mark it empty. */ - - if (feof (streams[bestfile])) - { - thisline[bestfile] = 0; - /* Update the number of files still not empty. */ - nleft--; - break; - } - readline (thisline[bestfile], streams[bestfile]); - if (thisline[bestfile]->buffer[0] || !feof (streams[bestfile])) - break; - } - } - - finish_index (ostream); - - /* Free all storage and close all input streams. */ - - for (i = 0; i < nfiles; i++) - { - fclose (streams[i]); - free (lb1[i].buffer); - free (lb2[i].buffer); - } - free (file_lossage); - free (lb1); - free (lb2); - free (thisline); - free (prevline); - free (streams); - - if (outfile) - fclose (ostream); - - return lossage; -} - -/* Print error message and exit. */ - -void -fatal (s1, s2) - char *s1, *s2; -{ - error (s1, s2); - exit (TI_FATAL_ERROR); -} - -/* Print error message. S1 is printf control string, S2 is arg for it. */ - -void -error (s1, s2) - char *s1, *s2; -{ - printf ("%s: ", program_name); - printf (s1, s2); - printf ("\n"); -} - -#if !defined (HAVE_STRERROR) -static char * -strerror (n) - int n; -{ - static char ebuf[40]; - - if (n < sys_nerr) - return sys_errlist[n]; - else - { - sprintf (ebuf, "Unknown error %d", n); - return ebuf; - } -} -#endif - -void -perror_with_name (name) - char *name; -{ - char *s; - - s = concat ("", strerror (errno), " for %s"); - error (s, name); -} - -void -pfatal_with_name (name) - char *name; -{ - char *s; - - s = concat ("", strerror (errno), " for %s"); - fatal (s, name); -} - -/* Return a newly-allocated string whose contents concatenate those of - S1, S2, S3. */ - -char * -concat (s1, s2, s3) - char *s1, *s2, *s3; -{ - int len1 = strlen (s1), len2 = strlen (s2), len3 = strlen (s3); - char *result = (char *) xmalloc (len1 + len2 + len3 + 1); - - strcpy (result, s1); - strcpy (result + len1, s2); - strcpy (result + len1 + len2, s3); - *(result + len1 + len2 + len3) = 0; - - return result; -} - -/* Just like malloc, but kills the program in case of fatal error. */ -void * -xmalloc (nbytes) - int nbytes; -{ - void *temp = (void *) malloc (nbytes); - - if (nbytes && temp == (void *)NULL) - memory_error ("xmalloc", nbytes); - - return (temp); -} - -/* Like realloc (), but barfs if there isn't enough memory. */ -void * -xrealloc (pointer, nbytes) - void *pointer; - int nbytes; -{ - void *temp; - - if (!pointer) - temp = (void *)xmalloc (nbytes); - else - temp = (void *)realloc (pointer, nbytes); - - if (nbytes && !temp) - memory_error ("xrealloc", nbytes); - - return (temp); -} - -memory_error (callers_name, bytes_wanted) - char *callers_name; - int bytes_wanted; -{ - char printable_string[80]; - - sprintf (printable_string, - "Virtual memory exhausted in %s ()! Needed %d bytes.", - callers_name, bytes_wanted); - - error (printable_string, ""); - abort (); -} diff --git a/lib/glob/Makefile b/lib/glob/Makefile.in similarity index 54% rename from lib/glob/Makefile rename to lib/glob/Makefile.in index 5811ba2..4471c18 100644 --- a/lib/glob/Makefile +++ b/lib/glob/Makefile.in @@ -4,39 +4,46 @@ # # #################################################################### -# This Makefile is hand made from a template file, found in -# ../template. Each library must provide several Makefile -# targets: `all', `clean', `documentation', `install', and -# `what-tar'. The `what-tar' target reports the names of the -# files that need to be included in a tarfile to build the full -# code and documentation for this library. - -# Please note that the values for INCLUDES, CC, AR, RM, CP, -# RANLIB, and selfdir are passed in from ../Makefile, and do -# not need to be defined here. -srcdir = . -VPATH = .:$(srcdir) +srcdir = @srcdir@ +VPATH = .:@srcdir@ +topdir = @top_srcdir@ +BUILD_DIR = @BUILD_DIR@ + +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_DATA = @INSTALL_DATA@ + +CC = @CC@ +RANLIB = @RANLIB@ +AR = @AR@ +RM = rm +CP = cp +MV = mv + +CFLAGS = @CFLAGS@ +LOCAL_CFLAGS = @LOCAL_CFLAGS@ +CPPFLAGS = @CPPFLAGS@ +LDFLAGS = @LDFLAGS@ @LOCAL_LDFLAGS@ + +DEFS = @DEFS@ + +INCLUDES = -I. -I../.. -I$(topdir) -I$(topdir)/lib + +CCFLAGS = $(DEFS) $(CPPFLAGS) ${INCLUDES} $(LOCAL_CFLAGS) $(CFLAGS) # Here is a rule for making .o files from .c files that doesn't force # the type of the machine (like -sun3) into the flags. .c.o: - $(CC) -c $(CFLAGS) $(INCLUDES) $(LOCAL_DEFINES) $(CPPFLAGS) $< - -# LOCAL_DEFINES are flags that are specific to this library. -# Define -DUSG if you are using a System V operating system. -LOCAL_DEFINES = $(LOCAL_INCLUDES) #-DUSG - -# For libraries which include headers from other libraries. -LOCAL_INCLUDES = -I.. + $(CC) -c $(CCFLAGS) $< # The name of the library target. LIBRARY_NAME = libglob.a # The C code source files for this library. -CSOURCES = $(srcdir)glob.c $(srcdir)fnmatch.c +CSOURCES = $(srcdir)/glob.c $(srcdir)/fnmatch.c # The header files for this library. -HSOURCES = $(srcdir)fnmatch.h +HSOURCES = $(srcdir)/fnmatch.h OBJECTS = glob.o fnmatch.o @@ -58,8 +65,8 @@ all: $(LIBRARY_NAME) $(LIBRARY_NAME): $(OBJECTS) $(RM) -f $@ - $(AR) cq $@ $(OBJECTS) - -[ -n "$(RANLIB)" ] && $(RANLIB) $@ + $(AR) cr $@ $(OBJECTS) + -test -n "$(RANLIB)" && $(RANLIB) $@ what-tar: @for file in $(THINGS_TO_TAR); do \ @@ -67,24 +74,24 @@ what-tar: done documentation: force - -(cd doc && $(MAKE) $(MFLAGS)) - + -(cd doc; $(MAKE) $(MFLAGS)) force: # The rule for 'includes' is written funny so that the if statement # always returns TRUE unless there really was an error installing the # include files. install: - -$(MV) $(bindir)/$(LIBRARY_NAME) $(bindir)/$(LIBRARY_NAME)-old - $(CP) $(LIBRARY_NAME) $(bindir)/$(LIBRARY_NAME) - -[ -n "$(RANLIB)" ] && $(RANLIB) -t $(bindir)/$(LIBRARY_NAME) clean: rm -f $(OBJECTS) $(LIBRARY_NAME) - -(cd doc && $(MAKE) $(MFLAGS) $@) + -(cd doc && $(MAKE) $(MFLAGS) $@ ) -maintainer-clean realclean mostlyclean distclean: clean - -(cd doc && $(MAKE) $(MFLAGS) $@) +realclean distclean maintainer-clean: clean + -( cd doc && $(MAKE) $(MFLAGS) $@ ) + $(RM) -f Makefile + +mostlyclean: clean + -( cd doc && $(MAKE) $(MFLAGS) $@ ) ###################################################################### # # @@ -93,3 +100,6 @@ maintainer-clean realclean mostlyclean distclean: clean ###################################################################### fnmatch.o: fnmatch.c fnmatch.h + +fnmatch.o: $(BUILD_DIR)/config.h +glob.o: $(BUILD_DIR)/config.h diff --git a/lib/glob/doc/Makefile b/lib/glob/doc/Makefile index 1b6084c..8dca606 100644 --- a/lib/glob/doc/Makefile +++ b/lib/glob/doc/Makefile @@ -1,5 +1,5 @@ all: cp glob.texi glob.info -maintainer-clean realclean distclean clean: +clean distclean mostlyclean maintainer-clean: rm -f glob.?? glob.info diff --git a/lib/glob/fnmatch.c b/lib/glob/fnmatch.c index 6a8b574..0763609 100644 --- a/lib/glob/fnmatch.c +++ b/lib/glob/fnmatch.c @@ -68,10 +68,14 @@ fnmatch (pattern, string, flags) (n == string || ((flags & FNM_PATHNAME) && n[-1] == '/'))) return (FNM_NOMATCH); - for (c = *p++; c == '?' || c == '*'; c = *p++, ++n) - if (((flags & FNM_PATHNAME) && *n == '/') || - (c == '?' && *n == '\0')) - return (FNM_NOMATCH); + for (c = *p++; c == '?' || c == '*'; c = *p++) + { + if (((flags & FNM_PATHNAME) && *n == '/') || + (c == '?' && *n == '\0')) + return (FNM_NOMATCH); + if (c == '?') + n++; + } if (c == '\0') return (0); diff --git a/lib/glob/glob.c b/lib/glob/glob.c index 6ff2cb4..412e15c 100644 --- a/lib/glob/glob.c +++ b/lib/glob/glob.c @@ -14,45 +14,48 @@ You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ - + /* To whomever it may concern: I have never seen the code which most Unix programs use to perform this function. I wrote this from scratch based on specifications for the pattern matching. --RMS. */ -#if defined (SHELL) -# if defined (HAVE_STDLIB_H) -# include -# else +#include + +#if !defined (__GNUC__) && !defined (HAVE_ALLOCA_H) && defined (_AIX) + #pragma alloca +#endif /* _AIX && RISC6000 && !__GNUC__ */ + +#if defined (HAVE_UNISTD_H) +# include +#endif + +#if defined (HAVE_STDLIB_H) +# include +#else +# if defined (SHELL) # include "ansi_stdlib.h" -# endif /* HAVE_STDLIB_H */ -# include +# endif /* SHELL */ #endif #include -#if !defined (SHELL) && (defined (_POSIX_VERSION) || defined (USGr3)) -# if !defined (HAVE_DIRENT_H) -# define HAVE_DIRENT_H -# endif /* !HAVE_DIRENT_H */ -#endif /* !SHELL && (_POSIX_VERSION || USGr3) */ - #if defined (HAVE_DIRENT_H) # include -# if !defined (direct) -# define direct dirent -# endif /* !direct */ # define D_NAMLEN(d) strlen ((d)->d_name) #else /* !HAVE_DIRENT_H */ # define D_NAMLEN(d) ((d)->d_namlen) -# if defined (USG) -# if defined (Xenix) -# include -# else /* !Xenix (but USG...) */ -# include "ndir.h" -# endif /* !Xenix */ -# else /* !USG */ +# if defined (HAVE_SYS_NDIR_H) +# include +# endif +# if defined (HAVE_SYS_DIR_H) # include -# endif /* !USG */ +# endif /* HAVE_SYS_DIR_H */ +# if defined (HAVE_NDIR_H) +# include +# endif +# if !defined (dirent) +# define dirent direct +# endif #endif /* !HAVE_DIRENT_H */ #if defined (_POSIX_SOURCE) @@ -63,34 +66,18 @@ # define REAL_DIR_ENTRY(dp) (dp->d_ino != 0) #endif /* _POSIX_SOURCE */ -#if defined (USG) || defined (NeXT) -# if !defined (HAVE_STRING_H) -# define HAVE_STRING_H -# endif /* !HAVE_STRING_H */ -#endif /* USG || NeXT */ - #if defined (HAVE_STRING_H) # include #else /* !HAVE_STRING_H */ # include #endif /* !HAVE_STRING_H */ -#if defined (USG) -# if !defined (isc386) -# include -# endif /* !isc386 */ -# if defined (RISC6000) -extern void bcopy (); -# else /* !RISC6000 */ -# define bcopy(s, d, n) ((void) memcpy ((d), (s), (n))) -# endif /* !RISC6000 */ -#endif /* USG */ - -#include "fnmatch.h" +#if !defined (HAVE_BCOPY) +# define bcopy(s, d, n) ((void) memcpy ((d), (s), (n))) +#endif /* !HAVE_BCOPY */ /* If the opendir () on your system lets you open non-directory files, - then we consider that not robust. Define OPENDIR_NOT_ROBUST in the - SYSDEP_CFLAGS for your machines entry in machines.h. */ + then we consider that not robust. */ #if defined (OPENDIR_NOT_ROBUST) # if defined (SHELL) # include "posixstat.h" @@ -99,7 +86,10 @@ extern void bcopy (); # endif /* !SHELL */ #endif /* OPENDIR_NOT_ROBUST */ -#if !defined (HAVE_STDLIB_H) +#include "memalloc.h" +#include "fnmatch.h" + +#if !defined (HAVE_STDLIB_H) && !defined (SHELL) extern char *malloc (), *realloc (); extern void free (); #endif /* !HAVE_STDLIB_H */ @@ -123,7 +113,6 @@ int noglob_dot_filenames = 1; /* Global variable to return to signify an error in globbing. */ char *glob_error_return; - /* Return nonzero if PATTERN has any special globbing chars in it. */ int glob_pattern_p (pattern) @@ -205,7 +194,7 @@ glob_vector (pat, dir) }; DIR *d; - register struct direct *dp; + register struct dirent *dp; struct globval *lastlink; register struct globval *nextlink; register char *nextname; @@ -365,7 +354,14 @@ glob_dir_to_array (dir, array) + strlen (array[i]) + 1); if (result[i] == NULL) return (NULL); - sprintf (result[i], "%s%s%s", dir, add_slash ? "/" : "", array[i]); +#if 1 + strcpy (result[i], dir); + if (add_slash) + result[i][l] = '/'; + strcpy (result[i] + l + add_slash, array[i]); +#else + (void)sprintf (result[i], "%s%s%s", dir, add_slash ? "/" : "", array[i]); +#endif } result[i] = NULL; @@ -432,7 +428,7 @@ glob_filename (pathname) goto memory_error; else if (directories == (char **)&glob_error_return) { - free ((char *)result); + free ((char *) result); return ((char **) &glob_error_return); } else if (*directories == NULL) diff --git a/lib/glob/glob.h b/lib/glob/glob.h new file mode 100644 index 0000000..a72dede --- /dev/null +++ b/lib/glob/glob.h @@ -0,0 +1,30 @@ +/* File-name wildcard pattern matching for GNU. + Copyright (C) 1985, 1988, 1989 Free Software Foundation, Inc. + + This program 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 1, or (at your option) + any later version. + + This program 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 this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#ifndef _GLOB_H_ +#define _GLOB_H_ + +#include "stdc.h" + +extern int glob_pattern_p __P((char *)); +extern char **glob_vector __P((char *, char *)); +extern char **glob_filename __P((char *)); + +extern char *glob_error_return; +extern int noglob_dot_filenames; + +#endif /* _GLOB_H_ */ diff --git a/lib/malloc/Makefile b/lib/malloc/Makefile deleted file mode 100644 index 4c0ab72..0000000 --- a/lib/malloc/Makefile +++ /dev/null @@ -1,28 +0,0 @@ -# Skeleton Makefile for the GNU malloc code -# -# Maybe this should really create a library instead of just compiling -# source files - -srcdir = . -VPATH = .:$(srcdir) - -.c.o: - $(CC) $(CFLAGS) $(CPPFLAGS) -c $< - -.s.o: - $(CC) $(CFLAGS) $(CPPFLAGS) -c $< - -MALLOC_SOURCE = malloc.c - -ALLOCA_SOURCE = alloca.c -ALLOCA_OBJECT = alloca.o - -malloc.o: malloc.c getpagesize.h - -$(ALLOCA_OBJECT): $(ALLOCA_SOURCE) - -alloca.o: $(ALLOCA_SOURCE) - $(CC) $(CFLAGS) $(CPPFLAGS) -c $< - @- if [ "$(ALLOCA_OBJECT)" != alloca.o ]; then \ - mv $(ALLOCA_OBJECT) alloca.o >/dev/null 2>&1 ; \ - fi diff --git a/lib/malloc/Makefile.in b/lib/malloc/Makefile.in new file mode 100644 index 0000000..6bba7d1 --- /dev/null +++ b/lib/malloc/Makefile.in @@ -0,0 +1,68 @@ +# Skeleton Makefile for the GNU malloc code +# + +srcdir = @srcdir@ +VPATH = .:@srcdir@ +topdir = @top_srcdir@ +BUILD_DIR = @BUILD_DIR@ + +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_DATA = @INSTALL_DATA@ + +CC = @CC@ +RANLIB = @RANLIB@ +AR = @AR@ +RM = rm -f +CP = cp +MV = mv + +CFLAGS = @CFLAGS@ +LOCAL_CFLAGS = @LOCAL_CFLAGS@ +CPPFLAGS = @CPPFLAGS@ +LDFLAGS = @LDFLAGS@ + +DEFS = @DEFS@ + +INCLUDES = -I. -I../.. -I$(topdir) -I$(topdir)/lib + +CCFLAGS = ${INCLUDES} $(DEFS) $(LOCAL_CFLAGS) $(CFLAGS) $(MALLOC_CFLAGS) $(CPPFLAGS) + +.c.o: + $(CC) $(CCFLAGS) -c $< + +.s.o: + $(CC) $(CCFLAGS) -c $< + +MALLOC_SOURCE = malloc.c + +ALLOCA_SOURCE = alloca.c +ALLOCA_OBJECT = alloca.o + +MALLOC_SRC = @MALLOC_SRC@ +MALLOC = @MALLOC@ +ALLOCA = @ALLOCA@ + +libmalloc.a: $(MALLOC) $(ALLOCA) stub.o + $(RM) $@ + $(AR) cr $@ $(MALLOC) $(ALLOCA) stub.o + -test -n "$(RANLIB)" && $(RANLIB) $@ + +malloc.o: malloc.c getpagesize.h + +alloca.o: $(ALLOCA_SOURCE) + $(CC) $(CCFLAGS) -c $(ALLOCA_SOURCE) + @- if test "$(ALLOCA_OBJECT)" != alloca.o ; then \ + mv $(ALLOCA_OBJECT) alloca.o >/dev/null 2>&1 ; \ + fi + +mostlyclean clean: + $(RM) *.o libmalloc.a + +distclean realclean maintainer-clean: clean + $(RM) Makefile + +alloca.o: $(BUILD_DIR)/config.h +malloc.o: $(BUILD_DIR)/config.h +xmalloc.o: $(BUILD_DIR)/config.h +gmalloc.o: $(BUILD_DIR)/config.h diff --git a/lib/malloc/gmalloc.c b/lib/malloc/gmalloc.c new file mode 100644 index 0000000..8690b12 --- /dev/null +++ b/lib/malloc/gmalloc.c @@ -0,0 +1,1579 @@ +/* DO NOT EDIT THIS FILE -- it is automagically generated. -*- C -*- */ + +#define _MALLOC_INTERNAL + +/* The malloc headers and source files from the C library follow here. */ + +/* Declarations for `malloc' and friends. + Copyright 1990, 91, 92, 93, 95, 96 Free Software Foundation, Inc. + Written May 1989 by Mike Haertel. + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +This 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 +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with this library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. + + The author may be reached (Email) at the address mike@ai.mit.edu, + or (US mail) as Mike Haertel c/o Free Software Foundation. */ + +#ifndef _MALLOC_H + +#define _MALLOC_H 1 + +#ifdef _MALLOC_INTERNAL + +#ifdef HAVE_CONFIG_H +#include +#endif + +#if defined(_LIBC) || defined(STDC_HEADERS) || defined(USG) +#include +#else +#ifndef memset +#define memset(s, zero, n) bzero ((s), (n)) +#endif +#ifndef memcpy +#define memcpy(d, s, n) bcopy ((s), (d), (n)) +#endif +#endif + +#if defined (__GNU_LIBRARY__) || (defined (__STDC__) && __STDC__) +#include +#else +#ifndef CHAR_BIT +#define CHAR_BIT 8 +#endif +#endif + +#ifdef HAVE_UNISTD_H +#include +#endif + +#endif /* _MALLOC_INTERNAL. */ + + +#ifdef __cplusplus +extern "C" +{ +#endif + +#if defined (__cplusplus) || (defined (__STDC__) && __STDC__) +#undef __P +#define __P(args) args +#undef __ptr_t +#define __ptr_t void * +#else /* Not C++ or ANSI C. */ +#undef __P +#define __P(args) () +#undef const +#define const +#undef __ptr_t +#define __ptr_t char * +#endif /* C++ or ANSI C. */ + +#if defined (__STDC__) && __STDC__ +#include +#define __malloc_size_t size_t +#define __malloc_ptrdiff_t ptrdiff_t +#else +#define __malloc_size_t unsigned int +#define __malloc_ptrdiff_t int +#endif + +#ifndef NULL +#define NULL 0 +#endif + + +/* Allocate SIZE bytes of memory. */ +extern __ptr_t malloc __P ((__malloc_size_t __size)); +/* Re-allocate the previously allocated block + in __ptr_t, making the new block SIZE bytes long. */ +extern __ptr_t realloc __P ((__ptr_t __ptr, __malloc_size_t __size)); +/* Allocate NMEMB elements of SIZE bytes each, all initialized to 0. */ +extern __ptr_t calloc __P ((__malloc_size_t __nmemb, __malloc_size_t __size)); +/* Free a block allocated by `malloc', `realloc' or `calloc'. */ +extern void free __P ((__ptr_t __ptr)); + +/* Allocate SIZE bytes allocated to ALIGNMENT bytes. */ +#if ! (defined (_MALLOC_INTERNAL) && __DJGPP__ - 0 == 1) /* Avoid conflict. */ +extern __ptr_t memalign __P ((__malloc_size_t __alignment, + __malloc_size_t __size)); +#endif + +/* Allocate SIZE bytes on a page boundary. */ +#if ! (defined (_MALLOC_INTERNAL) && defined (emacs)) /* Avoid conflict. */ +extern __ptr_t valloc __P ((__malloc_size_t __size)); +#endif + + +#ifdef _MALLOC_INTERNAL + +/* The allocator divides the heap into blocks of fixed size; large + requests receive one or more whole blocks, and small requests + receive a fragment of a block. Fragment sizes are powers of two, + and all fragments of a block are the same size. When all the + fragments in a block have been freed, the block itself is freed. */ +#define INT_BIT (CHAR_BIT * sizeof(int)) +#define BLOCKLOG (INT_BIT > 16 ? 12 : 9) +#define BLOCKSIZE (1 << BLOCKLOG) +#define BLOCKIFY(SIZE) (((SIZE) + BLOCKSIZE - 1) / BLOCKSIZE) + +/* Determine the amount of memory spanned by the initial heap table + (not an absolute limit). */ +#define HEAP (INT_BIT > 16 ? 4194304 : 65536) + +/* Number of contiguous free blocks allowed to build up at the end of + memory before they will be returned to the system. */ +#define FINAL_FREE_BLOCKS 8 + +/* Data structure giving per-block information. */ +typedef union + { + /* Heap information for a busy block. */ + struct + { + /* Zero for a large (multiblock) object, or positive giving the + logarithm to the base two of the fragment size. */ + int type; + union + { + struct + { + __malloc_size_t nfree; /* Free frags in a fragmented block. */ + __malloc_size_t first; /* First free fragment of the block. */ + } frag; + /* For a large object, in its first block, this has the number + of blocks in the object. In the other blocks, this has a + negative number which says how far back the first block is. */ + __malloc_ptrdiff_t size; + } info; + } busy; + /* Heap information for a free block + (that may be the first of a free cluster). */ + struct + { + __malloc_size_t size; /* Size (in blocks) of a free cluster. */ + __malloc_size_t next; /* Index of next free cluster. */ + __malloc_size_t prev; /* Index of previous free cluster. */ + } free; + } malloc_info; + +/* Pointer to first block of the heap. */ +extern char *_heapbase; + +/* Table indexed by block number giving per-block information. */ +extern malloc_info *_heapinfo; + +/* Address to block number and vice versa. */ +#define BLOCK(A) (((char *) (A) - _heapbase) / BLOCKSIZE + 1) +#define ADDRESS(B) ((__ptr_t) (((B) - 1) * BLOCKSIZE + _heapbase)) + +/* Current search index for the heap table. */ +extern __malloc_size_t _heapindex; + +/* Limit of valid info table indices. */ +extern __malloc_size_t _heaplimit; + +/* Doubly linked lists of free fragments. */ +struct list + { + struct list *next; + struct list *prev; + }; + +/* Free list headers for each fragment size. */ +extern struct list _fraghead[]; + +/* List of blocks allocated with `memalign' (or `valloc'). */ +struct alignlist + { + struct alignlist *next; + __ptr_t aligned; /* The address that memaligned returned. */ + __ptr_t exact; /* The address that malloc returned. */ + }; +extern struct alignlist *_aligned_blocks; + +/* Instrumentation. */ +extern __malloc_size_t _chunks_used; +extern __malloc_size_t _bytes_used; +extern __malloc_size_t _chunks_free; +extern __malloc_size_t _bytes_free; + +/* Internal versions of `malloc', `realloc', and `free' + used when these functions need to call each other. + They are the same but don't call the hooks. */ +extern __ptr_t _malloc_internal __P ((__malloc_size_t __size)); +extern __ptr_t _realloc_internal __P ((__ptr_t __ptr, __malloc_size_t __size)); +extern void _free_internal __P ((__ptr_t __ptr)); + +#endif /* _MALLOC_INTERNAL. */ + +/* Given an address in the middle of a malloc'd object, + return the address of the beginning of the object. */ +extern __ptr_t malloc_find_object_address __P ((__ptr_t __ptr)); + +/* Underlying allocation function; successive calls should + return contiguous pieces of memory. */ +extern __ptr_t (*__morecore) __P ((__malloc_ptrdiff_t __size)); + +/* Default value of `__morecore'. */ +extern __ptr_t __default_morecore __P ((__malloc_ptrdiff_t __size)); + +/* If not NULL, this function is called after each time + `__morecore' is called to increase the data size. */ +extern void (*__after_morecore_hook) __P ((void)); + +/* Number of extra blocks to get each time we ask for more core. + This reduces the frequency of calling `(*__morecore)'. */ +extern __malloc_size_t __malloc_extra_blocks; + +/* Nonzero if `malloc' has been called and done its initialization. */ +extern int __malloc_initialized; +/* Function called to initialize malloc data structures. */ +extern int __malloc_initialize __P ((void)); + +/* Hooks for debugging versions. */ +extern void (*__malloc_initialize_hook) __P ((void)); +extern void (*__free_hook) __P ((__ptr_t __ptr)); +extern __ptr_t (*__malloc_hook) __P ((__malloc_size_t __size)); +extern __ptr_t (*__realloc_hook) __P ((__ptr_t __ptr, __malloc_size_t __size)); +extern __ptr_t (*__memalign_hook) __P ((__malloc_size_t __size, + __malloc_size_t __alignment)); + +/* Return values for `mprobe': these are the kinds of inconsistencies that + `mcheck' enables detection of. */ +enum mcheck_status + { + MCHECK_DISABLED = -1, /* Consistency checking is not turned on. */ + MCHECK_OK, /* Block is fine. */ + MCHECK_FREE, /* Block freed twice. */ + MCHECK_HEAD, /* Memory before the block was clobbered. */ + MCHECK_TAIL /* Memory after the block was clobbered. */ + }; + +/* Activate a standard collection of debugging hooks. This must be called + before `malloc' is ever called. ABORTFUNC is called with an error code + (see enum above) when an inconsistency is detected. If ABORTFUNC is + null, the standard function prints on stderr and then calls `abort'. */ +extern int mcheck __P ((void (*__abortfunc) __P ((enum mcheck_status)))); + +/* Check for aberrations in a particular malloc'd block. You must have + called `mcheck' already. These are the same checks that `mcheck' does + when you free or reallocate a block. */ +extern enum mcheck_status mprobe __P ((__ptr_t __ptr)); + +/* Activate a standard collection of tracing hooks. */ +extern void mtrace __P ((void)); +extern void muntrace __P ((void)); + +/* Statistics available to the user. */ +struct mstats + { + __malloc_size_t bytes_total; /* Total size of the heap. */ + __malloc_size_t chunks_used; /* Chunks allocated by the user. */ + __malloc_size_t bytes_used; /* Byte total of user-allocated chunks. */ + __malloc_size_t chunks_free; /* Chunks in the free list. */ + __malloc_size_t bytes_free; /* Byte total of chunks in the free list. */ + }; + +/* Pick up the current statistics. */ +extern struct mstats mstats __P ((void)); + +/* Call WARNFUN with a warning message when memory usage is high. */ +extern void memory_warnings __P ((__ptr_t __start, + void (*__warnfun) __P ((const char *)))); + + +/* Relocating allocator. */ + +/* Allocate SIZE bytes, and store the address in *HANDLEPTR. */ +extern __ptr_t r_alloc __P ((__ptr_t *__handleptr, __malloc_size_t __size)); + +/* Free the storage allocated in HANDLEPTR. */ +extern void r_alloc_free __P ((__ptr_t *__handleptr)); + +/* Adjust the block at HANDLEPTR to be SIZE bytes long. */ +extern __ptr_t r_re_alloc __P ((__ptr_t *__handleptr, __malloc_size_t __size)); + + +#ifdef __cplusplus +} +#endif + +#endif /* malloc.h */ +/* Memory allocator `malloc'. + Copyright 1990, 1991, 1992, 1993, 1994, 1995 Free Software Foundation, Inc. + Written May 1989 by Mike Haertel. + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +This 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 +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with this library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. + + The author may be reached (Email) at the address mike@ai.mit.edu, + or (US mail) as Mike Haertel c/o Free Software Foundation. */ + +#ifndef _MALLOC_INTERNAL +#define _MALLOC_INTERNAL +#include +#endif +#include + +/* How to really get more memory. */ +__ptr_t (*__morecore) __P ((ptrdiff_t __size)) = __default_morecore; + +/* Debugging hook for `malloc'. */ +__ptr_t (*__malloc_hook) __P ((__malloc_size_t __size)); + +/* Pointer to the base of the first block. */ +char *_heapbase; + +/* Block information table. Allocated with align/__free (not malloc/free). */ +malloc_info *_heapinfo; + +/* Number of info entries. */ +static __malloc_size_t heapsize; + +/* Search index in the info table. */ +__malloc_size_t _heapindex; + +/* Limit of valid info table indices. */ +__malloc_size_t _heaplimit; + +/* Free lists for each fragment size. */ +struct list _fraghead[BLOCKLOG]; + +/* Instrumentation. */ +__malloc_size_t _chunks_used; +__malloc_size_t _bytes_used; +__malloc_size_t _chunks_free; +__malloc_size_t _bytes_free; + +/* Are you experienced? */ +int __malloc_initialized; + +__malloc_size_t __malloc_extra_blocks; + +void (*__malloc_initialize_hook) __P ((void)); +void (*__after_morecore_hook) __P ((void)); + + +/* Aligned allocation. */ +static __ptr_t align __P ((__malloc_size_t)); +static __ptr_t +align (size) + __malloc_size_t size; +{ + __ptr_t result; + unsigned long int adj; + + result = (*__morecore) (size); + adj = (unsigned long int) ((unsigned long int) ((char *) result - + (char *) NULL)) % BLOCKSIZE; + if (adj != 0) + { + __ptr_t new; + adj = BLOCKSIZE - adj; + new = (*__morecore) (adj); + result = (char *) result + adj; + } + + if (__after_morecore_hook) + (*__after_morecore_hook) (); + + return result; +} + +/* Get SIZE bytes, if we can get them starting at END. + Return the address of the space we got. + If we cannot get space at END, fail and return -1. */ +static __ptr_t get_contiguous_space __P ((__malloc_ptrdiff_t, __ptr_t)); +static __ptr_t +get_contiguous_space (size, position) + __malloc_ptrdiff_t size; + __ptr_t position; +{ + __ptr_t before; + __ptr_t after; + + before = (*__morecore) (0); + /* If we can tell in advance that the break is at the wrong place, + fail now. */ + if (before != position) + return 0; + + /* Allocate SIZE bytes and get the address of them. */ + after = (*__morecore) (size); + if (!after) + return 0; + + /* It was not contiguous--reject it. */ + if (after != position) + { + (*__morecore) (- size); + return 0; + } + + return after; +} + + +/* This is called when `_heapinfo' and `heapsize' have just + been set to describe a new info table. Set up the table + to describe itself and account for it in the statistics. */ +static void register_heapinfo __P ((void)); +#ifdef __GNUC__ +__inline__ +#endif +static void +register_heapinfo () +{ + __malloc_size_t block, blocks; + + block = BLOCK (_heapinfo); + blocks = BLOCKIFY (heapsize * sizeof (malloc_info)); + + /* Account for the _heapinfo block itself in the statistics. */ + _bytes_used += blocks * BLOCKSIZE; + ++_chunks_used; + + /* Describe the heapinfo block itself in the heapinfo. */ + _heapinfo[block].busy.type = 0; + _heapinfo[block].busy.info.size = blocks; + /* Leave back-pointers for malloc_find_address. */ + while (--blocks > 0) + _heapinfo[block + blocks].busy.info.size = -blocks; +} + +/* Set everything up and remember that we have. */ +int +__malloc_initialize () +{ + if (__malloc_initialized) + return 0; + + if (__malloc_initialize_hook) + (*__malloc_initialize_hook) (); + + heapsize = HEAP / BLOCKSIZE; + _heapinfo = (malloc_info *) align (heapsize * sizeof (malloc_info)); + if (_heapinfo == NULL) + return 0; + memset (_heapinfo, 0, heapsize * sizeof (malloc_info)); + _heapinfo[0].free.size = 0; + _heapinfo[0].free.next = _heapinfo[0].free.prev = 0; + _heapindex = 0; + _heapbase = (char *) _heapinfo; + _heaplimit = BLOCK (_heapbase + heapsize * sizeof (malloc_info)); + + register_heapinfo (); + + __malloc_initialized = 1; + return 1; +} + +static int morecore_recursing; + +/* Get neatly aligned memory, initializing or + growing the heap info table as necessary. */ +static __ptr_t morecore __P ((__malloc_size_t)); +static __ptr_t +morecore (size) + __malloc_size_t size; +{ + __ptr_t result; + malloc_info *newinfo, *oldinfo; + __malloc_size_t newsize; + + if (morecore_recursing) + /* Avoid recursion. The caller will know how to handle a null return. */ + return NULL; + + result = align (size); + if (result == NULL) + return NULL; + + /* Check if we need to grow the info table. */ + if ((__malloc_size_t) BLOCK ((char *) result + size) > heapsize) + { + /* Calculate the new _heapinfo table size. We do not account for the + added blocks in the table itself, as we hope to place them in + existing free space, which is already covered by part of the + existing table. */ + newsize = heapsize; + do + newsize *= 2; + while ((__malloc_size_t) BLOCK ((char *) result + size) > newsize); + + /* We must not reuse existing core for the new info table when called + from realloc in the case of growing a large block, because the + block being grown is momentarily marked as free. In this case + _heaplimit is zero so we know not to reuse space for internal + allocation. */ + if (_heaplimit != 0) + { + /* First try to allocate the new info table in core we already + have, in the usual way using realloc. If realloc cannot + extend it in place or relocate it to existing sufficient core, + we will get called again, and the code above will notice the + `morecore_recursing' flag and return null. */ + int save = errno; /* Don't want to clobber errno with ENOMEM. */ + morecore_recursing = 1; + newinfo = (malloc_info *) _realloc_internal + (_heapinfo, newsize * sizeof (malloc_info)); + morecore_recursing = 0; + if (newinfo == NULL) + errno = save; + else + { + /* We found some space in core, and realloc has put the old + table's blocks on the free list. Now zero the new part + of the table and install the new table location. */ + memset (&newinfo[heapsize], 0, + (newsize - heapsize) * sizeof (malloc_info)); + _heapinfo = newinfo; + heapsize = newsize; + goto got_heap; + } + } + + /* Allocate new space for the malloc info table. */ + while (1) + { + newinfo = (malloc_info *) align (newsize * sizeof (malloc_info)); + + /* Did it fail? */ + if (newinfo == NULL) + { + (*__morecore) (-size); + return NULL; + } + + /* Is it big enough to record status for its own space? + If so, we win. */ + if ((__malloc_size_t) BLOCK ((char *) newinfo + + newsize * sizeof (malloc_info)) + < newsize) + break; + + /* Must try again. First give back most of what we just got. */ + (*__morecore) (- newsize * sizeof (malloc_info)); + newsize *= 2; + } + + /* Copy the old table to the beginning of the new, + and zero the rest of the new table. */ + memcpy (newinfo, _heapinfo, heapsize * sizeof (malloc_info)); + memset (&newinfo[heapsize], 0, + (newsize - heapsize) * sizeof (malloc_info)); + oldinfo = _heapinfo; + _heapinfo = newinfo; + heapsize = newsize; + + register_heapinfo (); + + /* Reset _heaplimit so _free_internal never decides + it can relocate or resize the info table. */ + _heaplimit = 0; + _free_internal (oldinfo); + + /* The new heap limit includes the new table just allocated. */ + _heaplimit = BLOCK ((char *) newinfo + heapsize * sizeof (malloc_info)); + return result; + } + + got_heap: + _heaplimit = BLOCK ((char *) result + size); + return result; +} + +/* Allocate memory from the heap. */ +__ptr_t +_malloc_internal (size) + __malloc_size_t size; +{ + __ptr_t result; + __malloc_size_t block, blocks, lastblocks, start; + register __malloc_size_t i; + struct list *next; + + /* ANSI C allows `malloc (0)' to either return NULL, or to return a + valid address you can realloc and free (though not dereference). + + It turns out that some extant code (sunrpc, at least Ultrix's version) + expects `malloc (0)' to return non-NULL and breaks otherwise. + Be compatible. */ + +#if 0 + if (size == 0) + return NULL; +#endif + + if (size < sizeof (struct list)) + size = sizeof (struct list); + +#ifdef SUNOS_LOCALTIME_BUG + if (size < 16) + size = 16; +#endif + + /* Determine the allocation policy based on the request size. */ + if (size <= BLOCKSIZE / 2) + { + /* Small allocation to receive a fragment of a block. + Determine the logarithm to base two of the fragment size. */ + register __malloc_size_t log = 1; + --size; + while ((size /= 2) != 0) + ++log; + + /* Look in the fragment lists for a + free fragment of the desired size. */ + next = _fraghead[log].next; + if (next != NULL) + { + /* There are free fragments of this size. + Pop a fragment out of the fragment list and return it. + Update the block's nfree and first counters. */ + result = (__ptr_t) next; + next->prev->next = next->next; + if (next->next != NULL) + next->next->prev = next->prev; + block = BLOCK (result); + if (--_heapinfo[block].busy.info.frag.nfree != 0) + _heapinfo[block].busy.info.frag.first = (unsigned long int) + ((unsigned long int) ((char *) next->next - (char *) NULL) + % BLOCKSIZE) >> log; + + /* Update the statistics. */ + ++_chunks_used; + _bytes_used += 1 << log; + --_chunks_free; + _bytes_free -= 1 << log; + } + else + { + /* No free fragments of the desired size, so get a new block + and break it into fragments, returning the first. */ + result = malloc (BLOCKSIZE); + if (result == NULL) + return NULL; + + /* Link all fragments but the first into the free list. */ + next = (struct list *) ((char *) result + (1 << log)); + next->next = NULL; + next->prev = &_fraghead[log]; + _fraghead[log].next = next; + + for (i = 2; i < (__malloc_size_t) (BLOCKSIZE >> log); ++i) + { + next = (struct list *) ((char *) result + (i << log)); + next->next = _fraghead[log].next; + next->prev = &_fraghead[log]; + next->prev->next = next; + next->next->prev = next; + } + + /* Initialize the nfree and first counters for this block. */ + block = BLOCK (result); + _heapinfo[block].busy.type = log; + _heapinfo[block].busy.info.frag.nfree = i - 1; + _heapinfo[block].busy.info.frag.first = i - 1; + + _chunks_free += (BLOCKSIZE >> log) - 1; + _bytes_free += BLOCKSIZE - (1 << log); + _bytes_used -= BLOCKSIZE - (1 << log); + } + } + else + { + /* Large allocation to receive one or more blocks. + Search the free list in a circle starting at the last place visited. + If we loop completely around without finding a large enough + space we will have to get more memory from the system. */ + blocks = BLOCKIFY (size); + start = block = _heapindex; + while (_heapinfo[block].free.size < blocks) + { + block = _heapinfo[block].free.next; + if (block == start) + { + /* Need to get more from the system. Get a little extra. */ + __malloc_size_t wantblocks = blocks + __malloc_extra_blocks; + block = _heapinfo[0].free.prev; + lastblocks = _heapinfo[block].free.size; + /* Check to see if the new core will be contiguous with the + final free block; if so we don't need to get as much. */ + if (_heaplimit != 0 && block + lastblocks == _heaplimit && + /* We can't do this if we will have to make the heap info + table bigger to accomodate the new space. */ + block + wantblocks <= heapsize && + get_contiguous_space ((wantblocks - lastblocks) * BLOCKSIZE, + ADDRESS (block + lastblocks))) + { + /* We got it contiguously. Which block we are extending + (the `final free block' referred to above) might have + changed, if it got combined with a freed info table. */ + block = _heapinfo[0].free.prev; + _heapinfo[block].free.size += (wantblocks - lastblocks); + _bytes_free += (wantblocks - lastblocks) * BLOCKSIZE; + _heaplimit += wantblocks - lastblocks; + continue; + } + result = morecore (wantblocks * BLOCKSIZE); + if (result == NULL) + return NULL; + block = BLOCK (result); + /* Put the new block at the end of the free list. */ + _heapinfo[block].free.size = wantblocks; + _heapinfo[block].free.prev = _heapinfo[0].free.prev; + _heapinfo[block].free.next = 0; + _heapinfo[0].free.prev = block; + _heapinfo[_heapinfo[block].free.prev].free.next = block; + ++_chunks_free; + /* Now loop to use some of that block for this allocation. */ + } + } + + /* At this point we have found a suitable free list entry. + Figure out how to remove what we need from the list. */ + result = ADDRESS (block); + if (_heapinfo[block].free.size > blocks) + { + /* The block we found has a bit left over, + so relink the tail end back into the free list. */ + _heapinfo[block + blocks].free.size + = _heapinfo[block].free.size - blocks; + _heapinfo[block + blocks].free.next + = _heapinfo[block].free.next; + _heapinfo[block + blocks].free.prev + = _heapinfo[block].free.prev; + _heapinfo[_heapinfo[block].free.prev].free.next + = _heapinfo[_heapinfo[block].free.next].free.prev + = _heapindex = block + blocks; + } + else + { + /* The block exactly matches our requirements, + so just remove it from the list. */ + _heapinfo[_heapinfo[block].free.next].free.prev + = _heapinfo[block].free.prev; + _heapinfo[_heapinfo[block].free.prev].free.next + = _heapindex = _heapinfo[block].free.next; + --_chunks_free; + } + + _heapinfo[block].busy.type = 0; + _heapinfo[block].busy.info.size = blocks; + ++_chunks_used; + _bytes_used += blocks * BLOCKSIZE; + _bytes_free -= blocks * BLOCKSIZE; + + /* Mark all the blocks of the object just allocated except for the + first with a negative number so you can find the first block by + adding that adjustment. */ + while (--blocks > 0) + _heapinfo[block + blocks].busy.info.size = -blocks; + } + + return result; +} + +__ptr_t +malloc (size) + __malloc_size_t size; +{ + if (!__malloc_initialized && !__malloc_initialize ()) + return NULL; + + return (__malloc_hook != NULL ? *__malloc_hook : _malloc_internal) (size); +} + +#ifndef _LIBC + +/* On some ANSI C systems, some libc functions call _malloc, _free + and _realloc. Make them use the GNU functions. */ + +__ptr_t +_malloc (size) + __malloc_size_t size; +{ + return malloc (size); +} + +void +_free (ptr) + __ptr_t ptr; +{ + free (ptr); +} + +__ptr_t +_realloc (ptr, size) + __ptr_t ptr; + __malloc_size_t size; +{ + return realloc (ptr, size); +} + +#endif +/* Free a block of memory allocated by `malloc'. + Copyright 1990, 1991, 1992, 1994, 1995 Free Software Foundation, Inc. + Written May 1989 by Mike Haertel. + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +This 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 +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with this library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. + + The author may be reached (Email) at the address mike@ai.mit.edu, + or (US mail) as Mike Haertel c/o Free Software Foundation. */ + +#ifndef _MALLOC_INTERNAL +#define _MALLOC_INTERNAL +#include +#endif + + +/* Cope with systems lacking `memmove'. */ +#ifndef memmove +#if (defined (MEMMOVE_MISSING) || \ + !defined(_LIBC) && !defined(STDC_HEADERS) && !defined(USG)) +#ifdef emacs +#undef __malloc_safe_bcopy +#define __malloc_safe_bcopy safe_bcopy +#endif +/* This function is defined in realloc.c. */ +extern void __malloc_safe_bcopy __P ((__ptr_t, __ptr_t, __malloc_size_t)); +#define memmove(to, from, size) __malloc_safe_bcopy ((from), (to), (size)) +#endif +#endif + + +/* Debugging hook for free. */ +void (*__free_hook) __P ((__ptr_t __ptr)); + +/* List of blocks allocated by memalign. */ +struct alignlist *_aligned_blocks = NULL; + +/* Return memory to the heap. + Like `free' but don't call a __free_hook if there is one. */ +void +_free_internal (ptr) + __ptr_t ptr; +{ + int type; + __malloc_size_t block, blocks; + register __malloc_size_t i; + struct list *prev, *next; + __ptr_t curbrk; + const __malloc_size_t lesscore_threshold + /* Threshold of free space at which we will return some to the system. */ + = FINAL_FREE_BLOCKS + 2 * __malloc_extra_blocks; + + register struct alignlist *l; + + if (ptr == NULL) + return; + + for (l = _aligned_blocks; l != NULL; l = l->next) + if (l->aligned == ptr) + { + l->aligned = NULL; /* Mark the slot in the list as free. */ + ptr = l->exact; + break; + } + + block = BLOCK (ptr); + + type = _heapinfo[block].busy.type; + switch (type) + { + case 0: + /* Get as many statistics as early as we can. */ + --_chunks_used; + _bytes_used -= _heapinfo[block].busy.info.size * BLOCKSIZE; + _bytes_free += _heapinfo[block].busy.info.size * BLOCKSIZE; + + /* Find the free cluster previous to this one in the free list. + Start searching at the last block referenced; this may benefit + programs with locality of allocation. */ + i = _heapindex; + if (i > block) + while (i > block) + i = _heapinfo[i].free.prev; + else + { + do + i = _heapinfo[i].free.next; + while (i > 0 && i < block); + i = _heapinfo[i].free.prev; + } + + /* Determine how to link this block into the free list. */ + if (block == i + _heapinfo[i].free.size) + { + /* Coalesce this block with its predecessor. */ + _heapinfo[i].free.size += _heapinfo[block].busy.info.size; + block = i; + } + else + { + /* Really link this block back into the free list. */ + _heapinfo[block].free.size = _heapinfo[block].busy.info.size; + _heapinfo[block].free.next = _heapinfo[i].free.next; + _heapinfo[block].free.prev = i; + _heapinfo[i].free.next = block; + _heapinfo[_heapinfo[block].free.next].free.prev = block; + ++_chunks_free; + } + + /* Now that the block is linked in, see if we can coalesce it + with its successor (by deleting its successor from the list + and adding in its size). */ + if (block + _heapinfo[block].free.size == _heapinfo[block].free.next) + { + _heapinfo[block].free.size + += _heapinfo[_heapinfo[block].free.next].free.size; + _heapinfo[block].free.next + = _heapinfo[_heapinfo[block].free.next].free.next; + _heapinfo[_heapinfo[block].free.next].free.prev = block; + --_chunks_free; + } + + /* How many trailing free blocks are there now? */ + blocks = _heapinfo[block].free.size; + + /* Where is the current end of accessible core? */ + curbrk = (*__morecore) (0); + + if (_heaplimit != 0 && curbrk == ADDRESS (_heaplimit)) + { + /* The end of the malloc heap is at the end of accessible core. + It's possible that moving _heapinfo will allow us to + return some space to the system. */ + + __malloc_size_t info_block = BLOCK (_heapinfo); + __malloc_size_t info_blocks = _heapinfo[info_block].busy.info.size; + __malloc_size_t prev_block = _heapinfo[block].free.prev; + __malloc_size_t prev_blocks = _heapinfo[prev_block].free.size; + __malloc_size_t next_block = _heapinfo[block].free.next; + __malloc_size_t next_blocks = _heapinfo[next_block].free.size; + + if (/* Win if this block being freed is last in core, the info table + is just before it, the previous free block is just before the + info table, and the two free blocks together form a useful + amount to return to the system. */ + (block + blocks == _heaplimit && + info_block + info_blocks == block && + prev_block != 0 && prev_block + prev_blocks == info_block && + blocks + prev_blocks >= lesscore_threshold) || + /* Nope, not the case. We can also win if this block being + freed is just before the info table, and the table extends + to the end of core or is followed only by a free block, + and the total free space is worth returning to the system. */ + (block + blocks == info_block && + ((info_block + info_blocks == _heaplimit && + blocks >= lesscore_threshold) || + (info_block + info_blocks == next_block && + next_block + next_blocks == _heaplimit && + blocks + next_blocks >= lesscore_threshold))) + ) + { + malloc_info *newinfo; + __malloc_size_t oldlimit = _heaplimit; + + /* Free the old info table, clearing _heaplimit to avoid + recursion into this code. We don't want to return the + table's blocks to the system before we have copied them to + the new location. */ + _heaplimit = 0; + _free_internal (_heapinfo); + _heaplimit = oldlimit; + + /* Tell malloc to search from the beginning of the heap for + free blocks, so it doesn't reuse the ones just freed. */ + _heapindex = 0; + + /* Allocate new space for the info table and move its data. */ + newinfo = (malloc_info *) _malloc_internal (info_blocks + * BLOCKSIZE); + memmove (newinfo, _heapinfo, info_blocks * BLOCKSIZE); + _heapinfo = newinfo; + + /* We should now have coalesced the free block with the + blocks freed from the old info table. Examine the entire + trailing free block to decide below whether to return some + to the system. */ + block = _heapinfo[0].free.prev; + blocks = _heapinfo[block].free.size; + } + + /* Now see if we can return stuff to the system. */ + if (block + blocks == _heaplimit && blocks >= lesscore_threshold) + { + register __malloc_size_t bytes = blocks * BLOCKSIZE; + _heaplimit -= blocks; + (*__morecore) (-bytes); + _heapinfo[_heapinfo[block].free.prev].free.next + = _heapinfo[block].free.next; + _heapinfo[_heapinfo[block].free.next].free.prev + = _heapinfo[block].free.prev; + block = _heapinfo[block].free.prev; + --_chunks_free; + _bytes_free -= bytes; + } + } + + /* Set the next search to begin at this block. */ + _heapindex = block; + break; + + default: + /* Do some of the statistics. */ + --_chunks_used; + _bytes_used -= 1 << type; + ++_chunks_free; + _bytes_free += 1 << type; + + /* Get the address of the first free fragment in this block. */ + prev = (struct list *) ((char *) ADDRESS (block) + + (_heapinfo[block].busy.info.frag.first << type)); + + if (_heapinfo[block].busy.info.frag.nfree == (BLOCKSIZE >> type) - 1) + { + /* If all fragments of this block are free, remove them + from the fragment list and free the whole block. */ + next = prev; + for (i = 1; i < (__malloc_size_t) (BLOCKSIZE >> type); ++i) + next = next->next; + prev->prev->next = next; + if (next != NULL) + next->prev = prev->prev; + _heapinfo[block].busy.type = 0; + _heapinfo[block].busy.info.size = 1; + + /* Keep the statistics accurate. */ + ++_chunks_used; + _bytes_used += BLOCKSIZE; + _chunks_free -= BLOCKSIZE >> type; + _bytes_free -= BLOCKSIZE; + + free (ADDRESS (block)); + } + else if (_heapinfo[block].busy.info.frag.nfree != 0) + { + /* If some fragments of this block are free, link this + fragment into the fragment list after the first free + fragment of this block. */ + next = (struct list *) ptr; + next->next = prev->next; + next->prev = prev; + prev->next = next; + if (next->next != NULL) + next->next->prev = next; + ++_heapinfo[block].busy.info.frag.nfree; + } + else + { + /* No fragments of this block are free, so link this + fragment into the fragment list and announce that + it is the first free fragment of this block. */ + prev = (struct list *) ptr; + _heapinfo[block].busy.info.frag.nfree = 1; + _heapinfo[block].busy.info.frag.first = (unsigned long int) + ((unsigned long int) ((char *) ptr - (char *) NULL) + % BLOCKSIZE >> type); + prev->next = _fraghead[type].next; + prev->prev = &_fraghead[type]; + prev->prev->next = prev; + if (prev->next != NULL) + prev->next->prev = prev; + } + break; + } +} + +/* Return memory to the heap. */ +void +free (ptr) + __ptr_t ptr; +{ + if (__free_hook != NULL) + (*__free_hook) (ptr); + else + _free_internal (ptr); +} + +/* Define the `cfree' alias for `free'. */ +#ifdef weak_alias +weak_alias (free, cfree) +#else +void +cfree (ptr) + __ptr_t ptr; +{ + free (ptr); +} +#endif +/* Change the size of a block allocated by `malloc'. + Copyright 1990, 1991, 1992, 1993, 1994, 1995 Free Software Foundation, Inc. + Written May 1989 by Mike Haertel. + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +This 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 +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with this library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. + + The author may be reached (Email) at the address mike@ai.mit.edu, + or (US mail) as Mike Haertel c/o Free Software Foundation. */ + +#ifndef _MALLOC_INTERNAL +#define _MALLOC_INTERNAL +#include +#endif + + + +/* Cope with systems lacking `memmove'. */ +#if (defined (MEMMOVE_MISSING) || \ + !defined(_LIBC) && !defined(STDC_HEADERS) && !defined(USG)) + +#ifdef emacs +#undef __malloc_safe_bcopy +#define __malloc_safe_bcopy safe_bcopy +#else + +/* Snarfed directly from Emacs src/dispnew.c: + XXX Should use system bcopy if it handles overlap. */ + +/* Like bcopy except never gets confused by overlap. */ + +void +__malloc_safe_bcopy (afrom, ato, size) + __ptr_t afrom; + __ptr_t ato; + __malloc_size_t size; +{ + char *from = afrom, *to = ato; + + if (size <= 0 || from == to) + return; + + /* If the source and destination don't overlap, then bcopy can + handle it. If they do overlap, but the destination is lower in + memory than the source, we'll assume bcopy can handle that. */ + if (to < from || from + size <= to) + bcopy (from, to, size); + + /* Otherwise, we'll copy from the end. */ + else + { + register char *endf = from + size; + register char *endt = to + size; + + /* If TO - FROM is large, then we should break the copy into + nonoverlapping chunks of TO - FROM bytes each. However, if + TO - FROM is small, then the bcopy function call overhead + makes this not worth it. The crossover point could be about + anywhere. Since I don't think the obvious copy loop is too + bad, I'm trying to err in its favor. */ + if (to - from < 64) + { + do + *--endt = *--endf; + while (endf != from); + } + else + { + for (;;) + { + endt -= (to - from); + endf -= (to - from); + + if (endt < to) + break; + + bcopy (endf, endt, to - from); + } + + /* If SIZE wasn't a multiple of TO - FROM, there will be a + little left over. The amount left over is + (endt + (to - from)) - to, which is endt - from. */ + bcopy (from, to, endt - from); + } + } +} +#endif /* emacs */ + +#ifndef memmove +extern void __malloc_safe_bcopy __P ((__ptr_t, __ptr_t, __malloc_size_t)); +#define memmove(to, from, size) __malloc_safe_bcopy ((from), (to), (size)) +#endif + +#endif + + +#define min(A, B) ((A) < (B) ? (A) : (B)) + +/* Debugging hook for realloc. */ +__ptr_t (*__realloc_hook) __P ((__ptr_t __ptr, __malloc_size_t __size)); + +/* Resize the given region to the new size, returning a pointer + to the (possibly moved) region. This is optimized for speed; + some benchmarks seem to indicate that greater compactness is + achieved by unconditionally allocating and copying to a + new region. This module has incestuous knowledge of the + internals of both free and malloc. */ +__ptr_t +_realloc_internal (ptr, size) + __ptr_t ptr; + __malloc_size_t size; +{ + __ptr_t result; + int type; + __malloc_size_t block, blocks, oldlimit; + + if (size == 0) + { + _free_internal (ptr); + return _malloc_internal (0); + } + else if (ptr == NULL) + return _malloc_internal (size); + + block = BLOCK (ptr); + + type = _heapinfo[block].busy.type; + switch (type) + { + case 0: + /* Maybe reallocate a large block to a small fragment. */ + if (size <= BLOCKSIZE / 2) + { + result = _malloc_internal (size); + if (result != NULL) + { + memcpy (result, ptr, size); + _free_internal (ptr); + return result; + } + } + + /* The new size is a large allocation as well; + see if we can hold it in place. */ + blocks = BLOCKIFY (size); + if (blocks < _heapinfo[block].busy.info.size) + { + /* The new size is smaller; return + excess memory to the free list. */ + _heapinfo[block + blocks].busy.type = 0; + _heapinfo[block + blocks].busy.info.size + = _heapinfo[block].busy.info.size - blocks; + _heapinfo[block].busy.info.size = blocks; + /* We have just created a new chunk by splitting a chunk in two. + Now we will free this chunk; increment the statistics counter + so it doesn't become wrong when _free_internal decrements it. */ + ++_chunks_used; + _free_internal (ADDRESS (block + blocks)); + result = ptr; + } + else if (blocks == _heapinfo[block].busy.info.size) + /* No size change necessary. */ + result = ptr; + else + { + /* Won't fit, so allocate a new region that will. + Free the old region first in case there is sufficient + adjacent free space to grow without moving. */ + blocks = _heapinfo[block].busy.info.size; + /* Prevent free from actually returning memory to the system. */ + oldlimit = _heaplimit; + _heaplimit = 0; + _free_internal (ptr); + result = _malloc_internal (size); + if (_heaplimit == 0) + _heaplimit = oldlimit; + if (result == NULL) + { + /* Now we're really in trouble. We have to unfree + the thing we just freed. Unfortunately it might + have been coalesced with its neighbors. */ + if (_heapindex == block) + (void) _malloc_internal (blocks * BLOCKSIZE); + else + { + __ptr_t previous + = _malloc_internal ((block - _heapindex) * BLOCKSIZE); + (void) _malloc_internal (blocks * BLOCKSIZE); + _free_internal (previous); + } + return NULL; + } + if (ptr != result) + memmove (result, ptr, blocks * BLOCKSIZE); + } + break; + + default: + /* Old size is a fragment; type is logarithm + to base two of the fragment size. */ + if (size > (__malloc_size_t) (1 << (type - 1)) && + size <= (__malloc_size_t) (1 << type)) + /* The new size is the same kind of fragment. */ + result = ptr; + else + { + /* The new size is different; allocate a new space, + and copy the lesser of the new size and the old. */ + result = _malloc_internal (size); + if (result == NULL) + return NULL; + memcpy (result, ptr, min (size, (__malloc_size_t) 1 << type)); + _free_internal (ptr); + } + break; + } + + return result; +} + +__ptr_t +realloc (ptr, size) + __ptr_t ptr; + __malloc_size_t size; +{ + if (!__malloc_initialized && !__malloc_initialize ()) + return NULL; + + return (__realloc_hook != NULL ? *__realloc_hook : _realloc_internal) + (ptr, size); +} +/* Copyright (C) 1991, 1992, 1994 Free Software Foundation, Inc. + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +This 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 +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with this library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. + + The author may be reached (Email) at the address mike@ai.mit.edu, + or (US mail) as Mike Haertel c/o Free Software Foundation. */ + +#ifndef _MALLOC_INTERNAL +#define _MALLOC_INTERNAL +#include +#endif + +/* Allocate an array of NMEMB elements each SIZE bytes long. + The entire array is initialized to zeros. */ +__ptr_t +calloc (nmemb, size) + register __malloc_size_t nmemb; + register __malloc_size_t size; +{ + register __ptr_t result = malloc (nmemb * size); + + if (result != NULL) + (void) memset (result, 0, nmemb * size); + + return result; +} +/* Copyright (C) 1991, 1992, 1993, 1994, 1995 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C 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 C 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. + +You should have received a copy of the GNU General Public License +along with the GNU C Library; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#ifndef _MALLOC_INTERNAL +#define _MALLOC_INTERNAL +#include +#endif + +#ifndef __GNU_LIBRARY__ +#define __sbrk sbrk +#endif + +#ifdef __GNU_LIBRARY__ +/* It is best not to declare this and cast its result on foreign operating + systems with potentially hostile include files. */ + +#include +extern __ptr_t __sbrk __P ((ptrdiff_t increment)); +#endif + +#ifndef NULL +#define NULL 0 +#endif + +/* Allocate INCREMENT more bytes of data space, + and return the start of data space, or NULL on errors. + If INCREMENT is negative, shrink data space. */ +__ptr_t +__default_morecore (increment) + __malloc_ptrdiff_t increment; +{ + __ptr_t result = (__ptr_t) __sbrk (increment); + if (result == (__ptr_t) -1) + return NULL; + return result; +} +/* Copyright (C) 1991, 92, 93, 94, 95, 96 Free Software Foundation, Inc. + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +This 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 +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with this library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#ifndef _MALLOC_INTERNAL +#define _MALLOC_INTERNAL +#include +#endif + +#if __DJGPP__ - 0 == 1 + +/* There is some problem with memalign in DJGPP v1 and we are supposed + to omit it. Noone told me why, they just told me to do it. */ + +#else + +__ptr_t (*__memalign_hook) __P ((size_t __size, size_t __alignment)); + +__ptr_t +memalign (alignment, size) + __malloc_size_t alignment; + __malloc_size_t size; +{ + __ptr_t result; + unsigned long int adj, lastadj; + + if (__memalign_hook) + return (*__memalign_hook) (alignment, size); + + /* Allocate a block with enough extra space to pad the block with up to + (ALIGNMENT - 1) bytes if necessary. */ + result = malloc (size + alignment - 1); + if (result == NULL) + return NULL; + + /* Figure out how much we will need to pad this particular block + to achieve the required alignment. */ + adj = (unsigned long int) ((char *) result - (char *) NULL) % alignment; + + do + { + /* Reallocate the block with only as much excess as it needs. */ + free (result); + result = malloc (adj + size); + if (result == NULL) /* Impossible unless interrupted. */ + return NULL; + + lastadj = adj; + adj = (unsigned long int) ((char *) result - (char *) NULL) % alignment; + /* It's conceivable we might have been so unlucky as to get a + different block with weaker alignment. If so, this block is too + short to contain SIZE after alignment correction. So we must + try again and get another block, slightly larger. */ + } while (adj > lastadj); + + if (adj != 0) + { + /* Record this block in the list of aligned blocks, so that `free' + can identify the pointer it is passed, which will be in the middle + of an allocated block. */ + + struct alignlist *l; + for (l = _aligned_blocks; l != NULL; l = l->next) + if (l->aligned == NULL) + /* This slot is free. Use it. */ + break; + if (l == NULL) + { + l = (struct alignlist *) malloc (sizeof (struct alignlist)); + if (l == NULL) + { + free (result); + return NULL; + } + l->next = _aligned_blocks; + _aligned_blocks = l; + } + l->exact = result; + result = l->aligned = (char *) result + alignment - adj; + } + + return result; +} + +#endif /* Not DJGPP v1 */ diff --git a/lib/malloc/malloc.c b/lib/malloc/malloc.c index 78fb640..88217db 100644 --- a/lib/malloc/malloc.c +++ b/lib/malloc/malloc.c @@ -58,34 +58,27 @@ what you give them. Help stamp out software-hoarding! */ #endif */ +/* Define this to have free() write 0xcf into memory as it's freed, to + uncover callers that refer to freed memory. */ +/* SCO 3.2v4 getcwd and possibly other libc routines fail with MEMSCRAMBLE */ +#if !defined (NO_MEMSCRAMBLE) +# define MEMSCRAMBLE +#endif + #if defined (emacs) || defined (HAVE_CONFIG_H) -# include "config.h" +# include #endif /* emacs */ -#if !defined (USG) -# if defined (HPUX) || defined (UnixPC) || defined (Xenix) -# define USG -# endif /* HPUX || UnixPC || Xenix */ -#endif /* !USG */ +#if defined (HAVE_UNISTD_H) +# include +#endif /* Determine which kind of system this is. */ #include #include -#if !defined (USG) && !defined (USGr4) -# ifndef SIGTSTP -# ifndef USG -# define USG -# endif /* !USG */ -# else /* SIGTSTP */ -# ifdef SIGIO -# define BSD4_2 -# endif /* SIGIO */ -# endif /* SIGTSTP */ -#endif /* !USG && !USGr4 */ - -#ifndef BSD4_2 - /* Define getpagesize () if the system does not. */ +/* Define getpagesize () if the system does not. */ +#ifndef HAVE_GETPAGESIZE # include "getpagesize.h" #endif @@ -100,6 +93,10 @@ what you give them. Help stamp out software-hoarding! */ # undef HAVE_RESOURCE #endif +#if !defined (NULL) +# define NULL 0 +#endif + #define start_of_data() &etext #define ISALLOC ((char) 0xf7) /* magic byte that implies allocation */ @@ -111,12 +108,11 @@ what you give them. Help stamp out software-hoarding! */ beginning of the block. */ extern char etext; -#if !defined (NO_SBRK_DECL) +#if !defined (SBRK_DECLARED) extern char *sbrk (); -#endif /* !NO_SBRK_DECL */ +#endif /* !SBRK_DECLARED */ /* These two are for user programs to look at, when they are interested. */ - unsigned int malloc_sbrk_used; /* amount of data space used now */ unsigned int malloc_sbrk_unused; /* amount more we can have */ @@ -143,7 +139,7 @@ struct mhead { /* Remainder are valid only when block is allocated */ unsigned short mh_size; /* size, if < 0x10000 */ #ifdef rcheck - unsigned mh_nbytes; /* number of bytes allocated */ + unsigned int mh_nbytes; /* number of bytes allocated */ int mh_magic4; /* should be == MAGIC4 */ #endif /* rcheck */ }; @@ -241,7 +237,7 @@ malloc_usable_size (mem) return blocksize - sizeof (struct mhead) - EXTRA; } - + static void morecore (nu) /* ask system for more memory */ register int nu; /* size index to get more of */ @@ -249,11 +245,19 @@ morecore (nu) /* ask system for more memory */ register char *cp; register int nblks; register unsigned int siz; - int oldmask; -#if defined (BSD4_2) + /* Block all signals in case we are executed from a signal handler. */ +#if defined (HAVE_BSD_SIGNALS) + int oldmask; oldmask = sigsetmask (-1); -#endif /* BSD4_2 */ +#else +# if defined (HAVE_POSIX_SIGNALS) + sigset_t set, oset; + sigfillset (&set); + sigemptyset (&oset); + sigprocmask (SIG_BLOCK, &set, &oset); +# endif /* HAVE_POSIX_SIGNALS */ +#endif /* HAVE_BSD_SIGNALS */ if (!data_space_start) { @@ -331,9 +335,13 @@ morecore (nu) /* ask system for more memory */ } CHAIN ((struct mhead *) cp) = 0; -#if defined (BSD4_2) +#if defined (HAVE_BSD_SIGNALS) sigsetmask (oldmask); -#endif /* BSD4_2 */ +#else +# if defined (HAVE_POSIX_SIGNALS) + sigprocmask (SIG_SETMASK, &oset, (sigset_t *)NULL); +# endif +#endif /* HAVE_BSD_SIGNALS */ } static void @@ -373,10 +381,26 @@ getpool () cp += 8 << nu; } } - + +#if defined (MEMSCRAMBLE) || !defined (NO_CALLOC) +static char * +zmemset (s, c, n) + char *s; + int c; + register int n; +{ + register char *sp; + + sp = s; + while (--n >= 0) + *sp++ = c; + return (s); +} +#endif /* MEMSCRAMBLE || !NO_CALLOC */ + char * malloc (n) /* get a block */ - unsigned n; + unsigned int n; { register struct mhead *p; register unsigned int nbytes; @@ -436,6 +460,9 @@ malloc (n) /* get a block */ #else /* not rcheck */ p -> mh_size = n; #endif /* not rcheck */ +#ifdef MEMSCRAMBLE + zmemset ((char *)(p + 1), 0xdf, n); /* scramble previous contents */ +#endif #ifdef MSTATS nmalloc[nunits]++; nmal++; @@ -474,7 +501,7 @@ free (mem) if (p -> mh_alloc == ISFREE) botch ("free: Called with already freed block argument\n"); else - botch ("free: Called with bad argument\n"); + botch ("free: Called with unallocated block argument\n"); } ASSERT (p -> mh_magic4 == MAGIC4); @@ -483,6 +510,18 @@ free (mem) ASSERT (*ap++ == MAGIC1); ASSERT (*ap == MAGIC1); #endif /* rcheck */ } +#ifdef MEMSCRAMBLE + { + register int n; + +#ifdef rcheck + n = p->mh_nbytes; +#else /* not rcheck */ + n = p->mh_size; +#endif /* not rcheck */ + zmemset (mem, 0xcf, n); + } +#endif { register int nunits = p -> mh_index; @@ -506,7 +545,7 @@ free (mem) char * realloc (mem, n) char *mem; - register unsigned n; + register unsigned int n; { register struct mhead *p; register unsigned int tocopy; @@ -565,12 +604,14 @@ realloc (mem, n) char * memalign (alignment, size) - unsigned alignment, size; + unsigned int alignment, size; { - register char *ptr = malloc (size + alignment); + register char *ptr; register char *aligned; register struct mhead *p; + ptr = malloc (size + alignment); + if (ptr == 0) return 0; /* If entire block has the desired alignment, just accept it. */ @@ -587,16 +628,44 @@ memalign (alignment, size) return aligned; } -#if !defined (HPUX) && !defined (Multimax) && !defined (Multimax32k) +#if !defined (HPUX) /* This runs into trouble with getpagesize on HPUX, and Multimax machines. Patching out seems cleaner than the ugly fix needed. */ +#if defined (__STDC__) +void * +#else char * +#endif valloc (size) + size_t size; { return memalign (getpagesize (), size); } -#endif /* !HPUX && !Multimax && !Multimax32k */ - +#endif /* !HPUX */ + +#ifndef NO_CALLOC +char * +calloc (n, s) + size_t n, s; +{ + size_t total; + char *result; + + total = n * s; + result = malloc (total); + if (result) + zmemset (result, 0, total); + return result; +} + +void +cfree (p) + char *p; +{ + free (p); +} +#endif /* !NO_CALLOC */ + #ifdef MSTATS /* Return statistics describing allocation of blocks of size 2**n. */ @@ -633,7 +702,7 @@ malloc_stats (size) return v; } #endif /* MSTATS */ - + /* * This function returns the total number of bytes that the process * will be allowed to allocate via the sbrk(2) system call. On diff --git a/lib/malloc/stub.c b/lib/malloc/stub.c new file mode 100644 index 0000000..d297c65 --- /dev/null +++ b/lib/malloc/stub.c @@ -0,0 +1,4 @@ +void +bash_malloc_stub() +{ +} diff --git a/lib/malloc/xmalloc.c b/lib/malloc/xmalloc.c index 4f6dc76..4160651 100644 --- a/lib/malloc/xmalloc.c +++ b/lib/malloc/xmalloc.c @@ -19,8 +19,10 @@ along with Readline; see the file COPYING. If not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ -#if defined (ALREADY_HAVE_XMALLOC) -#else +#if defined (HAVE_CONFIG_H) +#include +#endif + #include #if defined (HAVE_STDLIB_H) @@ -44,9 +46,10 @@ char * xmalloc (bytes) int bytes; { - char *temp = (char *)malloc (bytes); + char *temp; - if (!temp) + temp = (char *)malloc (bytes); + if (temp == 0) memory_error_and_abort ("xmalloc"); return (temp); } @@ -58,12 +61,9 @@ xrealloc (pointer, bytes) { char *temp; - if (!pointer) - temp = (char *)malloc (bytes); - else - temp = (char *)realloc (pointer, bytes); + temp = pointer ? (char *)realloc (pointer, bytes) : (char *)malloc (bytes); - if (!temp) + if (temp == 0) memory_error_and_abort ("xrealloc"); return (temp); } @@ -72,7 +72,16 @@ static void memory_error_and_abort (fname) char *fname; { - fprintf (stderr, "%s: Out of virtual memory!\n", fname); - abort (); + fprintf (stderr, "%s: out of virtual memory\n", fname); + exit (2); +} + +/* Use this as the function to call when adding unwind protects so we + don't need to know what free() returns. */ +void +xfree (string) + char *string; +{ + if (string) + free (string); } -#endif /* !ALREADY_HAVE_XMALLOC */ diff --git a/lib/malloclib/Makefile b/lib/malloclib/Makefile deleted file mode 100644 index 7a449c3..0000000 --- a/lib/malloclib/Makefile +++ /dev/null @@ -1,53 +0,0 @@ -# Copyright (C) 1991 Free Software Foundation, Inc. -# This file is part of the GNU C Library. - -# The GNU C Library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Library General Public License -# as published by the Free Software Foundation; either version 2 of -# the License, or (at your option) any later version. - -# The GNU C 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 -# Library General Public License for more details. - -# You should have received a copy of the GNU Library General Public -# License along with the GNU C Library; see the file COPYING.LIB. If -# not, write to the Free Software Foundation, Inc., 675 Mass Ave, -# Cambridge, MA 02139, USA. - -# Makefile for standalone distribution of malloc. - -srcdir = . -VPATH = .:$(srcdir) - -all: libmalloc.a - -sources = calloc.c cfree.c free.c malloc.c mcheck.c morecore.c \ - memalign.c mstats.c mtrace.c realloc.c valloc.c -objects = calloc.o cfree.o free.o malloc.o mcheck.o morecore.o \ - memalign.o mstats.o mtrace.o realloc.o valloc.o -headers = malloc.h getpagesize.h - -libmalloc.a: $(objects) - ar crv $@ $(objects) - ranlib $@ - -.c.o: - $(CC) $(CFLAGS) $(CPPFLAGS) -I. -c $< $(OUTPUT_OPTION) - -.PHONY: clean realclean malloc-clean malloc-realclean -clean malloc-clean: - -rm -f libmalloc.a $(objects) core -realclean malloc-realclean: clean - -rm -f TAGS tags *~ - -calloc.o: malloc.h -free.o: malloc.h -malloc.o: malloc.h -mcheck.o: malloc.h -memalign.o: malloc.h -mstats.o: malloc.h -mtrace.o: malloc.h -realloc.o: malloc.h -valloc.o: malloc.h getpagesize.h diff --git a/lib/malloclib/alloca.c b/lib/malloclib/alloca.c deleted file mode 100644 index 918d023..0000000 --- a/lib/malloclib/alloca.c +++ /dev/null @@ -1,189 +0,0 @@ -/* alloca -- (mostly) portable public-domain implementation -- D A Gwyn - - last edit: 86/05/30 rms - include config.h, since on VMS it renames some symbols. - Use xmalloc instead of malloc. - - This implementation of the PWB library alloca() function, - which is used to allocate space off the run-time stack so - that it is automatically reclaimed upon procedure exit, - was inspired by discussions with J. Q. Johnson of Cornell. - - It should work under any C implementation that uses an - actual procedure stack (as opposed to a linked list of - frames). There are some preprocessor constants that can - be defined when compiling for your specific system, for - improved efficiency; however, the defaults should be okay. - - The general concept of this implementation is to keep - track of all alloca()-allocated blocks, and reclaim any - that are found to be deeper in the stack than the current - invocation. This heuristic does not reclaim storage as - soon as it becomes invalid, but it will do so eventually. - - As a special case, alloca(0) reclaims storage without - allocating any. It is a good idea to use alloca(0) in - your main control loop, etc. to force garbage collection. -*/ -#ifndef lint -static char SCCSid[] = "@(#)alloca.c 1.1"; /* for the "what" utility */ -#endif - -#ifdef emacs -#include "config.h" -#ifdef static -/* actually, only want this if static is defined as "" - -- this is for usg, in which emacs must undefine static - in order to make unexec workable - */ -#ifndef STACK_DIRECTION -you -lose --- must know STACK_DIRECTION at compile-time -#endif /* STACK_DIRECTION undefined */ -#endif /* static */ -#endif /* emacs */ - -#ifdef X3J11 -typedef void *pointer; /* generic pointer type */ -#else -typedef char *pointer; /* generic pointer type */ -#endif /* X3J11 */ - -#define NULL 0 /* null pointer constant */ - -extern void free(); -extern pointer xmalloc(); - -/* - Define STACK_DIRECTION if you know the direction of stack - growth for your system; otherwise it will be automatically - deduced at run-time. - - STACK_DIRECTION > 0 => grows toward higher addresses - STACK_DIRECTION < 0 => grows toward lower addresses - STACK_DIRECTION = 0 => direction of growth unknown -*/ - -#ifndef STACK_DIRECTION -#define STACK_DIRECTION 0 /* direction unknown */ -#endif - -#if STACK_DIRECTION != 0 - -#define STACK_DIR STACK_DIRECTION /* known at compile-time */ - -#else /* STACK_DIRECTION == 0; need run-time code */ - -static int stack_dir; /* 1 or -1 once known */ -#define STACK_DIR stack_dir - -static void -find_stack_direction (/* void */) -{ - static char *addr = NULL; /* address of first - `dummy', once known */ - auto char dummy; /* to get stack address */ - - if (addr == NULL) - { /* initial entry */ - addr = &dummy; - - find_stack_direction (); /* recurse once */ - } - else /* second entry */ - if (&dummy > addr) - stack_dir = 1; /* stack grew upward */ - else - stack_dir = -1; /* stack grew downward */ -} - -#endif /* STACK_DIRECTION == 0 */ - -/* - An "alloca header" is used to: - (a) chain together all alloca()ed blocks; - (b) keep track of stack depth. - - It is very important that sizeof(header) agree with malloc() - alignment chunk size. The following default should work okay. -*/ - -#ifndef ALIGN_SIZE -#define ALIGN_SIZE sizeof(double) -#endif - -typedef union hdr -{ - char align[ALIGN_SIZE]; /* to force sizeof(header) */ - struct - { - union hdr *next; /* for chaining headers */ - char *deep; /* for stack depth measure */ - } h; -} header; - -/* - alloca( size ) returns a pointer to at least `size' bytes of - storage which will be automatically reclaimed upon exit from - the procedure that called alloca(). Originally, this space - was supposed to be taken from the current stack frame of the - caller, but that method cannot be made to work for some - implementations of C, for example under Gould's UTX/32. -*/ - -static header *last_alloca_header = NULL; /* -> last alloca header */ - -pointer -alloca (size) /* returns pointer to storage */ - unsigned size; /* # bytes to allocate */ -{ - auto char probe; /* probes stack depth: */ - register char *depth = &probe; - -#if STACK_DIRECTION == 0 - if (STACK_DIR == 0) /* unknown growth direction */ - find_stack_direction (); -#endif - - /* Reclaim garbage, defined as all alloca()ed storage that - was allocated from deeper in the stack than currently. */ - { - register header *hp; /* traverses linked list */ - - for (hp = last_alloca_header; hp != NULL;) - if (STACK_DIR > 0 && hp->h.deep > depth - || STACK_DIR < 0 && hp->h.deep < depth) - { - register header *np = hp->h.next; - - free ((pointer) hp); /* collect garbage */ - - hp = np; /* -> next header */ - } - else - break; /* rest are not deeper */ - - last_alloca_header = hp; /* -> last valid storage */ - } - - if (size == 0) - return NULL; /* no allocation required */ - - /* Allocate combined header + user data storage. */ - - { - register pointer new = xmalloc (sizeof (header) + size); - /* address of header */ - - ((header *)new)->h.next = last_alloca_header; - ((header *)new)->h.deep = depth; - - last_alloca_header = (header *)new; - - /* User storage begins just after header. */ - - return (pointer)((char *)new + sizeof(header)); - } -} - diff --git a/lib/malloclib/calloc.c b/lib/malloclib/calloc.c deleted file mode 100644 index f870e94..0000000 --- a/lib/malloclib/calloc.c +++ /dev/null @@ -1,39 +0,0 @@ -/* Copyright (C) 1991, 1992 Free Software Foundation, Inc. - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Library General Public License as -published by the Free Software Foundation; either version 2 of the -License, or (at your option) any later version. - -This 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 -Library General Public License for more details. - -You should have received a copy of the GNU Library General Public -License along with this library; see the file COPYING.LIB. If -not, write to the Free Software Foundation, Inc., 675 Mass Ave, -Cambridge, MA 02139, USA. - - The author may be reached (Email) at the address mike@ai.mit.edu, - or (US mail) as Mike Haertel c/o Free Software Foundation. */ - -#ifndef _MALLOC_INTERNAL -#define _MALLOC_INTERNAL -#include -#endif - -/* Allocate an array of NMEMB elements each SIZE bytes long. - The entire array is initialized to zeros. */ -__ptr_t -calloc (nmemb, size) - register size_t nmemb; - register size_t size; -{ - register __ptr_t result = malloc (nmemb * size); - - if (result != NULL) - (void) memset (result, 0, nmemb * size); - - return result; -} diff --git a/lib/malloclib/cfree.c b/lib/malloclib/cfree.c deleted file mode 100644 index adc1ff6..0000000 --- a/lib/malloclib/cfree.c +++ /dev/null @@ -1,43 +0,0 @@ -/* Copyright (C) 1991, 1993 Free Software Foundation, Inc. -This file is part of the GNU C Library. - -The GNU C Library is free software; you can redistribute it and/or -modify it under the terms of the GNU Library General Public License as -published by the Free Software Foundation; either version 2 of the -License, or (at your option) any later version. - -The GNU C 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 -Library General Public License for more details. - -You should have received a copy of the GNU Library General Public -License along with the GNU C Library; see the file COPYING.LIB. If -not, write to the Free Software Foundation, Inc., 675 Mass Ave, -Cambridge, MA 02139, USA. */ - -#ifndef _MALLOC_INTERNAL -#define _MALLOC_INTERNAL -#include -#endif - -#undef cfree - -#ifdef _LIBC - -#include -#include - -function_alias(cfree, free, void, (ptr), - DEFUN(cfree, (ptr), PTR ptr)) - -#else - -void -cfree (ptr) - __ptr_t ptr; -{ - free (ptr); -} - -#endif diff --git a/lib/malloclib/free.c b/lib/malloclib/free.c deleted file mode 100644 index db97fcb..0000000 --- a/lib/malloclib/free.c +++ /dev/null @@ -1,212 +0,0 @@ -/* Free a block of memory allocated by `malloc'. - Copyright 1990, 1991, 1992 Free Software Foundation - Written May 1989 by Mike Haertel. - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Library General Public License as -published by the Free Software Foundation; either version 2 of the -License, or (at your option) any later version. - -This 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 -Library General Public License for more details. - -You should have received a copy of the GNU Library General Public -License along with this library; see the file COPYING.LIB. If -not, write to the Free Software Foundation, Inc., 675 Mass Ave, -Cambridge, MA 02139, USA. - - The author may be reached (Email) at the address mike@ai.mit.edu, - or (US mail) as Mike Haertel c/o Free Software Foundation. */ - -#ifndef _MALLOC_INTERNAL -#define _MALLOC_INTERNAL -#include -#endif - -/* Debugging hook for free. */ -void (*__free_hook) __P ((__ptr_t __ptr)); - -/* List of blocks allocated by memalign. */ -struct alignlist *_aligned_blocks = NULL; - -/* Return memory to the heap. - Like `free' but don't call a __free_hook if there is one. */ -void -_free_internal (ptr) - __ptr_t ptr; -{ - int type; - size_t block, blocks; - register size_t i; - struct list *prev, *next; - - block = BLOCK (ptr); - - type = _heapinfo[block].busy.type; - switch (type) - { - case 0: - /* Get as many statistics as early as we can. */ - --_chunks_used; - _bytes_used -= _heapinfo[block].busy.info.size * BLOCKSIZE; - _bytes_free += _heapinfo[block].busy.info.size * BLOCKSIZE; - - /* Find the free cluster previous to this one in the free list. - Start searching at the last block referenced; this may benefit - programs with locality of allocation. */ - i = _heapindex; - if (i > block) - while (i > block) - i = _heapinfo[i].free.prev; - else - { - do - i = _heapinfo[i].free.next; - while (i > 0 && i < block); - i = _heapinfo[i].free.prev; - } - - /* Determine how to link this block into the free list. */ - if (block == i + _heapinfo[i].free.size) - { - /* Coalesce this block with its predecessor. */ - _heapinfo[i].free.size += _heapinfo[block].busy.info.size; - block = i; - } - else - { - /* Really link this block back into the free list. */ - _heapinfo[block].free.size = _heapinfo[block].busy.info.size; - _heapinfo[block].free.next = _heapinfo[i].free.next; - _heapinfo[block].free.prev = i; - _heapinfo[i].free.next = block; - _heapinfo[_heapinfo[block].free.next].free.prev = block; - ++_chunks_free; - } - - /* Now that the block is linked in, see if we can coalesce it - with its successor (by deleting its successor from the list - and adding in its size). */ - if (block + _heapinfo[block].free.size == _heapinfo[block].free.next) - { - _heapinfo[block].free.size - += _heapinfo[_heapinfo[block].free.next].free.size; - _heapinfo[block].free.next - = _heapinfo[_heapinfo[block].free.next].free.next; - _heapinfo[_heapinfo[block].free.next].free.prev = block; - --_chunks_free; - } - - /* Now see if we can return stuff to the system. */ - blocks = _heapinfo[block].free.size; - if (blocks >= FINAL_FREE_BLOCKS && block + blocks == _heaplimit - && (*__morecore) (0) == ADDRESS (block + blocks)) - { - register size_t bytes = blocks * BLOCKSIZE; - _heaplimit -= blocks; - (*__morecore) (-bytes); - _heapinfo[_heapinfo[block].free.prev].free.next - = _heapinfo[block].free.next; - _heapinfo[_heapinfo[block].free.next].free.prev - = _heapinfo[block].free.prev; - block = _heapinfo[block].free.prev; - --_chunks_free; - _bytes_free -= bytes; - } - - /* Set the next search to begin at this block. */ - _heapindex = block; - break; - - default: - /* Do some of the statistics. */ - --_chunks_used; - _bytes_used -= 1 << type; - ++_chunks_free; - _bytes_free += 1 << type; - - /* Get the address of the first free fragment in this block. */ - prev = (struct list *) ((char *) ADDRESS (block) + - (_heapinfo[block].busy.info.frag.first << type)); - - if (_heapinfo[block].busy.info.frag.nfree == (BLOCKSIZE >> type) - 1 - && _fragblocks[type] > 1) - { - /* If all fragments of this block are free, remove them - from the fragment list and free the whole block. */ - --_fragblocks[type]; - next = prev; - for (i = 1; i < (size_t) (BLOCKSIZE >> type); ++i) - next = next->next; - prev->prev->next = next; - if (next != NULL) - next->prev = prev->prev; - _heapinfo[block].busy.type = 0; - _heapinfo[block].busy.info.size = 1; - - /* Keep the statistics accurate. */ - ++_chunks_used; - _bytes_used += BLOCKSIZE; - _chunks_free -= BLOCKSIZE >> type; - _bytes_free -= BLOCKSIZE; - - free (ADDRESS (block)); - } - else if (_heapinfo[block].busy.info.frag.nfree != 0) - { - /* If some fragments of this block are free, link this - fragment into the fragment list after the first free - fragment of this block. */ - next = (struct list *) ptr; - next->next = prev->next; - next->prev = prev; - prev->next = next; - if (next->next != NULL) - next->next->prev = next; - ++_heapinfo[block].busy.info.frag.nfree; - } - else - { - /* No fragments of this block are free, so link this - fragment into the fragment list and announce that - it is the first free fragment of this block. */ - prev = (struct list *) ptr; - _heapinfo[block].busy.info.frag.nfree = 1; - _heapinfo[block].busy.info.frag.first = (unsigned long int) - ((unsigned long int) ((char *) ptr - (char *) NULL) - % BLOCKSIZE >> type); - prev->next = _fraghead[type].next; - prev->prev = &_fraghead[type]; - prev->prev->next = prev; - if (prev->next != NULL) - prev->next->prev = prev; - } - break; - } -} - -/* Return memory to the heap. */ -void -free (ptr) - __ptr_t ptr; -{ - register struct alignlist *l; - - if (ptr == NULL) - return; - - for (l = _aligned_blocks; l != NULL; l = l->next) - if (l->aligned == ptr) - { - l->aligned = NULL; /* Mark the slot in the list as free. */ - ptr = l->exact; - break; - } - - if (__free_hook != NULL) - (*__free_hook) (ptr); - else - _free_internal (ptr); -} diff --git a/lib/malloclib/getpagesize.h b/lib/malloclib/getpagesize.h deleted file mode 100644 index b3aa4ba..0000000 --- a/lib/malloclib/getpagesize.h +++ /dev/null @@ -1,56 +0,0 @@ -/* Emulation of getpagesize() for systems that need it. - Copyright (C) 1991 Free Software Foundation, Inc. - -This program 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 of the License, or -(at your option) any later version. - -This program 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 this program; if not, write to the Free Software -Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ - -#if !defined (USG) -extern size_t getpagesize __P ((void)); -# if !defined (HAVE_GETPAGESIZE) -# define HAVE_GETPAGESIZE -# endif /* !HAVE_GETPAGESIZE */ -#endif /* !USG */ - -#if !defined (HAVE_GETPAGESIZE) && defined (HAVE_UNISTD_H) -# include -# if defined (_SC_PAGESIZE) -# define getpagesize() sysconf(_SC_PAGESIZE) -# endif /* _SC_PAGESIZE */ -#endif - -#if !defined (HAVE_GETPAGESIZE) -# include -# if defined (PAGESIZE) -# define getpagesize() PAGESIZE -# else /* !PAGESIZE */ -# if defined (EXEC_PAGESIZE) -# define getpagesize() EXEC_PAGESIZE -# else /* !EXEC_PAGESIZE */ -# if defined (NBPG) -# if !defined (CLSIZE) -# define CLSIZE 1 -# endif /* !CLSIZE */ -# define getpagesize() (NBPG * CLSIZE) -# else /* !NBPG */ -# if defined (NBPC) -# define getpagesize() NBPC -# endif /* NBPC */ -# endif /* !NBPG */ -# endif /* !EXEC_PAGESIZE */ -# endif /* !PAGESIZE */ -#endif /* !getpagesize */ - -#if !defined (HAVE_GETPAGESIZE) && !defined (getpagesize) -# define getpagesize() 4096 /* Just punt and use reasonable value */ -#endif /* !HAVE_GETPAGESIZE && !getpagesize */ diff --git a/lib/malloclib/i386-alloca.s b/lib/malloclib/i386-alloca.s deleted file mode 100644 index 01b2cfe..0000000 --- a/lib/malloclib/i386-alloca.s +++ /dev/null @@ -1,16 +0,0 @@ - .file "alloca.s" - .text - .align 4 - .def alloca; .val alloca; .scl 2; .type 044; .endef - .globl alloca -alloca: - popl %edx - popl %eax - addl $3,%eax - andl $0xfffffffc,%eax - subl %eax,%esp - movl %esp,%eax - pushl %eax - pushl %edx - ret - .def alloca; .val .; .scl -1; .endef diff --git a/lib/malloclib/malloc.c b/lib/malloclib/malloc.c deleted file mode 100644 index 1d9bc03..0000000 --- a/lib/malloclib/malloc.c +++ /dev/null @@ -1,324 +0,0 @@ -/* Memory allocator `malloc'. - Copyright 1990, 1991, 1992, 1993 Free Software Foundation - Written May 1989 by Mike Haertel. - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Library General Public License as -published by the Free Software Foundation; either version 2 of the -License, or (at your option) any later version. - -This 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 -Library General Public License for more details. - -You should have received a copy of the GNU Library General Public -License along with this library; see the file COPYING.LIB. If -not, write to the Free Software Foundation, Inc., 675 Mass Ave, -Cambridge, MA 02139, USA. - - The author may be reached (Email) at the address mike@ai.mit.edu, - or (US mail) as Mike Haertel c/o Free Software Foundation. */ - -#ifndef _MALLOC_INTERNAL -#define _MALLOC_INTERNAL -#include -#endif - -/* How to really get more memory. */ -__ptr_t (*__morecore) __P ((ptrdiff_t __size)) = __default_morecore; - -/* Debugging hook for `malloc'. */ -__ptr_t (*__malloc_hook) __P ((size_t __size)); - -/* Pointer to the base of the first block. */ -char *_heapbase; - -/* Block information table. Allocated with align/__free (not malloc/free). */ -malloc_info *_heapinfo; - -/* Number of info entries. */ -static size_t heapsize; - -/* Search index in the info table. */ -size_t _heapindex; - -/* Limit of valid info table indices. */ -size_t _heaplimit; - -/* Count of large blocks allocated for each fragment size. */ -int _fragblocks[BLOCKLOG]; - -/* Free lists for each fragment size. */ -struct list _fraghead[BLOCKLOG]; - -/* Instrumentation. */ -size_t _chunks_used; -size_t _bytes_used; -size_t _chunks_free; -size_t _bytes_free; - -/* Are you experienced? */ -int __malloc_initialized; - -void (*__after_morecore_hook) __P ((void)); - -/* Aligned allocation. */ -static __ptr_t align __P ((size_t)); -static __ptr_t -align (size) - size_t size; -{ - __ptr_t result; - unsigned long int adj; - - result = (*__morecore) (size); - adj = (unsigned long int) ((unsigned long int) ((char *) result - - (char *) NULL)) % BLOCKSIZE; - if (adj != 0) - { - adj = BLOCKSIZE - adj; - (void) (*__morecore) (adj); - result = (char *) result + adj; - } - - if (__after_morecore_hook) - (*__after_morecore_hook) (); - - return result; -} - -/* Set everything up and remember that we have. */ -static int initialize __P ((void)); -static int -initialize () -{ - heapsize = HEAP / BLOCKSIZE; - _heapinfo = (malloc_info *) align (heapsize * sizeof (malloc_info)); - - _bytes_used = heapsize * sizeof (malloc_info); - _chunks_used++; - - if (_heapinfo == NULL) - return 0; - memset (_heapinfo, 0, heapsize * sizeof (malloc_info)); - _heapinfo[0].free.size = 0; - _heapinfo[0].free.next = _heapinfo[0].free.prev = 0; - _heapindex = 0; - _heapbase = (char *) _heapinfo; - __malloc_initialized = 1; - return 1; -} - -/* Get neatly aligned memory, initializing or - growing the heap info table as necessary. */ -static __ptr_t morecore __P ((size_t)); -static __ptr_t -morecore (size) - size_t size; -{ - __ptr_t result; - malloc_info *newinfo, *oldinfo; - size_t newsize; - - result = align (size); - if (result == NULL) - return NULL; - - /* Check if we need to grow the info table. */ - if ((size_t) BLOCK ((char *) result + size) > heapsize) - { - newsize = heapsize; - while ((size_t) BLOCK ((char *) result + size) > newsize) - newsize *= 2; - newinfo = (malloc_info *) align (newsize * sizeof (malloc_info)); - if (newinfo == NULL) - { - (*__morecore) (-size); - return NULL; - } - - _bytes_used += newsize * sizeof (malloc_info); - _chunks_used++; - - memset (newinfo, 0, newsize * sizeof (malloc_info)); - memcpy (newinfo, _heapinfo, heapsize * sizeof (malloc_info)); - oldinfo = _heapinfo; - newinfo[BLOCK (oldinfo)].busy.type = 0; - newinfo[BLOCK (oldinfo)].busy.info.size - = BLOCKIFY (heapsize * sizeof (malloc_info)); - _heapinfo = newinfo; - - heapsize = newsize; - } - - _heaplimit = BLOCK ((char *) result + size); - return result; -} - -/* Allocate memory from the heap. */ -__ptr_t -malloc (size) - size_t size; -{ - __ptr_t result; - size_t block, blocks, lastblocks, start; - register size_t i; - struct list *next; - - if (size == 0) - return NULL; - - if (__malloc_hook != NULL) - return (*__malloc_hook) (size); - - if (!__malloc_initialized) - if (!initialize ()) - return NULL; - - if (size < sizeof (struct list)) - size = sizeof (struct list); - - /* Determine the allocation policy based on the request size. */ - if (size <= BLOCKSIZE / 2) - { - /* Small allocation to receive a fragment of a block. - Determine the logarithm to base two of the fragment size. */ - register size_t log = 1; - --size; - while ((size /= 2) != 0) - ++log; - - /* Look in the fragment lists for a - free fragment of the desired size. */ - next = _fraghead[log].next; - if (next != NULL) - { - /* There are free fragments of this size. - Pop a fragment out of the fragment list and return it. - Update the block's nfree and first counters. */ - result = (__ptr_t) next; - next->prev->next = next->next; - if (next->next != NULL) - next->next->prev = next->prev; - block = BLOCK (result); - if (--_heapinfo[block].busy.info.frag.nfree != 0) - _heapinfo[block].busy.info.frag.first = (unsigned long int) - ((unsigned long int) ((char *) next->next - (char *) NULL) - % BLOCKSIZE) >> log; - - /* Update the statistics. */ - ++_chunks_used; - _bytes_used += 1 << log; - --_chunks_free; - _bytes_free -= 1 << log; - } - else - { - /* No free fragments of the desired size, so get a new block - and break it into fragments, returning the first. */ - result = malloc (BLOCKSIZE); - if (result == NULL) - return NULL; - ++_fragblocks[log]; - - /* Link all fragments but the first into the free list. */ - for (i = 1; i < (size_t) (BLOCKSIZE >> log); ++i) - { - next = (struct list *) ((char *) result + (i << log)); - next->next = _fraghead[log].next; - next->prev = &_fraghead[log]; - next->prev->next = next; - if (next->next != NULL) - next->next->prev = next; - } - - /* Initialize the nfree and first counters for this block. */ - block = BLOCK (result); - _heapinfo[block].busy.type = log; - _heapinfo[block].busy.info.frag.nfree = i - 1; - _heapinfo[block].busy.info.frag.first = i - 1; - - _chunks_free += (BLOCKSIZE >> log) - 1; - _bytes_free += BLOCKSIZE - (1 << log); - _bytes_used -= BLOCKSIZE - (1 << log); - } - } - else - { - /* Large allocation to receive one or more blocks. - Search the free list in a circle starting at the last place visited. - If we loop completely around without finding a large enough - space we will have to get more memory from the system. */ - blocks = BLOCKIFY (size); - start = block = _heapindex; - while (_heapinfo[block].free.size < blocks) - { - block = _heapinfo[block].free.next; - if (block == start) - { - /* Need to get more from the system. Check to see if - the new core will be contiguous with the final free - block; if so we don't need to get as much. */ - block = _heapinfo[0].free.prev; - lastblocks = _heapinfo[block].free.size; - if (_heaplimit != 0 && block + lastblocks == _heaplimit && - (*__morecore) (0) == ADDRESS (block + lastblocks) && - (morecore ((blocks - lastblocks) * BLOCKSIZE)) != NULL) - { - /* Note that morecore() can change the location of - the final block if it moves the info table and the - old one gets coalesced into the final block. */ - block = _heapinfo[0].free.prev; - _heapinfo[block].free.size += blocks - lastblocks; - continue; - } - result = morecore (blocks * BLOCKSIZE); - if (result == NULL) - return NULL; - block = BLOCK (result); - _heapinfo[block].busy.type = 0; - _heapinfo[block].busy.info.size = blocks; - ++_chunks_used; - _bytes_used += blocks * BLOCKSIZE; - return result; - } - } - - /* At this point we have found a suitable free list entry. - Figure out how to remove what we need from the list. */ - result = ADDRESS (block); - if (_heapinfo[block].free.size > blocks) - { - /* The block we found has a bit left over, - so relink the tail end back into the free list. */ - _heapinfo[block + blocks].free.size - = _heapinfo[block].free.size - blocks; - _heapinfo[block + blocks].free.next - = _heapinfo[block].free.next; - _heapinfo[block + blocks].free.prev - = _heapinfo[block].free.prev; - _heapinfo[_heapinfo[block].free.prev].free.next - = _heapinfo[_heapinfo[block].free.next].free.prev - = _heapindex = block + blocks; - } - else - { - /* The block exactly matches our requirements, - so just remove it from the list. */ - _heapinfo[_heapinfo[block].free.next].free.prev - = _heapinfo[block].free.prev; - _heapinfo[_heapinfo[block].free.prev].free.next - = _heapindex = _heapinfo[block].free.next; - --_chunks_free; - } - - _heapinfo[block].busy.type = 0; - _heapinfo[block].busy.info.size = blocks; - ++_chunks_used; - _bytes_used += blocks * BLOCKSIZE; - _bytes_free -= blocks * BLOCKSIZE; - } - - return result; -} diff --git a/lib/malloclib/malloc.h b/lib/malloclib/malloc.h deleted file mode 100644 index 705a8c0..0000000 --- a/lib/malloclib/malloc.h +++ /dev/null @@ -1,268 +0,0 @@ -/* Declarations for `malloc' and friends. - Copyright 1990, 1991, 1992, 1993 Free Software Foundation, Inc. - Written May 1989 by Mike Haertel. - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Library General Public License as -published by the Free Software Foundation; either version 2 of the -License, or (at your option) any later version. - -This 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 -Library General Public License for more details. - -You should have received a copy of the GNU Library General Public -License along with this library; see the file COPYING.LIB. If -not, write to the Free Software Foundation, Inc., 675 Mass Ave, -Cambridge, MA 02139, USA. - - The author may be reached (Email) at the address mike@ai.mit.edu, - or (US mail) as Mike Haertel c/o Free Software Foundation. */ - -#ifndef _MALLOC_H - -#define _MALLOC_H 1 - -#ifdef _MALLOC_INTERNAL -/* Harmless, gets __GNU_LIBRARY__ defined. - We must do this before #defining size_t and ptrdiff_t - because tries to typedef them on some systems. */ -#include -#endif - -#ifdef __cplusplus -extern "C" -{ -#endif - -#if defined (__cplusplus) || (defined (__STDC__) && __STDC__) -#undef __P -#define __P(args) args -#undef __ptr_t -#define __ptr_t void * -#else /* Not C++ or ANSI C. */ -#undef __P -#define __P(args) () -#undef const -#define const -#undef __ptr_t -#define __ptr_t char * -#endif /* C++ or ANSI C. */ - -#ifndef NULL -#define NULL 0 -#endif - -#ifdef __STDC__ -#include -#else -#undef size_t -#define size_t unsigned int -#undef ptrdiff_t -#define ptrdiff_t int -#endif - - -/* Allocate SIZE bytes of memory. */ -extern __ptr_t malloc __P ((size_t __size)); -/* Re-allocate the previously allocated block - in __ptr_t, making the new block SIZE bytes long. */ -extern __ptr_t realloc __P ((__ptr_t __ptr, size_t __size)); -/* Allocate NMEMB elements of SIZE bytes each, all initialized to 0. */ -extern __ptr_t calloc __P ((size_t __nmemb, size_t __size)); -/* Free a block allocated by `malloc', `realloc' or `calloc'. */ -extern void free __P ((__ptr_t __ptr)); - -/* Allocate SIZE bytes allocated to ALIGNMENT bytes. */ -extern __ptr_t memalign __P ((size_t __alignment, size_t __size)); - -/* Allocate SIZE bytes on a page boundary. */ -extern __ptr_t valloc __P ((size_t __size)); - - -#ifdef _MALLOC_INTERNAL - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#if defined(__GNU_LIBRARY__) || defined(STDC_HEADERS) || defined(USG) -#include -#else -#ifndef memset -#define memset(s, zero, n) bzero ((s), (n)) -#endif -#ifndef memcpy -#define memcpy(d, s, n) bcopy ((s), (d), (n)) -#endif -#ifndef memmove -#define memmove(d, s, n) bcopy ((s), (d), (n)) -#endif -#endif - - -#if defined(__GNU_LIBRARY__) || defined(__STDC__) -#include -#else -#define CHAR_BIT 8 -#endif - -/* The allocator divides the heap into blocks of fixed size; large - requests receive one or more whole blocks, and small requests - receive a fragment of a block. Fragment sizes are powers of two, - and all fragments of a block are the same size. When all the - fragments in a block have been freed, the block itself is freed. */ -#define INT_BIT (CHAR_BIT * sizeof(int)) -#define BLOCKLOG (INT_BIT > 16 ? 12 : 9) -#define BLOCKSIZE (1 << BLOCKLOG) -#define BLOCKIFY(SIZE) (((SIZE) + BLOCKSIZE - 1) / BLOCKSIZE) - -/* Determine the amount of memory spanned by the initial heap table - (not an absolute limit). */ -#define HEAP (INT_BIT > 16 ? 4194304 : 65536) - -/* Number of contiguous free blocks allowed to build up at the end of - memory before they will be returned to the system. */ -#define FINAL_FREE_BLOCKS 8 - -/* Data structure giving per-block information. */ -typedef union - { - /* Heap information for a busy block. */ - struct - { - /* Zero for a large block, or positive giving the - logarithm to the base two of the fragment size. */ - int type; - union - { - struct - { - size_t nfree; /* Free fragments in a fragmented block. */ - size_t first; /* First free fragment of the block. */ - } frag; - /* Size (in blocks) of a large cluster. */ - size_t size; - } info; - } busy; - /* Heap information for a free block - (that may be the first of a free cluster). */ - struct - { - size_t size; /* Size (in blocks) of a free cluster. */ - size_t next; /* Index of next free cluster. */ - size_t prev; /* Index of previous free cluster. */ - } free; - } malloc_info; - -/* Pointer to first block of the heap. */ -extern char *_heapbase; - -/* Table indexed by block number giving per-block information. */ -extern malloc_info *_heapinfo; - -/* Address to block number and vice versa. */ -#define BLOCK(A) (((char *) (A) - _heapbase) / BLOCKSIZE + 1) -#define ADDRESS(B) ((__ptr_t) (((B) - 1) * BLOCKSIZE + _heapbase)) - -/* Current search index for the heap table. */ -extern size_t _heapindex; - -/* Limit of valid info table indices. */ -extern size_t _heaplimit; - -/* Doubly linked lists of free fragments. */ -struct list - { - struct list *next; - struct list *prev; - }; - -/* Count of blocks for each fragment size. */ -extern int _fragblocks[]; - -/* Free list headers for each fragment size. */ -extern struct list _fraghead[]; - -/* List of blocks allocated with `memalign' (or `valloc'). */ -struct alignlist - { - struct alignlist *next; - __ptr_t aligned; /* The address that memaligned returned. */ - __ptr_t exact; /* The address that malloc returned. */ - }; -extern struct alignlist *_aligned_blocks; - -/* Instrumentation. */ -extern size_t _chunks_used; -extern size_t _bytes_used; -extern size_t _chunks_free; -extern size_t _bytes_free; - -/* Internal version of `free' used in `morecore' (malloc.c). */ -extern void _free_internal __P ((__ptr_t __ptr)); - -#endif /* _MALLOC_INTERNAL. */ - -/* Underlying allocation function; successive calls should - return contiguous pieces of memory. */ -extern __ptr_t (*__morecore) __P ((ptrdiff_t __size)); - -/* Default value of `__morecore'. */ -extern __ptr_t __default_morecore __P ((ptrdiff_t __size)); - -/* If not NULL, this function is called after each time - `__morecore' is called to increase the data size. */ -extern void (*__after_morecore_hook) __P ((void)); - -/* Nonzero if `malloc' has been called and done its initialization. */ -extern int __malloc_initialized; - -/* Hooks for debugging versions. */ -extern void (*__free_hook) __P ((__ptr_t __ptr)); -extern __ptr_t (*__malloc_hook) __P ((size_t __size)); -extern __ptr_t (*__realloc_hook) __P ((__ptr_t __ptr, size_t __size)); - -/* Activate a standard collection of debugging hooks. */ -extern int mcheck __P ((void (*__bfunc) __P ((char *)), - void (*__afunc) __P ((void)))); - -/* Activate a standard collection of tracing hooks. */ -extern void mtrace __P ((void)); - -/* Statistics available to the user. */ -struct mstats - { - size_t bytes_total; /* Total size of the heap. */ - size_t chunks_used; /* Chunks allocated by the user. */ - size_t bytes_used; /* Byte total of user-allocated chunks. */ - size_t chunks_free; /* Chunks in the free list. */ - size_t bytes_free; /* Byte total of chunks in the free list. */ - }; - -/* Pick up the current statistics. */ -extern struct mstats mstats __P ((void)); - -/* Call WARNFUN with a warning message when memory usage is high. */ -extern void memory_warnings __P ((__ptr_t __start, - void (*__warnfun) __P ((__const char *)))); - - -/* Relocating allocator. */ - -/* Allocate SIZE bytes, and store the address in *HANDLEPTR. */ -extern __ptr_t r_alloc __P ((__ptr_t *__handleptr, size_t __size)); - -/* Free the storage allocated in HANDLEPTR. */ -extern void r_alloc_free __P ((__ptr_t *__handleptr)); - -/* Adjust the block at HANDLEPTR to be SIZE bytes long. */ -extern __ptr_t r_re_alloc __P ((__ptr_t *__handleptr, size_t __size)); - - -#ifdef __cplusplus -} -#endif - -#endif /* malloc.h */ diff --git a/lib/malloclib/mcheck.c b/lib/malloclib/mcheck.c deleted file mode 100644 index f7d9d4f..0000000 --- a/lib/malloclib/mcheck.c +++ /dev/null @@ -1,133 +0,0 @@ -/* Standard debugging hooks for `malloc'. - Copyright 1990, 1991, 1992, 1993 Free Software Foundation - Written May 1989 by Mike Haertel. - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Library General Public License as -published by the Free Software Foundation; either version 2 of the -License, or (at your option) any later version. - -This 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 -Library General Public License for more details. - -You should have received a copy of the GNU Library General Public -License along with this library; see the file COPYING.LIB. If -not, write to the Free Software Foundation, Inc., 675 Mass Ave, -Cambridge, MA 02139, USA. - - The author may be reached (Email) at the address mike@ai.mit.edu, - or (US mail) as Mike Haertel c/o Free Software Foundation. */ - -#ifndef _MALLOC_INTERNAL -#define _MALLOC_INTERNAL -#include -#endif - -/* Old hook values. */ -static void (*old_free_hook) __P ((__ptr_t ptr)); -static __ptr_t (*old_malloc_hook) __P ((size_t size)); -static __ptr_t (*old_realloc_hook) __P ((__ptr_t ptr, size_t size)); - -/* Function to call when something awful happens. */ -static void (*abortfunc) __P ((void)); - -/* Arbitrary magical numbers. */ -#define MAGICWORD 0xfedabeeb -#define MAGICBYTE ((char) 0xd7) - -struct hdr - { - size_t size; /* Exact size requested by user. */ - unsigned long int magic; /* Magic number to check header integrity. */ - }; - -static void checkhdr __P ((const struct hdr *)); -static void -checkhdr (hdr) - const struct hdr *hdr; -{ - if (hdr->magic != MAGICWORD || ((char *) &hdr[1])[hdr->size] != MAGICBYTE) - (*abortfunc) (); -} - -static void freehook __P ((__ptr_t)); -static void -freehook (ptr) - __ptr_t ptr; -{ - struct hdr *hdr = ((struct hdr *) ptr) - 1; - checkhdr (hdr); - hdr->magic = 0; - __free_hook = old_free_hook; - free (hdr); - __free_hook = freehook; -} - -static __ptr_t mallochook __P ((size_t)); -static __ptr_t -mallochook (size) - size_t size; -{ - struct hdr *hdr; - - __malloc_hook = old_malloc_hook; - hdr = (struct hdr *) malloc (sizeof (struct hdr) + size + 1); - __malloc_hook = mallochook; - if (hdr == NULL) - return NULL; - - hdr->size = size; - hdr->magic = MAGICWORD; - ((char *) &hdr[1])[size] = MAGICBYTE; - return (__ptr_t) (hdr + 1); -} - -static __ptr_t reallochook __P ((__ptr_t, size_t)); -static __ptr_t -reallochook (ptr, size) - __ptr_t ptr; - size_t size; -{ - struct hdr *hdr = ((struct hdr *) ptr) - 1; - - checkhdr (hdr); - __free_hook = old_free_hook; - __malloc_hook = old_malloc_hook; - __realloc_hook = old_realloc_hook; - hdr = (struct hdr *) realloc ((__ptr_t) hdr, sizeof (struct hdr) + size + 1); - __free_hook = freehook; - __malloc_hook = mallochook; - __realloc_hook = reallochook; - if (hdr == NULL) - return NULL; - - hdr->size = size; - ((char *) &hdr[1])[size] = MAGICBYTE; - return (__ptr_t) (hdr + 1); -} - -int -mcheck (func) - void (*func) __P ((void)); -{ - extern void abort __P ((void)); - static int mcheck_used = 0; - - abortfunc = (func != NULL) ? func : abort; - - /* These hooks may not be safely inserted if malloc is already in use. */ - if (!__malloc_initialized && !mcheck_used) - { - old_free_hook = __free_hook; - __free_hook = freehook; - old_malloc_hook = __malloc_hook; - __malloc_hook = mallochook; - old_realloc_hook = __realloc_hook; - __realloc_hook = reallochook; - mcheck_used = 1; - } - - return mcheck_used ? 0 : -1; -} diff --git a/lib/malloclib/memalign.c b/lib/malloclib/memalign.c deleted file mode 100644 index f5ad17c..0000000 --- a/lib/malloclib/memalign.c +++ /dev/null @@ -1,61 +0,0 @@ -/* Copyright (C) 1991, 1992 Free Software Foundation, Inc. - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Library General Public License as -published by the Free Software Foundation; either version 2 of the -License, or (at your option) any later version. - -This 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 -Library General Public License for more details. - -You should have received a copy of the GNU Library General Public -License along with this library; see the file COPYING.LIB. If -not, write to the Free Software Foundation, Inc., 675 Mass Ave, -Cambridge, MA 02139, USA. */ - -#ifndef _MALLOC_INTERNAL -#define _MALLOC_INTERNAL -#include -#endif - -__ptr_t -memalign (alignment, size) - size_t alignment; - size_t size; -{ - __ptr_t result; - unsigned long int adj; - - size = ((size + alignment - 1) / alignment) * alignment; - - result = malloc (size); - if (result == NULL) - return NULL; - adj = (unsigned long int) ((unsigned long int) ((char *) result - - (char *) NULL)) % alignment; - if (adj != 0) - { - struct alignlist *l; - for (l = _aligned_blocks; l != NULL; l = l->next) - if (l->aligned == NULL) - /* This slot is free. Use it. */ - break; - if (l == NULL) - { - l = (struct alignlist *) malloc (sizeof (struct alignlist)); - if (l == NULL) - { - free (result); - return NULL; - } - } - l->exact = result; - result = l->aligned = (char *) result + alignment - adj; - l->next = _aligned_blocks; - _aligned_blocks = l; - } - - return result; -} diff --git a/lib/malloclib/morecore.c b/lib/malloclib/morecore.c deleted file mode 100644 index c9a9ca5..0000000 --- a/lib/malloclib/morecore.c +++ /dev/null @@ -1,44 +0,0 @@ -/* Copyright (C) 1991, 1992 Free Software Foundation, Inc. -This file is part of the GNU C Library. - -The GNU C 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 C 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. - -You should have received a copy of the GNU General Public License -along with the GNU C Library; see the file COPYING. If not, write to -the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ - -#ifndef _MALLOC_INTERNAL -#define _MALLOC_INTERNAL -#include -#endif - -#ifndef __GNU_LIBRARY__ -#define __sbrk sbrk -#endif - -extern __ptr_t __sbrk __P ((int increment)); - -#ifndef NULL -#define NULL 0 -#endif - -/* Allocate INCREMENT more bytes of data space, - and return the start of data space, or NULL on errors. - If INCREMENT is negative, shrink data space. */ -__ptr_t -__default_morecore (increment) - ptrdiff_t increment; -{ - __ptr_t result = __sbrk ((int) increment); - if (result == (__ptr_t) -1) - return NULL; - return result; -} diff --git a/lib/malloclib/mstats.c b/lib/malloclib/mstats.c deleted file mode 100644 index 511cdad..0000000 --- a/lib/malloclib/mstats.c +++ /dev/null @@ -1,39 +0,0 @@ -/* Access the statistics maintained by `malloc'. - Copyright 1990, 1991, 1992 Free Software Foundation - Written May 1989 by Mike Haertel. - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Library General Public License as -published by the Free Software Foundation; either version 2 of the -License, or (at your option) any later version. - -This 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 -Library General Public License for more details. - -You should have received a copy of the GNU Library General Public -License along with this library; see the file COPYING.LIB. If -not, write to the Free Software Foundation, Inc., 675 Mass Ave, -Cambridge, MA 02139, USA. - - The author may be reached (Email) at the address mike@ai.mit.edu, - or (US mail) as Mike Haertel c/o Free Software Foundation. */ - -#ifndef _MALLOC_INTERNAL -#define _MALLOC_INTERNAL -#include -#endif - -struct mstats -mstats () -{ - struct mstats result; - - result.bytes_total = (char *) (*__morecore) (0) - _heapbase; - result.chunks_used = _chunks_used; - result.bytes_used = _bytes_used; - result.chunks_free = _chunks_free; - result.bytes_free = _bytes_free; - return result; -} diff --git a/lib/malloclib/mtrace.awk b/lib/malloclib/mtrace.awk deleted file mode 100644 index d7689ce..0000000 --- a/lib/malloclib/mtrace.awk +++ /dev/null @@ -1,36 +0,0 @@ -# -# Awk program to analyze mtrace.c output. -# -$1 == "+" { if (allocated[$2] != "") - print "+", $2, "Alloc", NR, "duplicate:", allocated[$2]; - else - allocated[$2] = $3; - } -$1 == "-" { if (allocated[$2] != "") { - allocated[$2] = ""; - if (allocated[$2] != "") - print "DELETE FAILED", $2, allocated[$2]; - } else - print "-", $2, "Free", NR, "was never alloc'd"; - } -$1 == "<" { if (allocated[$2] != "") - allocated[$2] = ""; - else - print "-", $2, "Realloc", NR, "was never alloc'd"; - } -$1 == ">" { if (allocated[$2] != "") - print "+", $2, "Realloc", NR, "duplicate:", allocated[$2]; - else - allocated[$2] = $3; - } - -# Ignore "= Start" -$1 == "=" { } -# Ignore failed realloc attempts for now -$1 == "!" { } - - -END { for (x in allocated) - if (allocated[x] != "") - print "+", x, allocated[x]; - } diff --git a/lib/malloclib/mtrace.c b/lib/malloclib/mtrace.c deleted file mode 100644 index ea1d3a4..0000000 --- a/lib/malloclib/mtrace.c +++ /dev/null @@ -1,150 +0,0 @@ -/* More debugging hooks for `malloc'. - Copyright (C) 1991, 1992, 1993 Free Software Foundation, Inc. - Written April 2, 1991 by John Gilmore of Cygnus Support. - Based on mcheck.c by Mike Haertel. - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Library General Public License as -published by the Free Software Foundation; either version 2 of the -License, or (at your option) any later version. - -This 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 -Library General Public License for more details. - -You should have received a copy of the GNU Library General Public -License along with this library; see the file COPYING.LIB. If -not, write to the Free Software Foundation, Inc., 675 Mass Ave, -Cambridge, MA 02139, USA. - - The author may be reached (Email) at the address mike@ai.mit.edu, - or (US mail) as Mike Haertel c/o Free Software Foundation. */ - -#ifndef _MALLOC_INTERNAL -#define _MALLOC_INTERNAL -#include -#endif - -/* Don't #include because did it for us. */ - -#ifndef __GNU_LIBRARY__ -extern char *getenv (); -#else -#include -#endif - -static FILE *mallstream; -static char mallenv[]= "MALLOC_TRACE"; -static char mallbuf[BUFSIZ]; /* Buffer for the output. */ - -/* Address to breakpoint on accesses to... */ -__ptr_t mallwatch; - -/* Old hook values. */ -static void (*tr_old_free_hook) __P ((__ptr_t ptr)); -static __ptr_t (*tr_old_malloc_hook) __P ((size_t size)); -static __ptr_t (*tr_old_realloc_hook) __P ((__ptr_t ptr, size_t size)); - -/* This function is called when the block being alloc'd, realloc'd, or - freed has an address matching the variable "mallwatch". In a debugger, - set "mallwatch" to the address of interest, then put a breakpoint on - tr_break. */ - -void tr_break __P ((void)); -void -tr_break () -{ -} - -static void tr_freehook __P ((__ptr_t)); -static void -tr_freehook (ptr) - __ptr_t ptr; -{ - fprintf (mallstream, "- %p\n", ptr); /* Be sure to print it first. */ - if (ptr == mallwatch) - tr_break (); - __free_hook = tr_old_free_hook; - free (ptr); - __free_hook = tr_freehook; -} - -static __ptr_t tr_mallochook __P ((size_t)); -static __ptr_t -tr_mallochook (size) - size_t size; -{ - __ptr_t hdr; - - __malloc_hook = tr_old_malloc_hook; - hdr = (__ptr_t) malloc (size); - __malloc_hook = tr_mallochook; - - /* We could be printing a NULL here; that's OK. */ - fprintf (mallstream, "+ %p %x\n", hdr, size); - - if (hdr == mallwatch) - tr_break (); - - return hdr; -} - -static __ptr_t tr_reallochook __P ((__ptr_t, size_t)); -static __ptr_t -tr_reallochook (ptr, size) - __ptr_t ptr; - size_t size; -{ - __ptr_t hdr; - - if (ptr == mallwatch) - tr_break (); - - __free_hook = tr_old_free_hook; - __malloc_hook = tr_old_malloc_hook; - __realloc_hook = tr_old_realloc_hook; - hdr = (__ptr_t) realloc (ptr, size); - __free_hook = tr_freehook; - __malloc_hook = tr_mallochook; - __realloc_hook = tr_reallochook; - if (hdr == NULL) - /* Failed realloc. */ - fprintf (mallstream, "! %p %x\n", ptr, size); - else - fprintf (mallstream, "< %p\n> %p %x\n", ptr, hdr, size); - - if (hdr == mallwatch) - tr_break (); - - return hdr; -} - -/* We enable tracing if either the environment variable MALLOC_TRACE - is set, or if the variable mallwatch has been patched to an address - that the debugging user wants us to stop on. When patching mallwatch, - don't forget to set a breakpoint on tr_break! */ - -void -mtrace () -{ - char *mallfile; - - mallfile = getenv (mallenv); - if (mallfile != NULL || mallwatch != NULL) - { - mallstream = fopen (mallfile != NULL ? mallfile : "/dev/null", "w"); - if (mallstream != NULL) - { - /* Be sure it doesn't malloc its buffer! */ - setbuf (mallstream, mallbuf); - fprintf (mallstream, "= Start\n"); - tr_old_free_hook = __free_hook; - __free_hook = tr_freehook; - tr_old_malloc_hook = __malloc_hook; - __malloc_hook = tr_mallochook; - tr_old_realloc_hook = __realloc_hook; - __realloc_hook = tr_reallochook; - } - } -} diff --git a/lib/malloclib/realloc.c b/lib/malloclib/realloc.c deleted file mode 100644 index 2d31766..0000000 --- a/lib/malloclib/realloc.c +++ /dev/null @@ -1,146 +0,0 @@ -/* Change the size of a block allocated by `malloc'. - Copyright 1990, 1991, 1992, 1993 Free Software Foundation, Inc. - Written May 1989 by Mike Haertel. - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Library General Public License as -published by the Free Software Foundation; either version 2 of the -License, or (at your option) any later version. - -This 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 -Library General Public License for more details. - -You should have received a copy of the GNU Library General Public -License along with this library; see the file COPYING.LIB. If -not, write to the Free Software Foundation, Inc., 675 Mass Ave, -Cambridge, MA 02139, USA. - - The author may be reached (Email) at the address mike@ai.mit.edu, - or (US mail) as Mike Haertel c/o Free Software Foundation. */ - -#ifndef _MALLOC_INTERNAL -#define _MALLOC_INTERNAL -#include -#endif - -#define min(A, B) ((A) < (B) ? (A) : (B)) - -/* Debugging hook for realloc. */ -__ptr_t (*__realloc_hook) __P ((__ptr_t __ptr, size_t __size)); - -/* Resize the given region to the new size, returning a pointer - to the (possibly moved) region. This is optimized for speed; - some benchmarks seem to indicate that greater compactness is - achieved by unconditionally allocating and copying to a - new region. This module has incestuous knowledge of the - internals of both free and malloc. */ -__ptr_t -realloc (ptr, size) - __ptr_t ptr; - size_t size; -{ - __ptr_t result; - int type; - size_t block, blocks, oldlimit; - - if (size == 0) - { - free (ptr); - return malloc (0); - } - else if (ptr == NULL) - return malloc (size); - - if (__realloc_hook != NULL) - return (*__realloc_hook) (ptr, size); - - block = BLOCK (ptr); - - type = _heapinfo[block].busy.type; - switch (type) - { - case 0: - /* Maybe reallocate a large block to a small fragment. */ - if (size <= BLOCKSIZE / 2) - { - result = malloc (size); - if (result != NULL) - { - memcpy (result, ptr, size); - free (ptr); - return result; - } - } - - /* The new size is a large allocation as well; - see if we can hold it in place. */ - blocks = BLOCKIFY (size); - if (blocks < _heapinfo[block].busy.info.size) - { - /* The new size is smaller; return - excess memory to the free list. */ - _heapinfo[block + blocks].busy.type = 0; - _heapinfo[block + blocks].busy.info.size - = _heapinfo[block].busy.info.size - blocks; - _heapinfo[block].busy.info.size = blocks; - free (ADDRESS (block + blocks)); - result = ptr; - } - else if (blocks == _heapinfo[block].busy.info.size) - /* No size change necessary. */ - result = ptr; - else - { - /* Won't fit, so allocate a new region that will. - Free the old region first in case there is sufficient - adjacent free space to grow without moving. */ - blocks = _heapinfo[block].busy.info.size; - /* Prevent free from actually returning memory to the system. */ - oldlimit = _heaplimit; - _heaplimit = 0; - free (ptr); - _heaplimit = oldlimit; - result = malloc (size); - if (result == NULL) - { - /* Now we're really in trouble. We have to unfree - the thing we just freed. Unfortunately it might - have been coalesced with its neighbors. */ - if (_heapindex == block) - (void) malloc (blocks * BLOCKSIZE); - else - { - __ptr_t previous = malloc ((block - _heapindex) * BLOCKSIZE); - (void) malloc (blocks * BLOCKSIZE); - free (previous); - } - return NULL; - } - if (ptr != result) - memmove (result, ptr, blocks * BLOCKSIZE); - } - break; - - default: - /* Old size is a fragment; type is logarithm - to base two of the fragment size. */ - if (size > (size_t) (1 << (type - 1)) && size <= (size_t) (1 << type)) - /* The new size is the same kind of fragment. */ - result = ptr; - else - { - /* The new size is different; allocate a new space, - and copy the lesser of the new size and the old. */ - result = malloc (size); - if (result == NULL) - return NULL; - memcpy (result, ptr, min (size, (size_t) 1 << type)); - free (ptr); - } - break; - } - - return result; -} diff --git a/lib/malloclib/valloc.c b/lib/malloclib/valloc.c deleted file mode 100644 index eb5d372..0000000 --- a/lib/malloclib/valloc.c +++ /dev/null @@ -1,48 +0,0 @@ -/* Allocate memory on a page boundary. - Copyright (C) 1991, 1992, 1993 Free Software Foundation, Inc. - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Library General Public License as -published by the Free Software Foundation; either version 2 of the -License, or (at your option) any later version. - -This 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 -Library General Public License for more details. - -You should have received a copy of the GNU Library General Public -License along with this library; see the file COPYING.LIB. If -not, write to the Free Software Foundation, Inc., 675 Mass Ave, -Cambridge, MA 02139, USA. - - The author may be reached (Email) at the address mike@ai.mit.edu, - or (US mail) as Mike Haertel c/o Free Software Foundation. */ - -#ifndef _MALLOC_INTERNAL -#define _MALLOC_INTERNAL -#include -#endif - -#if defined (emacs) || defined (HAVE_CONFIG_H) -#include "config.h" -#endif - -#ifdef __GNU_LIBRARY__ -extern size_t __getpagesize __P ((void)); -#else -#include "getpagesize.h" -#define __getpagesize() getpagesize() -#endif - -static size_t pagesize; - -__ptr_t -valloc (size) - size_t size; -{ - if (pagesize == 0) - pagesize = __getpagesize (); - - return memalign (pagesize, size); -} diff --git a/lib/malloclib/x386-alloca.s b/lib/malloclib/x386-alloca.s deleted file mode 100644 index 112d33c..0000000 --- a/lib/malloclib/x386-alloca.s +++ /dev/null @@ -1,63 +0,0 @@ -;; alloca386.s 1.2 -;; GNU-compatible stack allocation function for Xenix/386. -;; Written by Chip Salzenberg at ComDev. -;; Last modified 90/01/11 -;;> Is your alloca clearly better than the one in i386-alloca.s? I haven't -;;> looked at either. -;; -;;They're different because Xenix/386 has a different assembler. SCO -;;Xenix has the Microsoft C compiler and the Microsoft macro assembler, -;;called "masm". MASM's assembler syntax is quite different from AT&T's -;;in all sorts of ways. Xenix people can't use the AT&T version. -;;-- -;;Chip Salzenberg at ComDev/TCT , - - TITLE $alloca386 - - .386 -DGROUP GROUP CONST, _BSS, _DATA -_DATA SEGMENT DWORD USE32 PUBLIC 'DATA' -_DATA ENDS -_BSS SEGMENT DWORD USE32 PUBLIC 'BSS' -_BSS ENDS -CONST SEGMENT DWORD USE32 PUBLIC 'CONST' -CONST ENDS -_TEXT SEGMENT DWORD USE32 PUBLIC 'CODE' - ASSUME CS: _TEXT, DS: DGROUP, SS: DGROUP, ES: DGROUP - - PUBLIC _alloca -_alloca PROC NEAR - -; Get argument. - pop edx ; edx -> return address - pop eax ; eax = amount to allocate - -; Validate allocation amount. - add eax,3 - and eax,not 3 - cmp eax,0 - jg aa_size_ok - mov eax,4 -aa_size_ok: - -; Allocate stack space. - mov ecx,esp ; ecx -> old stack pointer - sub esp,eax ; perform allocation - mov eax,esp ; eax -> new stack pointer - -; Copy the three saved register variables from old stack top to new stack top. -; They may not be there. So we waste twelve bytes. Big fat hairy deal. - push DWORD PTR 8[ecx] - push DWORD PTR 4[ecx] - push DWORD PTR 0[ecx] - -; Push something so the caller can pop it off. - push eax - -; Return to caller. - jmp edx - -_alloca ENDP - -_TEXT ENDS - END diff --git a/lib/malloclib/xmalloc.c b/lib/malloclib/xmalloc.c deleted file mode 100644 index a25cb11..0000000 --- a/lib/malloclib/xmalloc.c +++ /dev/null @@ -1,69 +0,0 @@ -/* xmalloc.c -- safe versions of malloc and realloc */ - -/* Copyright (C) 1991 Free Software Foundation, Inc. - - This file is part of GNU Readline, a library for reading lines - of text with interactive input and history editing. - - Readline is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by the - Free Software Foundation; either version 1, or (at your option) any - later version. - - Readline is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Readline; see the file COPYING. If not, write to the Free - Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ - -#include - -static void memory_error_and_abort (); - -/* **************************************************************** */ -/* */ -/* Memory Allocation and Deallocation. */ -/* */ -/* **************************************************************** */ - -/* Return a pointer to free()able block of memory large enough - to hold BYTES number of bytes. If the memory cannot be allocated, - print an error message and abort. */ -char * -xmalloc (bytes) - int bytes; -{ - char *temp = (char *)malloc (bytes); - - if (!temp) - memory_error_and_abort ("xmalloc"); - return (temp); -} - -char * -xrealloc (pointer, bytes) - char *pointer; - int bytes; -{ - char *temp; - - if (!pointer) - temp = (char *)malloc (bytes); - else - temp = (char *)realloc (pointer, bytes); - - if (!temp) - memory_error_and_abort ("xrealloc"); - return (temp); -} - -static void -memory_error_and_abort (fname) - char *fname; -{ - fprintf (stderr, "%s: Out of virtual memory!\n", fname); - abort (); -} diff --git a/lib/posixheaders/filecntl.h b/lib/posixheaders/filecntl.h index c0b2081..cf5054d 100644 --- a/lib/posixheaders/filecntl.h +++ b/lib/posixheaders/filecntl.h @@ -33,4 +33,13 @@ #define SET_CLOSE_ON_EXEC(fd) (fcntl ((fd), F_SETFD, FD_CLOEXEC)) #define SET_OPEN_ON_EXEC(fd) (fcntl ((fd), F_SETFD, FD_NCLOEXEC)) +/* How to open a file in non-blocking mode, the Posix.1 way. */ +#if !defined (O_NONBLOCK) +# if defined (O_NDELAY) +# define O_NONBLOCK O_NDELAY +# else +# define O_NONBLOCK 0 +# endif +#endif + #endif /* ! _FILECNTL_H_ */ diff --git a/lib/posixheaders/memalloc.h b/lib/posixheaders/memalloc.h index 750d53d..ba210bb 100644 --- a/lib/posixheaders/memalloc.h +++ b/lib/posixheaders/memalloc.h @@ -19,8 +19,8 @@ with Bash; see the file COPYING. If not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ -#if !defined (__MEMALLOC_H__) -# define __MEMALLOC_H__ +#if !defined (_MEMALLOC_H_) +# define _MEMALLOC_H_ #if defined (sparc) && defined (sun) && !defined (HAVE_ALLOCA_H) # define HAVE_ALLOCA_H @@ -34,8 +34,6 @@ # define HAVE_ALLOCA #endif /* HAVE_ALLOCA_H && !HAVE_ALLOCA */ -#if !defined (BUILDING_MAKEFILE) - #if defined (__GNUC__) # undef alloca # define alloca __builtin_alloca @@ -46,11 +44,15 @@ # else /* !IBMESA */ # include # endif /* !IBMESA */ -# else +# else /* !HAVE_ALLOCA_H */ +# if defined (hpux_9) && defined (__STDC__) && !defined (alloca) +extern void *alloca (); +# else +# if !defined (alloca) extern char *alloca (); +# endif /* !alloca */ +# endif /* !hpux_9 || !__STDC__ && !alloca */ # endif /* !HAVE_ALLOCA_H */ #endif /* !__GNUC__ */ -#endif /* !BUILDING_MAKEFILE */ - -#endif /* __MEMALLOC_H__ */ +#endif /* _MEMALLOC_H_ */ diff --git a/lib/posixheaders/posixdir.h b/lib/posixheaders/posixdir.h new file mode 100644 index 0000000..8b0e5bc --- /dev/null +++ b/lib/posixheaders/posixdir.h @@ -0,0 +1,49 @@ +/* posixdir.h -- Posix directory reading includes and defines. */ + +/* Copyright (C) 1987,1991 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 1, 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, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* This file should be included instead of or . */ + +#if !defined (_POSIXDIR_H_) +#define _POSIXDIR_H_ + +#if defined (HAVE_DIRENT_H) +# include +# define D_NAMLEN(d) (strlen ((d)->d_name)) +#else +# if defined (HAVE_SYS_NDIR_H) +# include +# endif +# if defined (HAVE_SYS_DIR_H) +# include +# endif +# if defined (HAVE_NDIR_H) +# include +# endif +# if !defined (dirent) +# define dirent direct +# endif /* !dirent */ +# define D_NAMLEN(d) ((d)->d_namlen) +#endif /* !HAVE_DIRENT_H */ + +#if defined (STRUCT_DIRENT_HAS_D_INO) +# define d_fileno d_ino +#endif + +#endif /* !_POSIXDIR_H_ */ diff --git a/lib/posixheaders/posixstat.h b/lib/posixheaders/posixstat.h index 7d1cece..bfce8c0 100644 --- a/lib/posixheaders/posixstat.h +++ b/lib/posixheaders/posixstat.h @@ -21,34 +21,27 @@ /* This file should be included instead of . It relies on the local sys/stat.h to work though. */ -#if !defined (_POSIXSTAT_H) -#define _POSIXSTAT_H +#if !defined (_POSIXSTAT_H_) +#define _POSIXSTAT_H_ #include -#if defined (isc386) -# if !defined (S_IFDIR) -# define S_IFDIR 0040000 -# endif /* !S_IFDIR */ -# if !defined (S_IFMT) -# define S_IFMT 0170000 -# endif /* !S_IFMT */ -#endif /* isc386 */ - -/* This text is taken directly from the Cadmus I was trying to - compile on: - the following MACROs are defined for X/OPEN compatibility - however, is the param correct ?? - #define S_ISBLK(s) ((s.st_mode & S_IFMT) == S_IFBLK) - - Well, the answer is no. Thus... */ -#if defined (BrainDeath) +#if defined (STAT_MACROS_BROKEN) # undef S_ISBLK # undef S_ISCHR # undef S_ISDIR # undef S_ISFIFO # undef S_ISREG -#endif /* BrainDeath */ +# undef S_ISLNK +#endif /* STAT_MACROS_BROKEN */ + +/* These are guaranteed to work only on isc386 */ +#if !defined (S_IFDIR) && !defined (S_ISDIR) +# define S_IFDIR 0040000 +#endif /* !S_IFDIR && !S_ISDIR */ +#if !defined (S_IFMT) +# define S_IFMT 0170000 +#endif /* !S_IFMT */ /* Posix 1003.1 5.6.1.1 file types */ @@ -114,7 +107,7 @@ /* * POSIX 1003.1 5.6.1.2 File Modes */ - + #if !defined (S_IRWXU) # if !defined (S_IREAD) # define S_IREAD 00400 @@ -146,4 +139,4 @@ #define S_IWUGO (S_IWUSR | S_IWGRP | S_IWOTH) #define S_IXUGO (S_IXUSR | S_IXGRP | S_IXOTH) -#endif /* _POSIXSTAT_H */ +#endif /* _POSIXSTAT_H_ */ diff --git a/lib/posixheaders/stdc.h b/lib/posixheaders/stdc.h index 5dcc32b..f1590c6 100644 --- a/lib/posixheaders/stdc.h +++ b/lib/posixheaders/stdc.h @@ -19,14 +19,15 @@ along with Bash; see the file COPYING. If not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ -#if !defined (__STDC_H__) -#define __STDC_H__ +#if !defined (_STDC_H_) +#define _STDC_H_ /* Adapted from BSD /usr/include/sys/cdefs.h. */ /* A function can be defined using prototypes and compile on both ANSI C and traditional C compilers with something like this: extern char *func __P((char *, char *, int)); */ + #if defined (__STDC__) # if !defined (__P) @@ -75,4 +76,4 @@ #endif /* !__STDC__ */ -#endif /* !__STDC_H__ */ +#endif /* !_STDC_H_ */ diff --git a/lib/readline/COPYING b/lib/readline/COPYING index 1bb82d1..a43ea21 100644 --- a/lib/readline/COPYING +++ b/lib/readline/COPYING @@ -1,46 +1,40 @@ - GNU GENERAL PUBLIC LICENSE - Version 1, February 1989 + Version 2, June 1991 - Copyright (C) 1989 Free Software Foundation, Inc. - 675 Mass Ave, Cambridge, MA 02139, USA + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 675 Mass Ave, Cambridge, MA 02139, USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. -The Free Software Foundation has exempted Bash from the requirement of -Paragraph 2c of the General Public License. This is to say, there is -no requirement for Bash to print a notice when it is started -interactively in the usual way. We made this exception because users -and standards expect shells not to print such messages. This -exception applies to any program that serves as a shell and that is -based primarily on Bash as opposed to other GNU software. - Preamble - The license agreements of most software companies try to keep users -at the mercy of those companies. By contrast, our General Public + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free -software--to make sure the software is free for all its users. The -General Public License applies to the Free Software Foundation's -software and to any other program whose authors commit to using it. -You can use it for your programs, too. +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. When we speak of free software, we are referring to freedom, not -price. Specifically, the General Public License is designed to make -sure that you have the freedom to give away or sell copies of free -software, that you receive source code or can get it if you want it, -that you can change the software or use pieces of it in new free -programs; and that you know you can do these things. +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. - For example, if you distribute copies of a such a program, whether + For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the -source code. And you must tell them their rights. +source code. And you must show them these terms so they know their +rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, @@ -53,122 +47,209 @@ want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - 0. This License Agreement applies to any program or other work which -contains a notice placed by the copyright holder saying it may be -distributed under the terms of this General Public License. The -"Program", below, refers to any such program or work, and a "work based -on the Program" means either the Program or any work containing the -Program or a portion of it, either verbatim or with modifications. Each -licensee is addressed as "you". - - 1. You may copy and distribute verbatim copies of the Program's source -code as you receive it, in any medium, provided that you conspicuously and -appropriately publish on each copy an appropriate copyright notice and -disclaimer of warranty; keep intact all the notices that refer to this -General Public License and to the absence of any warranty; and give any -other recipients of the Program a copy of this General Public License -along with the Program. You may charge a fee for the physical act of -transferring a copy. - - 2. You may modify your copy or copies of the Program or any portion of -it, and copy and distribute such modifications under the terms of Paragraph -1 above, provided that you also do the following: - - a) cause the modified files to carry prominent notices stating that - you changed the files and the date of any change; and - - b) cause the whole of any work that you distribute or publish, that - in whole or in part contains the Program or any part thereof, either - with or without modifications, to be licensed at no charge to all - third parties under the terms of this General Public License (except - that you may choose to grant warranty protection to some or all - third parties, at your option). - - c) If the modified program normally reads commands interactively when - run, you must cause it, when started running for such interactive use - in the simplest and most usual way, to print or display an - announcement including an appropriate copyright notice and a notice - that there is no warranty (or else, saying that you provide a - warranty) and that users may redistribute the program under these - conditions, and telling the user how to view a copy of this General - Public License. - - d) You may charge a fee for the physical act of transferring a - copy, and you may at your option offer warranty protection in - exchange for a fee. - -Mere aggregation of another independent work with the Program (or its -derivative) on a volume of a storage or distribution medium does not bring -the other work under the scope of these terms. + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) - 3. You may copy and distribute the Program (or a portion or derivative of -it, under Paragraph 2) in object code or executable form under the terms of -Paragraphs 1 and 2 above provided that you also do one of the following: - - a) accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of - Paragraphs 1 and 2 above; or, - - b) accompany it with a written offer, valid for at least three - years, to give any third party free (except for a nominal charge - for the cost of distribution) a complete machine-readable copy of the - corresponding source code, to be distributed under the terms of - Paragraphs 1 and 2 above; or, - - c) accompany it with the information you received as to where the - corresponding source code may be obtained. (This alternative is +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you - received the program in object code or executable form alone.) - -Source code for a work means the preferred form of the work for making -modifications to it. For an executable file, complete source code means -all the source code for all modules it contains; but, as a special -exception, it need not include source code for modules which are standard -libraries that accompany the operating system on which the executable -file runs, or for standard header files or definitions files that -accompany that operating system. - - 4. You may not copy, modify, sublicense, distribute or transfer the -Program except as expressly provided under this General Public License. -Any attempt otherwise to copy, modify, sublicense, distribute or transfer -the Program is void, and will automatically terminate your rights to use -the Program under this License. However, parties who have received -copies, or rights to use copies, from you under this General Public -License will not have their licenses terminated so long as such parties -remain in full compliance. - - 5. By copying, distributing or modifying the Program (or any work based -on the Program) you indicate your acceptance of this license to do so, -and all its terms and conditions. + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the original -licensor to copy, distribute or modify the Program subject to these -terms and conditions. You may not impose any further restrictions on the -recipients' exercise of the rights granted herein. +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. - 7. The Free Software Foundation may publish revised and/or new versions + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. -Each version is given a distinguishing version number. If the Program -specifies a version number of the license which applies to it and "any +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of -the license, you may choose any version ever published by the Free Software +this License, you may choose any version ever published by the Free Software Foundation. - 8. If you wish to incorporate parts of the Program into other free + 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author -to ask for permission. For software which is copyrighted by the Free +to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and @@ -176,7 +257,7 @@ of promoting the sharing and reuse of software generally. NO WARRANTY - 9. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED @@ -186,7 +267,7 @@ TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - 10. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING @@ -201,22 +282,21 @@ POSSIBILITY OF SUCH DAMAGES. Appendix: How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest -possible use to humanity, the best way to achieve this is to make it -free software which everyone can redistribute and change under these -terms. +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. - To do so, attach the following notices to the program. It is safest to -attach them to the start of each source file to most effectively convey -the exclusion of warranty; and each file should have at least the -"copyright" line and a pointer to where the full notice is found. + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. - Copyright (C) 19yy + Copyright (C) 19yy This program 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 1, or (at your option) - any later version. + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -232,26 +312,28 @@ Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: - Gnomovision version 69, Copyright (C) 19xx name of author + Gnomovision version 69, Copyright (C) 19yy name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. -The hypothetical commands `show w' and `show c' should show the -appropriate parts of the General Public License. Of course, the -commands you use may be called something other than `show w' and `show -c'; they could even be mouse-clicks or menu items--whatever suits your -program. +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here a sample; alter the names: +necessary. Here is a sample; alter the names: - Yoyodyne, Inc., hereby disclaims all copyright interest in the - program `Gnomovision' (a program to direct compilers to make passes - at assemblers) written by James Hacker. + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice -That's all there is to it! +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/lib/readline/Makefile b/lib/readline/Makefile deleted file mode 100644 index b36cab7..0000000 --- a/lib/readline/Makefile +++ /dev/null @@ -1,134 +0,0 @@ -## -*- text -*- #################################################### -# # -# Makefile for the GNU Readline and History Libraries. # -# # -#################################################################### - -srcdir = . -VPATH = .:$(srcdir) - -INSTALL = install -c -INSTALL_PROGRAM = ${INSTALL} -INSTALL_DATA = ${INSTALL} -m 644 - -RANLIB = ranlib -AR = ar -RM = rm -CP = cp -MV = mv - -# See the file STANDALONE for the -D defines that readline understands -DEFS = -# For libraries which include headers from other libraries. -LOCAL_INCLUDES = -I. -I.. - -CPPFLAGS = $(DEFS) $(LOCAL_INCLUDES) - -# Here is a rule for making .o files from .c files that doesn't force -# the type of the machine (like -sun3) into the flags. -.c.o: - $(CC) -c $(CPPFLAGS) $(CFLAGS) $< - -# The name of the main library target. -LIBRARY_NAME = libreadline.a - -# The C code source files for this library. -CSOURCES = $(srcdir)readline.c $(srcdir)funmap.c $(srcdir)keymaps.c \ - $(srcdir)vi_mode.c $(srcdir)parens.c $(srcdir)rltty.c \ - $(srcdir)complete.c $(srcdir)bind.c $(srcdir)isearch.c \ - $(srcdir)display.c $(srcdir)signals.c $(srcdir)emacs_keymap.c \ - $(srcdir)vi_keymap.c $(srcdir)history.c $(srcdir)tilde.c \ - $(srcdir)xmalloc.c - -# The header files for this library. -HSOURCES = readline.h rldefs.h chardefs.h keymaps.h history.h \ - posixstat.h tilde.h rlconf.h - -OBJECTS = readline.o vi_mode.o funmap.o keymaps.o parens.o search.o \ - rltty.o complete.o bind.o isearch.o display.o signals.o \ - history.o tilde.o xmalloc.o - -# The texinfo files which document this library. -DOCSOURCE = doc/rlman.texinfo doc/rltech.texinfo doc/rluser.texinfo -DOCOBJECT = doc/readline.dvi -DOCSUPPORT = doc/Makefile -DOCUMENTATION = $(DOCSOURCE) $(DOCOBJECT) $(DOCSUPPORT) - -SUPPORT = Makefile ChangeLog $(DOCSUPPORT) examples/[-a-z.]* - -SOURCES = $(CSOURCES) $(HSOURCES) $(DOCSOURCE) - -THINGS_TO_TAR = $(SOURCES) $(SUPPORT) - -########################################################################## - -all: libreadline.a libhistory.a - -libreadline.a: $(OBJECTS) - $(RM) -f $@ - $(AR) cq $@ $(OBJECTS) - -[ -n "$(RANLIB)" ] && $(RANLIB) $@ - -libhistory.a: history.o - $(RM) -f $@ - $(AR) cq $@ history.o - -[ -n "$(RANLIB)" ] && $(RANLIB) $@ - -documentation: force - [ ! -d doc ] && mkdir doc - (if [ -d doc ]; then cd doc; $(MAKE) $(MFLAGS); fi) - -force: - -# The rule for 'includes' is written funny so that the if statement -# always returns TRUE unless there really was an error installing the -# include files. -install: installdirs libreadline.a - ${INSTALL_DATA} readline.h keymaps.h chardefs.h history.h \ - $(incdir)/readline - -${MV} $(libdir)/libreadline.a $(libdir)/libreadline.old - ${INSTALL_DATA} libreadline.a $(bindir)/libreadline.a - -[ -n "$(RANLIB)" ] && $(RANLIB) -t $(bindir)/libreadline.a - -installdirs: - [ ! -d $(incdir)/readline ] && { \ - mkdir $(incdir)/readline && chmod chmod 755 $(incdir)/readline; } - -uninstall: - cd $(incdir)/readline && ${RM} -f ${INSTALLED_HEADERS} - cd $(libdir) && ${RM} -f libreadline.a libreadline.old - -tags: force - etags $(CSOURCES) $(HSOURCES) - -TAGS: force - ctags -x $(CSOURCES) $(HSOURCES) > $@ - -readline: readline.h rldefs.h chardefs.h -readline: $(OBJECTS) - $(CC) $(CFLAGS) $(CPPFLAGS) $(READLINE_DEFINES) \ - $(LOCAL_INCLUDES) -DTEST -o readline readline.c vi_mode.o funmap.o \ - keymaps.o -ltermcap - -clean: - $(RM) -f $(OBJECTS) libreadline.a libhistory.a - (if [ -d doc ]; then cd doc; $(MAKE) $(MFLAGS) $@; fi) - -maintainer-clean realclean distclean mostlyclean: clean - (if [ -d doc ]; then cd doc; $(MAKE) $(MFLAGS) $@; fi) - -# Dependencies -readline.o: readline.c readline.h rldefs.h rlconf.h chardefs.h -readline.o: keymaps.h history.h -vi_mode.o: rldefs.h rlconf.h readline.h history.h -funmap.o: funmap.c readline.h rlconf.h -keymaps.o: keymaps.c emacs_keymap.c vi_keymap.c keymaps.h chardefs.h rlconf.h -history.o: history.h memalloc.h -isearch.o: memalloc.h readline.h history.h -search.o: memalloc.h readline.h history.h -display.o: readline.h history.h rldefs.h rlconf.h -complete.o: readline.h rldefs.h rlconf.h -rltty.o: rldefs.h rlconf.h readline.h -bind.o: rldefs.h rlconf.h readline.h history.h -signals.o: rldefs.h rlconf.h readline.h history.h -parens.o: readline.h diff --git a/lib/readline/Makefile.in b/lib/readline/Makefile.in new file mode 100644 index 0000000..c5ac183 --- /dev/null +++ b/lib/readline/Makefile.in @@ -0,0 +1,192 @@ +## -*- text -*- #################################################### +# # +# Makefile for the GNU Readline and History Libraries. # +# # +#################################################################### + +srcdir = @srcdir@ +VPATH = .:@srcdir@ +topdir = @top_srcdir@ +BUILD_DIR = @BUILD_DIR@ + +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_DATA = @INSTALL_DATA@ + +CC = @CC@ +RANLIB = @RANLIB@ +AR = @AR@ +RM = rm -f +CP = cp +MV = mv + +# See the file STANDALONE for the -D defines that readline understands + +CFLAGS = @CFLAGS@ +LOCAL_CFLAGS = @LOCAL_CFLAGS@ +CPPFLAGS = @CPPFLAGS@ +LDFLAGS = @LDFLAGS@ + +DEFS = @DEFS@ + +INCLUDES = -I. -I$(BUILD_DIR) -I$(topdir) -I$(topdir)/lib + +CCFLAGS = $(DEFS) $(APP_CFLAGS) $(CPPFLAGS) ${INCLUDES} $(LOCAL_CFLAGS) $(CFLAGS) + +# Here is a rule for making .o files from .c files that doesn't force +# the type of the machine (like -sun3) into the flags. +.c.o: + $(CC) -c $(CCFLAGS) $< + +# The name of the main library target. +LIBRARY_NAME = libreadline.a + +# The C code source files for this library. +CSOURCES = $(srcdir)/readline.c $(srcdir)/funmap.c $(srcdir)/keymaps.c \ + $(srcdir)/vi_mode.c $(srcdir)/parens.c $(srcdir)/rltty.c \ + $(srcdir)/complete.c $(srcdir)/bind.c $(srcdir)/isearch.c \ + $(srcdir)/display.c $(srcdir)/signals.c $(srcdir)/emacs_keymap.c \ + $(srcdir)/vi_keymap.c $(srcdir)/util.c $(srcdir)/kill.c \ + $(srcdir)/undo.c $(srcdir)/macro.c $(srcdir)/input.c \ + $(srcdir)/callback.c $(srcdir)/terminal.c $(srcdir)/xmalloc.c \ + $(srcdir)/history.c $(srcdir)/histsearch.c $(srcdir)/histexpand.c \ + $(srcdir)/histfile.c $(srcdir)/nls.c \ + $(srcdir)/tilde.c \ + +# The header files for this library. +HSOURCES = readline.h rldefs.h chardefs.h keymaps.h history.h histlib.h \ + posixstat.h tilde.h rlconf.h tcap.h + +HISTOBJ = history.o histexpand.o histfile.o histsearch.o +TILDEOBJ= tilde.o +OBJECTS = readline.o vi_mode.o funmap.o keymaps.o parens.o search.o \ + rltty.o complete.o bind.o isearch.o display.o signals.o \ + util.o kill.o undo.o macro.o input.o callback.o terminal.o \ + nls.o xmalloc.o \ + $(HISTOBJ) $(TILDEOBJ) + +# The texinfo files which document this library. +DOCSOURCE = doc/rlman.texinfo doc/rltech.texinfo doc/rluser.texinfo +DOCOBJECT = doc/readline.dvi +DOCSUPPORT = doc/Makefile +DOCUMENTATION = $(DOCSOURCE) $(DOCOBJECT) $(DOCSUPPORT) + +SUPPORT = Makefile ChangeLog $(DOCSUPPORT) examples/[-a-z.]* + +SOURCES = $(CSOURCES) $(HSOURCES) $(DOCSOURCE) + +THINGS_TO_TAR = $(SOURCES) $(SUPPORT) + +INSTALLED_HEADERS = readline.h chardefs.h keymaps.h history.h tilde.h + +########################################################################## + +all: libreadline.a libhistory.a + +libreadline.a: $(OBJECTS) + $(RM) -f $@ + $(AR) cr $@ $(OBJECTS) + -test -n "$(RANLIB)" && $(RANLIB) $@ + +libhistory.a: $(HISTOBJ) xmalloc.o + $(RM) -f $@ + $(AR) cr $@ $(HISTOBJ) xmalloc.o + -test -n "$(RANLIB)" && $(RANLIB) $@ + +documentation: force + test -d doc || mkdir doc + -( cd doc && $(MAKE) $(MFLAGS) ) + +force: + +# The rule for 'includes' is written funny so that the if statement +# always returns TRUE unless there really was an error installing the +# include files. +install: installdirs libreadline.a + for file in $(INSTALLED_HEADERS) ; do \ + $(INSTALL_DATA) $(srcdir)/$$file $(includedir)/readline ; \ + done + -${MV} $(libdir)/libreadline.a $(libdir)/libreadline.old + ${INSTALL_DATA} libreadline.a $(libdir)/libreadline.a + -test -n "$(RANLIB)" && $(RANLIB) -t $(bindir)/libreadline.a + +installdirs: $(topdir)/support/mkdirs + $(SHELL) $(topdir)/support/mkdirs $(includedir) \ + $(includedir)/readline $(libdir) $(infodir) $(man3dir) + +uninstall: + cd $(includedir)/readline && ${RM} -f ${INSTALLED_HEADERS} + cd $(libdir) && ${RM} -f libreadline.a libreadline.old + +tags: force + etags $(CSOURCES) $(HSOURCES) + +TAGS: force + ctags -x $(CSOURCES) $(HSOURCES) > $@ + +readline: readline.h rldefs.h chardefs.h +readline: $(OBJECTS) + $(CC) $(CFLAGS) $(CPPFLAGS) $(READLINE_DEFINES) \ + $(LOCAL_INCLUDES) -DTEST -o readline readline.c vi_mode.o funmap.o \ + keymaps.o -ltermcap + +clean: force + $(RM) $(OBJECTS) *.a + -( cd doc && $(MAKE) $(MFLAGS) $@ ) + +distclean realclean maintainer-clean: clean + -( cd doc && $(MAKE) $(MFLAGS) $@ ) + $(RM) Makefile + +mostlyclean: clean + -( cd doc && $(MAKE) $(MFLAGS) $@ ) + +# Dependencies +readline.o: readline.c readline.h rldefs.h rlconf.h chardefs.h tcap.h +readline.o: keymaps.h history.h +vi_mode.o: rldefs.h rlconf.h readline.h history.h +funmap.o: funmap.c readline.h rlconf.h +keymaps.o: keymaps.c emacs_keymap.c vi_keymap.c keymaps.h chardefs.h rlconf.h +history.o: history.h histlib.h +histexpand.o: history.h histlib.h +histsearch.o: history.h histlib.h +histfile.o: history.h histlib.h +isearch.o: readline.h history.h +search.o: readline.h history.h +display.o: readline.h history.h rldefs.h rlconf.h tcap.h +complete.o: readline.h rldefs.h rlconf.h posixdir.h posixstat.h +rltty.o: rldefs.h rlconf.h readline.h rltty.h +bind.o: rldefs.h rlconf.h readline.h history.h +signals.o: rldefs.h rlconf.h readline.h history.h +parens.o: readline.h +kill.o: rldefs.h rlconf.h readline.h history.h +macro.o: rldefs.h rlconf.h readline.h history.h +undo.o: rldefs.h rlconf.h readline.h history.h +input.o: rldefs.h rlconf.h readline.h history.h +callback.o: rlconf.h rldefs.h readline.h +terminal.o: rlconf.h rldefs.h readline.h tcap.h history.h + +bind.o: $(BUILD_DIR)/config.h +callback.o: $(BUILD_DIR)/config.h +complete.o: $(BUILD_DIR)/config.h +display.o: $(BUILD_DIR)/config.h +funmap.o: $(BUILD_DIR)/config.h +histexpand.o: $(BUILD_DIR)/config.h +histfile.o: $(BUILD_DIR)/config.h +history.o: $(BUILD_DIR)/config.h +histsearch.o: $(BUILD_DIR)/config.h +input.o: $(BUILD_DIR)/config.h +isearch.o: $(BUILD_DIR)/config.h +keymaps.o: $(BUILD_DIR)/config.h +kill.o: $(BUILD_DIR)/config.h +macro.o: $(BUILD_DIR)/config.h +parens.o: $(BUILD_DIR)/config.h +readline.o: $(BUILD_DIR)/config.h +rltty.o: $(BUILD_DIR)/config.h +search.o: $(BUILD_DIR)/config.h +signals.o: $(BUILD_DIR)/config.h +tilde.o: $(BUILD_DIR)/config.h +undo.o: $(BUILD_DIR)/config.h +util.o: $(BUILD_DIR)/config.h +vi_mode.o: $(BUILD_DIR)/config.h +xmalloc.o: $(BUILD_DIR)/config.h diff --git a/lib/readline/STANDALONE b/lib/readline/STANDALONE index c1387f3..f999e8d 100644 --- a/lib/readline/STANDALONE +++ b/lib/readline/STANDALONE @@ -15,6 +15,7 @@ HAVE_DIRENT_H exists and is usable HAVE_SYS_PTEM_H exists HAVE_SYS_PTE_H exists HAVE_SYS_STREAM_H exists +HAVE_SYS_SELECT_H exists System-specific options: diff --git a/lib/readline/bind.c b/lib/readline/bind.c index 8821599..bd899ca 100644 --- a/lib/readline/bind.c +++ b/lib/readline/bind.c @@ -21,13 +21,16 @@ 675 Mass Ave, Cambridge, MA 02139, USA. */ #define READLINE_LIBRARY +#if defined (HAVE_CONFIG_H) +# include +#endif + #include #include #include -#if !defined (NO_SYS_FILE) +#if defined (HAVE_SYS_FILE_H) # include -#endif /* !NO_SYS_FILE */ -#include +#endif /* HAVE_SYS_FILE_H */ #if defined (HAVE_UNISTD_H) # include @@ -39,8 +42,9 @@ # include "ansi_stdlib.h" #endif /* HAVE_STDLIB_H */ +#include #include -/* Not all systems declare ERRNO in errno.h... and some systems #define it! */ + #if !defined (errno) extern int errno; #endif /* !errno */ @@ -65,6 +69,8 @@ extern int _rl_meta_flag; extern int _rl_convert_meta_chars_to_ascii; extern int _rl_output_meta_chars; extern int _rl_complete_show_all; +extern int _rl_complete_mark_directories; +extern int _rl_enable_keypad; #if defined (PAREN_MATCHING) extern int rl_blink_matching_paren; #endif /* PAREN_MATCHING */ @@ -73,36 +79,31 @@ extern int rl_visible_stats; #endif /* VISIBLE_STATS */ extern int rl_complete_with_tilde_expansion; extern int rl_completion_query_items; -#if defined (VI_MODE) -extern char *rl_vi_comment_begin; -#endif +extern int rl_inhibit_completion; +extern char *_rl_comment_begin; extern int rl_explicit_arg; extern int rl_editing_mode; -extern unsigned short _rl_parsing_conditionalized_out; +extern unsigned char _rl_parsing_conditionalized_out; extern Keymap _rl_keymap; extern char *possible_control_prefixes[], *possible_meta_prefixes[]; extern char **rl_funmap_names (); +extern int rl_add_funmap_entry (); + +extern char *_rl_strindex (); + +/* Variables exported by this file. */ +Keymap rl_binding_keymap; /* Forward declarations */ void rl_set_keymap_from_edit_mode (); static int glean_key_from_name (); +static int substring_member_of_array (); -#if defined (HAVE_STRCASECMP) -#define stricmp strcasecmp -#define strnicmp strncasecmp -#else -static int stricmp (), strnicmp (); -#endif - -#if defined (STATIC_MALLOC) -static char *xmalloc (), *xrealloc (); -#else extern char *xmalloc (), *xrealloc (); -#endif /* STATIC_MALLOC */ /* **************************************************************** */ /* */ @@ -113,6 +114,7 @@ extern char *xmalloc (), *xrealloc (); /* rl_add_defun (char *name, Function *function, int key) Add NAME to the list of named functions. Make FUNCTION be the function that gets called. If KEY is not -1, then bind it. */ +int rl_add_defun (name, function, key) char *name; Function *function; @@ -150,6 +152,7 @@ rl_bind_key (key, function) _rl_keymap[key].type = ISFUNC; _rl_keymap[key].function = function; + rl_binding_keymap = _rl_keymap; return (0); } @@ -162,8 +165,9 @@ rl_bind_key_in_map (key, function, map) Keymap map; { int result; - Keymap oldmap = _rl_keymap; + Keymap oldmap; + oldmap = _rl_keymap; _rl_keymap = map; result = rl_bind_key (key, function); _rl_keymap = oldmap; @@ -192,6 +196,7 @@ rl_unbind_key_in_map (key, map) /* Bind the key sequence represented by the string KEYSEQ to FUNCTION. This makes new keymaps as necessary. The initial place to do bindings is in MAP. */ +int rl_set_key (keyseq, function, map) char *keyseq; Function *function; @@ -203,6 +208,7 @@ rl_set_key (keyseq, function, map) /* Bind the key sequence represented by the string KEYSEQ to the string of characters MACRO. This makes new keymaps as necessary. The initial place to do bindings is in MAP. */ +int rl_macro_bind (keyseq, macro, map) char *keyseq, *macro; Keymap map; @@ -226,6 +232,7 @@ rl_macro_bind (keyseq, macro, map) pointed to by DATA, right now this can be a function (ISFUNC), a macro (ISMACR), or a keymap (ISKMAP). This makes new keymaps as necessary. The initial place to do bindings is in MAP. */ +int rl_generic_bind (type, keyseq, data, map) int type; char *keyseq, *data; @@ -286,6 +293,8 @@ rl_generic_bind (type, keyseq, data, map) map[ic].function = KEYMAP_TO_FUNCTION (data); map[ic].type = type; } + + rl_binding_keymap = map; } free (keys); return 0; @@ -294,30 +303,30 @@ rl_generic_bind (type, keyseq, data, map) /* Translate the ASCII representation of SEQ, stuffing the values into ARRAY, an array of characters. LEN gets the final length of ARRAY. Return non-zero if there was an error parsing SEQ. */ +int rl_translate_keyseq (seq, array, len) char *seq, *array; int *len; { - register int i, c, l = 0; + register int i, c, l; - for (i = 0; c = seq[i]; i++) + for (i = l = 0; c = seq[i]; i++) { if (c == '\\') { c = seq[++i]; - if (!c) + if (c == 0) break; - if (((c == 'C' || c == 'M') && seq[i + 1] == '-') || - (c == 'e')) + if (((c == 'C' || c == 'M') && seq[i + 1] == '-') || (c == 'e')) { /* Handle special case of backwards define. */ if (strncmp (&seq[i], "C-\\M-", 5) == 0) { array[l++] = ESC; i += 5; - array[l++] = CTRL (to_upper (seq[i])); + array[l++] = CTRL (_rl_to_upper (seq[i])); if (!seq[i]) i--; continue; @@ -327,16 +336,13 @@ rl_translate_keyseq (seq, array, len) { case 'M': i++; - array[l++] = ESC; + array[l++] = ESC; /* XXX */ break; case 'C': i += 2; /* Special hack for C-?... */ - if (seq[i] == '?') - array[l++] = RUBOUT; - else - array[l++] = CTRL (to_upper (seq[i])); + array[l++] = (seq[i] == '?') ? RUBOUT : CTRL (_rl_to_upper (seq[i])); break; case 'e': @@ -354,6 +360,52 @@ rl_translate_keyseq (seq, array, len) return (0); } +char * +rl_untranslate_keyseq (seq) + int seq; +{ + static char kseq[16]; + int i, c; + + i = 0; + c = seq; + if (META_CHAR (c)) + { + kseq[i++] = '\\'; + kseq[i++] = 'M'; + kseq[i++] = '-'; + c = UNMETA (c); + } + else if (CTRL_CHAR (c)) + { + kseq[i++] = '\\'; + kseq[i++] = 'C'; + kseq[i++] = '-'; + c = UNCTRL (c); + } + else if (c == RUBOUT) + { + kseq[i++] = '\\'; + kseq[i++] = 'C'; + kseq[i++] = '-'; + c = '?'; + } + + if (c == ESC) + { + kseq[i++] = '\\'; + kseq[i++] = 'e'; + } + else if (c == '\\' || c == '"') + { + kseq[i++] = '\\'; + } + + kseq[i++] = (unsigned char) c; + kseq[i] = '\0'; + return kseq; +} + /* Return a pointer to the function that STRING represents. If STRING doesn't have a matching function, then a NULL pointer is returned. */ @@ -366,7 +418,7 @@ rl_named_function (string) rl_initialize_funmap (); for (i = 0; funmap[i]; i++) - if (stricmp (funmap[i]->name, string) == 0) + if (_rl_stricmp (funmap[i]->name, string) == 0) return (funmap[i]->function); return ((Function *)NULL); } @@ -435,7 +487,12 @@ rl_function_of_keyseq (keyseq, map, type) /* The last key bindings file read. */ static char *last_readline_init_file = (char *)NULL; +/* The file we're currently reading key bindings from. */ +static char *current_readline_init_file; +static int current_readline_init_lineno; + /* Re-read the current keybindings file. */ +int rl_re_read_init_file (count, ignore) int count, ignore; { @@ -462,18 +519,19 @@ rl_read_init_file (filename) int file; /* Default the filename. */ - if (!filename) + if (filename == 0) { filename = last_readline_init_file; - if (!filename) + if (filename == 0) filename = getenv ("INPUTRC"); - if (!filename) + if (filename == 0) filename = DEFAULT_INPUTRC; } - if (!*filename) + if (*filename == 0) filename = DEFAULT_INPUTRC; + current_readline_init_file = filename; openname = tilde_expand (filename); if ((stat (openname, &finfo) < 0) || @@ -503,6 +561,7 @@ rl_read_init_file (filename) /* Loop over the lines in the file. Lines that start with `#' are comments; all other lines are commands for readline initialization. */ + current_readline_init_lineno = 1; line = buffer; end = buffer + finfo.st_size; while (line < end) @@ -526,11 +585,21 @@ rl_read_init_file (filename) /* Move to the next line. */ line += i + 1; + current_readline_init_lineno++; } free (buffer); return (0); } +static void +_rl_init_file_error (msg) + char *msg; +{ + fprintf (stderr, "readline: %s: line %d: %s\n", current_readline_init_file, + current_readline_init_lineno, + msg); +} + /* **************************************************************** */ /* */ /* Parser Directives */ @@ -544,8 +613,8 @@ char *rl_readline_name = "other"; /* Stack of previous values of parsing_conditionalized_out. */ static unsigned char *if_stack = (unsigned char *)NULL; -static int if_stack_depth = 0; -static int if_stack_size = 0; +static int if_stack_depth; +static int if_stack_size; /* Push _rl_parsing_conditionalized_out, and set parser state based on ARGS. */ @@ -579,7 +648,7 @@ parser_if (args) /* Handle "if term=foo" and "if mode=emacs" constructs. If this isn't term=foo, or mode=emacs, then check to see if the first word in ARGS is the same as the value stored in rl_readline_name. */ - if (rl_terminal_name && strnicmp (args, "term=", 5) == 0) + if (rl_terminal_name && _rl_strnicmp (args, "term=", 5) == 0) { char *tem, *tname; @@ -593,35 +662,28 @@ parser_if (args) if someone has a `sun-cmd' and does not want to have bindings that will be executed if the terminal is a `sun', they can put `$if term=sun-cmd' into their .inputrc. */ - if ((stricmp (args + 5, tname) == 0) || - (stricmp (args + 5, rl_terminal_name) == 0)) - _rl_parsing_conditionalized_out = 0; - else - _rl_parsing_conditionalized_out = 1; - + _rl_parsing_conditionalized_out = _rl_stricmp (args + 5, tname) && + _rl_stricmp (args + 5, rl_terminal_name); free (tname); } #if defined (VI_MODE) - else if (strnicmp (args, "mode=", 5) == 0) + else if (_rl_strnicmp (args, "mode=", 5) == 0) { int mode; - if (stricmp (args + 5, "emacs") == 0) + if (_rl_stricmp (args + 5, "emacs") == 0) mode = emacs_mode; - else if (stricmp (args + 5, "vi") == 0) + else if (_rl_stricmp (args + 5, "vi") == 0) mode = vi_mode; else mode = no_mode; - if (mode == rl_editing_mode) - _rl_parsing_conditionalized_out = 0; - else - _rl_parsing_conditionalized_out = 1; + _rl_parsing_conditionalized_out = mode != rl_editing_mode; } #endif /* VI_MODE */ /* Check to see if the first word in ARGS is the same as the value stored in rl_readline_name. */ - else if (stricmp (args, rl_readline_name) == 0) + else if (_rl_stricmp (args, rl_readline_name) == 0) _rl_parsing_conditionalized_out = 0; else _rl_parsing_conditionalized_out = 1; @@ -705,7 +767,7 @@ handle_parser_directive (statement) /* Lookup the command, and act on it. */ for (i = 0; parser_directives[i].name; i++) - if (stricmp (directive, parser_directives[i].name) == 0) + if (_rl_stricmp (directive, parser_directives[i].name) == 0) { (*parser_directives[i].function) (args); return (0); @@ -715,12 +777,11 @@ handle_parser_directive (statement) return (1); } -static int substring_member_of_array (); - /* Read the binding command from STRING and perform it. A key binding command looks like: Keyname: function-name\0, a variable binding command looks like: set variable value. A new-style keybinding looks like "\C-x\C-x": exchange-point-and-mark. */ +int rl_parse_and_bind (string) char *string; { @@ -770,6 +831,12 @@ rl_parse_and_bind (string) if (c == '"') break; } + /* If we didn't find a closing quote, abort the line. */ + if (string[i] == '\0') + { + _rl_init_file_error ("no closing `\"' in key binding"); + return 1; + } } /* Advance to the colon (:) or whitespace which separates the two objects. */ @@ -786,7 +853,7 @@ rl_parse_and_bind (string) string[i++] = '\0'; /* If this is a command to set a variable, then do that. */ - if (stricmp (string, "set") == 0) + if (_rl_stricmp (string, "set") == 0) { char *var = string + i; char *value; @@ -915,7 +982,7 @@ rl_parse_and_bind (string) /* Add in control and meta bits. */ if (substring_member_of_array (string, possible_control_prefixes)) - key = CTRL (to_upper (key)); + key = CTRL (_rl_to_upper (key)); if (substring_member_of_array (string, possible_meta_prefixes)) key = META (key); @@ -934,7 +1001,7 @@ rl_parse_and_bind (string) } #if defined (PREFIX_META_HACK) /* Ugly, but working hack to keep prefix-meta around. */ - else if (stricmp (funname, "prefix-meta") == 0) + else if (_rl_stricmp (funname, "prefix-meta") == 0) { char seq[2]; @@ -956,22 +1023,27 @@ static struct { char *name; int *value; } boolean_varlist [] = { - { "horizontal-scroll-mode", &_rl_horizontal_scroll_mode }, - { "mark-modified-lines", &_rl_mark_modified_lines }, - { "meta-flag", &_rl_meta_flag }, #if defined (PAREN_MATCHING) { "blink-matching-paren", &rl_blink_matching_paren }, #endif { "convert-meta", &_rl_convert_meta_chars_to_ascii }, - { "show-all-if-ambiguous", &_rl_complete_show_all }, + { "disable-completion", &rl_inhibit_completion }, + { "enable-keypad", &_rl_enable_keypad }, + { "expand-tilde", &rl_complete_with_tilde_expansion }, + { "horizontal-scroll-mode", &_rl_horizontal_scroll_mode }, + { "input-meta", &_rl_meta_flag }, + { "mark-directories", &_rl_complete_mark_directories }, + { "mark-modified-lines", &_rl_mark_modified_lines }, + { "meta-flag", &_rl_meta_flag }, { "output-meta", &_rl_output_meta_chars }, + { "show-all-if-ambiguous", &_rl_complete_show_all }, #if defined (VISIBLE_STATS) { "visible-stats", &rl_visible_stats }, #endif /* VISIBLE_STATS */ - { "expand-tilde", &rl_complete_with_tilde_expansion }, { (char *)NULL, (int *)NULL } }; +int rl_variable_bind (name, value) char *name, *value; { @@ -980,15 +1052,12 @@ rl_variable_bind (name, value) /* Check for simple variables first. */ for (i = 0; boolean_varlist[i].name; i++) { - if (stricmp (name, boolean_varlist[i].name) == 0) + if (_rl_stricmp (name, boolean_varlist[i].name) == 0) { /* A variable is TRUE if the "value" is "on", "1" or "". */ - if ((!*value) || - (stricmp (value, "On") == 0) || - (value[0] == '1' && value[1] == '\0')) - *boolean_varlist[i].value = 1; - else - *boolean_varlist[i].value = 0; + *boolean_varlist[i].value = *value == 0 || + _rl_stricmp (value, "on") == 0 || + (value[0] == '1' && value[1] == '\0'); return 0; } } @@ -996,16 +1065,16 @@ rl_variable_bind (name, value) /* Not a boolean variable, so check for specials. */ /* Editing mode change? */ - if (stricmp (name, "editing-mode") == 0) + if (_rl_stricmp (name, "editing-mode") == 0) { - if (strnicmp (value, "vi", 2) == 0) + if (_rl_strnicmp (value, "vi", 2) == 0) { #if defined (VI_MODE) _rl_keymap = vi_insertion_keymap; rl_editing_mode = vi_mode; #endif /* VI_MODE */ } - else if (strnicmp (value, "emacs", 5) == 0) + else if (_rl_strnicmp (value, "emacs", 5) == 0) { _rl_keymap = emacs_standard_keymap; rl_editing_mode = emacs_mode; @@ -1013,19 +1082,17 @@ rl_variable_bind (name, value) } /* Comment string change? */ - else if (stricmp (name, "comment-begin") == 0) + else if (_rl_stricmp (name, "comment-begin") == 0) { -#if defined (VI_MODE) if (*value) { - if (rl_vi_comment_begin) - free (rl_vi_comment_begin); + if (_rl_comment_begin) + free (_rl_comment_begin); - rl_vi_comment_begin = savestring (value); + _rl_comment_begin = savestring (value); } -#endif /* VI_MODE */ } - else if (stricmp (name, "completion-query-items") == 0) + else if (_rl_stricmp (name, "completion-query-items") == 0) { int nval = 100; if (*value) @@ -1036,31 +1103,31 @@ rl_variable_bind (name, value) } rl_completion_query_items = nval; } - else if (stricmp (name, "keymap") == 0) + else if (_rl_stricmp (name, "keymap") == 0) { Keymap kmap; kmap = rl_get_keymap_by_name (value); if (kmap) rl_set_keymap (kmap); } - else if (stricmp (name, "bell-style") == 0) + else if (_rl_stricmp (name, "bell-style") == 0) { if (!*value) _rl_bell_preference = AUDIBLE_BELL; else { - if (stricmp (value, "none") == 0 || stricmp (value, "off") == 0) + if (_rl_stricmp (value, "none") == 0 || _rl_stricmp (value, "off") == 0) _rl_bell_preference = NO_BELL; - else if (stricmp (value, "audible") == 0 || stricmp (value, "on") == 0) + else if (_rl_stricmp (value, "audible") == 0 || _rl_stricmp (value, "on") == 0) _rl_bell_preference = AUDIBLE_BELL; - else if (stricmp (value, "visible") == 0) + else if (_rl_stricmp (value, "visible") == 0) _rl_bell_preference = VISIBLE_BELL; } } - else if (stricmp (name, "prefer-visible-bell") == 0) + else if (_rl_stricmp (name, "prefer-visible-bell") == 0) { /* Backwards compatibility. */ - if (*value && (stricmp (value, "on") == 0 || + if (*value && (_rl_stricmp (value, "on") == 0 || (*value == '1' && !value[1]))) _rl_bell_preference = VISIBLE_BELL; else @@ -1100,7 +1167,7 @@ glean_key_from_name (name) register int i; for (i = 0; name_key_alist[i].name; i++) - if (stricmp (name, name_key_alist[i].name) == 0) + if (_rl_stricmp (name, name_key_alist[i].name) == 0) return (name_key_alist[i].value); return (*(unsigned char *)name); /* XXX was return (*name) */ @@ -1136,6 +1203,17 @@ rl_get_keymap_by_name (name) return ((Keymap) NULL); } +char * +rl_get_keymap_name (map) + Keymap map; +{ + register int i; + for (i = 0; keymap_names[i].name; i++) + if (map == keymap_names[i].map) + return (keymap_names[i].name); + return ((char *)NULL); +} + void rl_set_keymap (map) Keymap map; @@ -1160,7 +1238,20 @@ rl_set_keymap_from_edit_mode () _rl_keymap = vi_insertion_keymap; #endif /* VI_MODE */ } - + +char * +rl_get_keymap_name_from_edit_mode () +{ + if (rl_editing_mode == emacs_mode) + return "emacs"; +#if defined (VI_MODE) + else if (rl_editing_mode == vi_mode) + return "vi"; +#endif /* VI_MODE */ + else + return "none"; +} + /* **************************************************************** */ /* */ /* Key Binding and Function Information */ @@ -1174,8 +1265,7 @@ rl_set_keymap_from_edit_mode () /* Print the names of functions known to Readline. */ void -rl_list_funmap_names (count, ignore) - int count, ignore; +rl_list_funmap_names () { register int i; char **funmap_names; @@ -1191,6 +1281,67 @@ rl_list_funmap_names (count, ignore) free (funmap_names); } +static char * +_rl_get_keyname (key) + int key; +{ + char *keyname; + int i, c; + + keyname = (char *)xmalloc (8); + + c = key; + /* Since this is going to be used to write out keysequence-function + pairs for possible inclusion in an inputrc file, we don't want to + do any special meta processing on KEY. */ + +#if 0 + /* We might want to do this, but the old version of the code did not. */ + + /* If this is an escape character, we don't want to do any more processing. + Just add the special ESC key sequence and return. */ + if (c == ESC) + { + keyseq[0] = '\\'; + keyseq[1] = 'e'; + keyseq[2] = '\0'; + return keyseq; + } +#endif + + /* RUBOUT is translated directly into \C-? */ + if (key == RUBOUT) + { + keyname[0] = '\\'; + keyname[1] = 'C'; + keyname[2] = '-'; + keyname[3] = '?'; + keyname[4] = '\0'; + return keyname; + } + + i = 0; + /* Now add special prefixes needed for control characters. This can + potentially change C. */ + if (CTRL_CHAR (c)) + { + keyname[i++] = '\\'; + keyname[i++] = 'C'; + keyname[i++] = '-'; + c = _rl_to_lower (UNCTRL (c)); + } + + /* Now, if the character needs to be quoted with a backslash, do that. */ + if (c == '\\' || c == '"') + keyname[i++] = '\\'; + + /* Now add the key, terminate the string, and return it. */ + keyname[i++] = (char) c; + keyname[i] = '\0'; + + return keyname; +} + /* Return a NULL terminated array of strings which represent the key sequences that are used to invoke FUNCTION in MAP. */ char ** @@ -1205,7 +1356,7 @@ rl_invoking_keyseqs_in_map (function, map) result = (char **)NULL; result_index = result_size = 0; - for (key = 0; key < 128; key++) + for (key = 0; key < KEYMAP_SIZE; key++) { switch (map[key].type) { @@ -1217,27 +1368,15 @@ rl_invoking_keyseqs_in_map (function, map) then add the current KEY to the list of invoking keys. */ if (map[key].function == function) { - char *keyname = (char *)xmalloc (5); + char *keyname; - if (CTRL_CHAR (key)) - sprintf (keyname, "\\C-%c", to_lower (UNCTRL (key))); - else if (key == RUBOUT) - sprintf (keyname, "\\C-?"); - else if (key == '\\' || key == '"') - { - keyname[0] = '\\'; - keyname[1] = (char) key; - keyname[2] = '\0'; - } - else - { - keyname[0] = (char) key; - keyname[1] = '\0'; - } + keyname = _rl_get_keyname (key); if (result_index + 2 > result_size) - result = (char **) xrealloc - (result, (result_size += 10) * sizeof (char *)); + { + result_size += 10; + result = (char **) xrealloc (result, result_size * sizeof (char *)); + } result[result_index++] = keyname; result[result_index] = (char *)NULL; @@ -1246,53 +1385,56 @@ rl_invoking_keyseqs_in_map (function, map) case ISKMAP: { - char **seqs = (char **)NULL; + char **seqs; + register int i; /* Find the list of keyseqs in this map which have FUNCTION as their target. Add the key sequences found to RESULT. */ if (map[key].function) seqs = rl_invoking_keyseqs_in_map (function, FUNCTION_TO_KEYMAP (map, key)); + else + break; + + if (seqs == 0) + break; - if (seqs) + for (i = 0; seqs[i]; i++) { - register int i; + char *keyname = (char *)xmalloc (6 + strlen (seqs[i])); + + if (key == ESC) + sprintf (keyname, "\\e"); + else if (CTRL_CHAR (key)) + sprintf (keyname, "\\C-%c", _rl_to_lower (UNCTRL (key))); + else if (key == RUBOUT) + sprintf (keyname, "\\C-?"); + else if (key == '\\' || key == '"') + { + keyname[0] = '\\'; + keyname[1] = (char) key; + keyname[2] = '\0'; + } + else + { + keyname[0] = (char) key; + keyname[1] = '\0'; + } + + strcat (keyname, seqs[i]); + free (seqs[i]); - for (i = 0; seqs[i]; i++) + if (result_index + 2 > result_size) { - char *keyname = (char *)xmalloc (6 + strlen (seqs[i])); - - if (key == ESC) - sprintf (keyname, "\\e"); - else if (CTRL_CHAR (key)) - sprintf (keyname, "\\C-%c", to_lower (UNCTRL (key))); - else if (key == RUBOUT) - sprintf (keyname, "\\C-?"); - else if (key == '\\' || key == '"') - { - keyname[0] = '\\'; - keyname[1] = (char) key; - keyname[2] = '\0'; - } - else - { - keyname[0] = (char) key; - keyname[1] = '\0'; - } - - strcat (keyname, seqs[i]); - free (seqs[i]); - - if (result_index + 2 > result_size) - result = (char **) xrealloc - (result, (result_size += 10) * sizeof (char *)); - - result[result_index++] = keyname; - result[result_index] = (char *)NULL; + result_size += 10; + result = (char **) xrealloc (result, result_size * sizeof (char *)); } - free (seqs); + result[result_index++] = keyname; + result[result_index] = (char *)NULL; } + + free (seqs); } break; } @@ -1309,18 +1451,6 @@ rl_invoking_keyseqs (function) return (rl_invoking_keyseqs_in_map (function, _rl_keymap)); } -/* Print all of the current functions and their bindings to - rl_outstream. If an explicit argument is given, then print - the output in such a way that it can be read back in. */ -int -rl_dump_functions (count, key) - int count, key; -{ - rl_function_dumper (rl_explicit_arg); - rl_on_new_line (); - return (0); -} - /* Print all of the functions and their bindings to rl_outstream. If PRINT_READABLY is non-zero, then print the output in such a way that it can be read back in. */ @@ -1391,6 +1521,164 @@ rl_function_dumper (print_readably) } } +/* Print all of the current functions and their bindings to + rl_outstream. If an explicit argument is given, then print + the output in such a way that it can be read back in. */ +int +rl_dump_functions (count, key) + int count, key; +{ + rl_function_dumper (rl_explicit_arg); + rl_on_new_line (); + return (0); +} + +static void +_rl_macro_dumper_internal (print_readably, map, prefix) + int print_readably; + Keymap map; + char *prefix; +{ + register int key; + char *keyname, *out; + int prefix_len; + + for (key = 0; key < KEYMAP_SIZE; key++) + { + switch (map[key].type) + { + case ISMACR: + keyname = _rl_get_keyname (key); + out = (char *)map[key].function; + if (print_readably) + fprintf (rl_outstream, "\"%s%s\": \"%s\"\n", prefix ? prefix : "", + keyname, + out ? out : ""); + else + fprintf (rl_outstream, "%s%s outputs %s\n", prefix ? prefix : "", + keyname, + out ? out : ""); + free (keyname); + break; + case ISFUNC: + break; + case ISKMAP: + prefix_len = prefix ? strlen (prefix) : 0; + if (key == ESC) + { + keyname = xmalloc (3 + prefix_len); + if (prefix) + strcpy (keyname, prefix); + keyname[prefix_len] = '\\'; + keyname[prefix_len + 1] = 'e'; + keyname[prefix_len + 2] = '\0'; + } + else + { + keyname = _rl_get_keyname (key); + if (prefix) + { + out = xmalloc (strlen (keyname) + prefix_len + 1); + strcpy (out, prefix); + strcpy (out + prefix_len, keyname); + free (keyname); + keyname = out; + } + } + + _rl_macro_dumper_internal (print_readably, FUNCTION_TO_KEYMAP (map, key), keyname); + free (keyname); + break; + } + } +} + +void +rl_macro_dumper (print_readably) + int print_readably; +{ + _rl_macro_dumper_internal (print_readably, _rl_keymap, (char *)NULL); +} + +int +rl_dump_macros (count, key) + int count, key; +{ + rl_macro_dumper (rl_explicit_arg); + rl_on_new_line (); + return (0); +} + +void +rl_variable_dumper (print_readably) + int print_readably; +{ + int i; + char *kname; + + for (i = 0; boolean_varlist[i].name; i++) + { + if (print_readably) + fprintf (rl_outstream, "set %s %s\n", boolean_varlist[i].name, + *boolean_varlist[i].value ? "on" : "off"); + else + fprintf (rl_outstream, "%s is set to `%s'\n", boolean_varlist[i].name, + *boolean_varlist[i].value ? "on" : "off"); + } + + /* bell-style */ + switch (_rl_bell_preference) + { + case NO_BELL: kname = "none"; break; + case VISIBLE_BELL: kname = "visible"; break; + case AUDIBLE_BELL: + default: kname = "audible"; break; + } + if (print_readably) + fprintf (rl_outstream, "set bell-style %s\n", kname); + else + fprintf (rl_outstream, "bell-style is set to `%s'\n", kname); + + /* comment-begin */ + if (print_readably) + fprintf (rl_outstream, "set comment-begin %s\n", _rl_comment_begin ? _rl_comment_begin : RL_COMMENT_BEGIN_DEFAULT); + else + fprintf (rl_outstream, "comment-begin is set to `%s'\n", _rl_comment_begin ? _rl_comment_begin : ""); + + /* completion-query-items */ + if (print_readably) + fprintf (rl_outstream, "set completion-query-items %d\n", rl_completion_query_items); + else + fprintf (rl_outstream, "completion-query-items is set to `%d'\n", rl_completion_query_items); + + /* editing-mode */ + if (print_readably) + fprintf (rl_outstream, "set editing-mode %s\n", (rl_editing_mode == emacs_mode) ? "emacs" : "vi"); + else + fprintf (rl_outstream, "editing-mode is set to `%s'\n", (rl_editing_mode == emacs_mode) ? "emacs" : "vi"); + + /* keymap */ + kname = rl_get_keymap_name (_rl_keymap); + if (kname == 0) + kname = rl_get_keymap_name_from_edit_mode (); + if (print_readably) + fprintf (rl_outstream, "set keymap %s\n", kname ? kname : "none"); + else + fprintf (rl_outstream, "keymap is set to `%s'\n", kname ? kname : "none"); +} + +/* Print all of the current variables and their values to + rl_outstream. If an explicit argument is given, then print + the output in such a way that it can be read back in. */ +int +rl_dump_variables (count, key) + int count, key; +{ + rl_variable_dumper (rl_explicit_arg); + rl_on_new_line (); + return (0); +} + /* Bind key sequence KEYSEQ to DEFAULT_FUNC if KEYSEQ is unbound. */ void _rl_bind_if_unbound (keyseq, default_func) @@ -1407,14 +1695,6 @@ _rl_bind_if_unbound (keyseq, default_func) } } -/* **************************************************************** */ -/* */ -/* String Utility Functions */ -/* */ -/* **************************************************************** */ - -static char *strindex (); - /* Return non-zero if any members of ARRAY are a substring in STRING. */ static int substring_member_of_array (string, array) @@ -1422,66 +1702,9 @@ substring_member_of_array (string, array) { while (*array) { - if (strindex (string, *array)) + if (_rl_strindex (string, *array)) return (1); array++; } return (0); } - -#if !defined (HAVE_STRCASECMP) -/* Whoops, Unix doesn't have strnicmp. */ - -/* Compare at most COUNT characters from string1 to string2. Case - doesn't matter. */ -static int -strnicmp (string1, string2, count) - char *string1, *string2; - int count; -{ - register char ch1, ch2; - - while (count) - { - ch1 = *string1++; - ch2 = *string2++; - if (to_upper(ch1) == to_upper(ch2)) - count--; - else - break; - } - return (count); -} - -/* strcmp (), but caseless. */ -static int -stricmp (string1, string2) - char *string1, *string2; -{ - register char ch1, ch2; - - while (*string1 && *string2) - { - ch1 = *string1++; - ch2 = *string2++; - if (to_upper(ch1) != to_upper(ch2)) - return (1); - } - return (*string1 - *string2); -} -#endif /* !HAVE_STRCASECMP */ - -/* Determine if s2 occurs in s1. If so, return a pointer to the - match in s1. The compare is case insensitive. */ -static char * -strindex (s1, s2) - register char *s1, *s2; -{ - register int i, l = strlen (s2); - register int len = strlen (s1); - - for (i = 0; (len - i) >= l; i++) - if (strnicmp (s1 + i, s2, l) == 0) - return (s1 + i); - return ((char *)NULL); -} diff --git a/lib/readline/callback.c b/lib/readline/callback.c new file mode 100644 index 0000000..ad57f75 --- /dev/null +++ b/lib/readline/callback.c @@ -0,0 +1,144 @@ +/* callback.c -- functions to use readline as an X `callback' mechanism. */ + +/* Copyright (C) 1987, 1989, 1992 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 1, 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, + 675 Mass Ave, Cambridge, MA 02139, USA. */ +#define READLINE_LIBRARY + +#if defined (HAVE_CONFIG_H) +# include +#endif + +#include "rlconf.h" + +#if defined (READLINE_CALLBACKS) + +#include +#include + +/* System-specific feature definitions and include files. */ +#include "rldefs.h" +#include "readline.h" + +extern void readline_internal_startup (); +extern char *readline_internal_teardown (); +extern int readline_internal_char (); + +extern int _rl_meta_flag; +extern char *rl_prompt; +extern int rl_visible_prompt_length; + +/* **************************************************************** */ +/* */ +/* Callback Readline Functions */ +/* */ +/* **************************************************************** */ + +/* Allow using readline in situations where a program may have multiple + things to handle at once, and dispatches them via select(). Call + rl_callback_handler_install() with the prompt and a function to call + whenever a complete line of input is ready. The user must then + call readline_char() every time some input is available, and + readline_char() will call the user's function with the complete text + read in at each end of line. The terminal is kept prepped and signals + handled all the time, except during calls to the user's function. */ + +VFunction *rl_linefunc; /* user callback function */ +static int in_handler; /* terminal_prepped and signals set? */ + +/* Make sure the terminal is set up, initialize readline, and prompt. */ +static void +_rl_callback_newline () +{ + rl_initialize (); + + if (in_handler == 0) + { + in_handler = 1; + + (*rl_prep_term_function) (_rl_meta_flag); + +#if defined (HANDLE_SIGNALS) + rl_set_signals (); +#endif + } + + readline_internal_setup (); +} + +/* Install a readline handler, set up the terminal, and issue the prompt. */ +void +rl_callback_handler_install (prompt, linefunc) + char *prompt; + VFunction *linefunc; +{ + rl_prompt = prompt; + rl_visible_prompt_length = rl_prompt ? rl_expand_prompt (rl_prompt) : 0; + rl_linefunc = linefunc; + _rl_callback_newline (); +} + +/* Read one character, and dispatch to the handler if it ends the line. */ +void +rl_callback_read_char () +{ + char *line; + int eof; + + if (rl_linefunc == NULL) + { + fprintf (stderr, "readline: readline_callback_read_char() called with no handler!\r\n"); + abort (); + } + + eof = readline_internal_char (); + + if (rl_done) + { + line = readline_internal_teardown (eof); + + (*rl_deprep_term_function) (); +#if defined (HANDLE_SIGNALS) + rl_clear_signals (); +#endif + in_handler = 0; + (*rl_linefunc) (line); + + /* Redisplay the prompt if readline_handler_{install,remove} not called. */ + if (in_handler == 0 && rl_linefunc) + _rl_callback_newline (); + } +} + +/* Remove the handler, and make sure the terminal is in its normal state. */ +void +rl_callback_handler_remove () +{ + rl_linefunc = NULL; + if (in_handler) + { + in_handler = 0; + (*rl_deprep_term_function) (); +#if defined (HANDLE_SIGNALS) + rl_clear_signals (); +#endif + } +} + +#endif diff --git a/lib/readline/chardefs.h b/lib/readline/chardefs.h index 8c92811..8e6f0ef 100644 --- a/lib/readline/chardefs.h +++ b/lib/readline/chardefs.h @@ -20,16 +20,20 @@ have a copy of the license, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ -#ifndef _CHARDEFS_H -#define _CHARDEFS_H +#ifndef _CHARDEFS_H_ +#define _CHARDEFS_H_ #include -#if defined (HAVE_STRING_H) -# include +#if defined (HAVE_CONFIG_H) +# if defined (HAVE_STRING_H) +# include +# else +# include +# endif /* HAVE_STRING_H */ #else -# include -#endif /* HAVE_STRING_H */ +# include +#endif /* !HAVE_CONFIG_H */ #ifndef whitespace #define whitespace(c) (((c) == ' ') || ((c) == '\t')) @@ -47,39 +51,40 @@ #define meta_character_bit 0x080 /* x0000000, must be on. */ #define largest_char 255 /* Largest character value. */ -#define CTRL_CHAR(c) ((c) < control_character_threshold) +#define CTRL_CHAR(c) ((c) < control_character_threshold && (c) >= 0) #define META_CHAR(c) ((c) > meta_character_threshold && (c) <= largest_char) #define CTRL(c) ((c) & control_character_mask) #define META(c) ((c) | meta_character_bit) #define UNMETA(c) ((c) & (~meta_character_bit)) -#define UNCTRL(c) to_upper(((c)|control_character_bit)) +#define UNCTRL(c) _rl_to_upper(((c)|control_character_bit)) /* Old versions -#define lowercase_p(c) (((c) > ('a' - 1) && (c) < ('z' + 1))) -#define uppercase_p(c) (((c) > ('A' - 1) && (c) < ('Z' + 1))) -#define digit_p(c) ((c) >= '0' && (c) <= '9') +#define _rl_lowercase_p(c) (((c) > ('a' - 1) && (c) < ('z' + 1))) +#define _rl_uppercase_p(c) (((c) > ('A' - 1) && (c) < ('Z' + 1))) +#define _rl_digit_p(c) ((c) >= '0' && (c) <= '9') */ -#define lowercase_p(c) (islower(c)) -#define uppercase_p(c) (isupper(c)) -#define digit_p(x) (isdigit (x)) +#define _rl_lowercase_p(c) (islower(c)) +#define _rl_uppercase_p(c) (isupper(c)) +#define _rl_digit_p(x) (isdigit (x)) -#define pure_alphabetic(c) (lowercase_p(c) || uppercase_p(c)) +#define _rl_pure_alphabetic(c) (_rl_lowercase_p(c) || _rl_uppercase_p(c)) +#define ALPHABETIC(c) (_rl_lowercase_p(c) || _rl_uppercase_p(c) || _rl_digit_p(c)) /* Old versions -# define to_upper(c) (lowercase_p(c) ? ((c) - 32) : (c)) -# define to_lower(c) (uppercase_p(c) ? ((c) + 32) : (c)) +# define _rl_to_upper(c) (_rl_lowercase_p(c) ? ((c) - 32) : (c)) +# define _rl_to_lower(c) (_rl_uppercase_p(c) ? ((c) + 32) : (c)) */ -#ifndef to_upper -# define to_upper(c) (islower(c) ? toupper(c) : (c)) -# define to_lower(c) (isupper(c) ? tolower(c) : (c)) +#ifndef _rl_to_upper +# define _rl_to_upper(c) (islower(c) ? toupper(c) : (c)) +# define _rl_to_lower(c) (isupper(c) ? tolower(c) : (c)) #endif -#ifndef digit_value -#define digit_value(x) ((x) - '0') +#ifndef _rl_digit_value +#define _rl_digit_value(x) ((x) - '0') #endif #ifndef NEWLINE @@ -119,4 +124,4 @@ #define ESC CTRL('[') -#endif /* _CHARDEFS_H */ +#endif /* _CHARDEFS_H_ */ diff --git a/lib/readline/complete.c b/lib/readline/complete.c index f219877..f9e27eb 100644 --- a/lib/readline/complete.c +++ b/lib/readline/complete.c @@ -22,15 +22,15 @@ #define READLINE_LIBRARY #if defined (HAVE_CONFIG_H) -# include "config.h" +# include #endif #include #include #include -#if !defined (NO_SYS_FILE) -# include -#endif /* !NO_SYS_FILE */ +#if defined (HAVE_SYS_FILE_H) +#include +#endif #if defined (HAVE_UNISTD_H) # include @@ -43,13 +43,12 @@ #endif /* HAVE_STDLIB_H */ #include -/* Not all systems declare ERRNO in errno.h... and some systems #define it! */ #if !defined (errno) extern int errno; #endif /* !errno */ #include -#if defined (USG) && !defined (HAVE_GETPW_DECLS) +#if !defined (HAVE_GETPW_DECLS) extern struct passwd *getpwent (); #endif /* USG && !HAVE_GETPW_DECLS */ @@ -62,6 +61,7 @@ extern struct passwd *getpwent (); # endif /* !__STDC__ */ #endif /* isc386 && _POSIX_SOURCE */ +#include "posixdir.h" #include "posixstat.h" /* System-specific feature definitions and include files. */ @@ -70,35 +70,36 @@ extern struct passwd *getpwent (); /* Some standard library routines. */ #include "readline.h" -/* Possible values for do_replace in rl_complete_internal. */ -#define NO_MATCH 0 -#define SINGLE_MATCH 1 -#define MULT_MATCH 2 - -#if !defined (strchr) && !defined (__STDC__) -extern char *strchr (), *strrchr (); -#endif /* !strchr && !__STDC__ */ - extern char *tilde_expand (); extern char *rl_copy_text (); +extern void _rl_abort_internal (); +extern int _rl_qsort_string_compare (); extern Function *rl_last_func; extern int rl_editing_mode; extern int screenwidth; +extern void _rl_move_vert (); +extern int _rl_vis_botlin; +extern int rl_display_fixed; + /* Forward declarations for functions defined and used in this file. */ char *filename_completion_function (); char **completion_matches (); -static int compare_strings (); +static char *rl_quote_filename (); static char *rl_strpbrk (); -#if defined (STATIC_MALLOC) -static char *xmalloc (), *xrealloc (); -#else +static char **remove_duplicate_matches (); +static void insert_text (); +static void insert_match (); +static void append_to_match (); +static void insert_all_matches (); +static void display_matches (); +static int compute_lcd_of_matches (); + extern char *xmalloc (), *xrealloc (); -#endif /* STATIC_MALLOC */ - + /* If non-zero, then this is the address of a function to call when completing on a directory name. The function is called with the address of a string (the current directory name) as an arg. */ @@ -110,6 +111,9 @@ int rl_complete_with_tilde_expansion = 0; /* If non-zero, non-unique completions always show the list of matches. */ int _rl_complete_show_all = 0; +/* If non-zero, completed directory names have a slash appended. */ +int _rl_complete_mark_directories = 1; + #if defined (VISIBLE_STATS) # if !defined (X_OK) # define X_OK 1 @@ -129,6 +133,9 @@ int rl_visible_stats = 0; /* */ /* **************************************************************** */ +/* Local variable states what happened during the last completion attempt. */ +static int completion_changed_buffer; + /* Pointer to the generator function for completion_matches (). NULL means to use filename_entry_function (), the default filename completer. */ @@ -147,54 +154,10 @@ CPPFunction *rl_attempted_completion_function = (CPPFunction *)NULL; user-specified completion function has been called. */ int rl_attempted_completion_over = 0; -/* Local variable states what happened during the last completion attempt. */ -static int completion_changed_buffer = 0; - -/* Complete the word at or before point. You have supplied the function - that does the initial simple matching selection algorithm (see - completion_matches ()). The default is to do filename completion. */ - -rl_complete (ignore, invoking_key) - int ignore, invoking_key; -{ - if (rl_last_func == rl_complete && !completion_changed_buffer) - return (rl_complete_internal ('?')); - else if (_rl_complete_show_all) - return (rl_complete_internal ('!')); - else - return (rl_complete_internal (TAB)); -} - -/* List the possible completions. See description of rl_complete (). */ -rl_possible_completions (ignore, invoking_key) - int ignore, invoking_key; -{ - return (rl_complete_internal ('?')); -} - -rl_insert_completions (ignore, invoking_key) - int ignore, invoking_key; -{ - return (rl_complete_internal ('*')); -} - -/* The user must press "y" or "n". Non-zero return means "y" pressed. */ -get_y_or_n () -{ - int c; - - for (;;) - { - c = rl_read_key (); - if (c == 'y' || c == 'Y' || c == ' ') - return (1); - if (c == 'n' || c == 'N' || c == RUBOUT) - return (0); - if (c == ABORT_CHAR) - rl_abort (); - ding (); - } -} +/* Set to a character indicating the type of completion being performed + by rl_complete_internal, available for use by application completion + functions. */ +int rl_completion_type = 0; /* Up to this many items will be displayed in response to a possible-completions call. After that, we ask the user if @@ -206,6 +169,9 @@ int rl_completion_query_items = 100; in the shell, i.e. " \t\n\"\\'`@$><=" */ char *rl_basic_word_break_characters = " \t\n\"\\'`@$><=;|&{("; +/* List of basic quoting characters. */ +char *rl_basic_quote_characters = "\"'"; + /* The list of characters that signal a break between words for rl_complete_internal. The default list is the contents of rl_basic_word_break_characters. */ @@ -217,6 +183,9 @@ char *rl_completer_word_break_characters = (char *)NULL; unless they also appear within this list. */ char *rl_completer_quote_characters = (char *)NULL; +/* List of characters that should be quoted in filenames by the completer. */ +char *rl_filename_quote_characters = (char *)NULL; + /* List of characters that are word break characters, but should be left in TEXT when it is passed to the completion function. The shell uses this to help determine what kind of completing to do. */ @@ -232,7 +201,7 @@ int rl_filename_completion_desired = 0; /* Non-zero means that the results of the matches are to be quoted using double quotes (or an application-specific quoting mechanism) if the - filename contains any characters in rl_word_break_chars. This is + filename contains any characters in rl_filename_quote_chars. This is ALWAYS non-zero on entry, and can only be changed within a completion entry finder function. */ int rl_filename_quoting_desired = 1; @@ -248,43 +217,80 @@ int rl_filename_quoting_desired = 1; to implement FIGNORE a la SunOS csh. */ Function *rl_ignore_some_completions_function = (Function *)NULL; -#if defined (SHELL) -/* A function to strip quotes that are not protected by backquotes. It - allows single quotes to appear within double quotes, and vice versa. - It should be smarter. It's fairly shell-specific, hence the SHELL - definition wrapper. */ -static char * -_delete_quotes (text) - char *text; +/* Set to a function to quote a filename in an application-specific fashion. + Called with the text to quote, the type of match found (single or multiple) + and a pointer to the quoting character to be used, which the function can + reset if desired. */ +CPFunction *rl_filename_quoting_function = rl_quote_filename; + +/* Function to call to remove quoting characters from a filename. Called + before completion is attempted, so the embedded quotes do not interfere + with matching names in the file system. Readline doesn't do anything + with this; it's set only by applications. */ +CPFunction *rl_filename_dequoting_function = (CPFunction *)NULL; + +/* Function to call to decide whether or not a word break character is + quoted. If a character is quoted, it does not break words for the + completer. */ +Function *rl_char_is_quoted_p = (Function *)NULL; + +/* Character appended to completed words when at the end of the line. The + default is a space. */ +int rl_completion_append_character = ' '; + +/* If non-zero, inhibit completion (temporarily). */ +int rl_inhibit_completion; + +/* Complete the word at or before point. You have supplied the function + that does the initial simple matching selection algorithm (see + completion_matches ()). The default is to do filename completion. */ +int +rl_complete (ignore, invoking_key) + int ignore, invoking_key; +{ + if (rl_inhibit_completion) + return (rl_insert (ignore, invoking_key)); + else if (rl_last_func == rl_complete && !completion_changed_buffer) + return (rl_complete_internal ('?')); + else if (_rl_complete_show_all) + return (rl_complete_internal ('!')); + else + return (rl_complete_internal (TAB)); +} + +/* List the possible completions. See description of rl_complete (). */ +int +rl_possible_completions (ignore, invoking_key) + int ignore, invoking_key; +{ + return (rl_complete_internal ('?')); +} + +int +rl_insert_completions (ignore, invoking_key) + int ignore, invoking_key; { - char *ret, *p, *r; - int l, quoted; + return (rl_complete_internal ('*')); +} - l = strlen (text); - ret = xmalloc (l + 1); - for (quoted = 0, p = text, r = ret; p && *p; p++) +/* The user must press "y" or "n". Non-zero return means "y" pressed. */ +static int +get_y_or_n () +{ + int c; + + for (;;) { - /* Allow backslash-quoted characters to pass through unscathed. */ - if (*p == '\\') - continue; - /* Close quote. */ - if (quoted && *p == quoted) - { - quoted = 0; - continue; - } - /* Open quote. */ - if (quoted == 0 && (*p == '\'' || *p == '"')) - { - quoted = *p; - continue; - } - *r++ = *p; + c = rl_read_key (); + if (c == 'y' || c == 'Y' || c == ' ') + return (1); + if (c == 'n' || c == 'N' || c == RUBOUT) + return (0); + if (c == ABORT_CHAR) + _rl_abort_internal (); + ding (); } - *r = '\0'; - return ret; } -#endif /* SHELL */ /* Return the portion of PATHNAME that should be output when listing possible completions. If we are hacking filename completion, we @@ -294,20 +300,16 @@ static char * printable_part (pathname) char *pathname; { - char *temp = (char *)NULL; - - if (rl_filename_completion_desired) - temp = strrchr (pathname, '/'); + char *temp; - if (!temp) - return (pathname); - else - return (++temp); + temp = rl_filename_completion_desired ? strrchr (pathname, '/') : (char *)NULL; + return (temp ? ++temp : pathname); } /* Output TO_PRINT to rl_outstream. If VISIBLE_STATS is defined and we are using it, check for and output a single character for `special' filenames. Return 1 if we printed an extension character, 0 if not. */ + #define PUTX(c) \ if (CTRL_CHAR (c)) \ { \ @@ -315,12 +317,12 @@ printable_part (pathname) putc (UNCTRL (c), rl_outstream); \ } \ else if (c == RUBOUT) \ - { \ - putc ('^', rl_outstream); \ - putc ('?', rl_outstream); \ - } \ + { \ + putc ('^', rl_outstream); \ + putc ('?', rl_outstream); \ + } \ else \ - putc (c, rl_outstream) + putc (c, rl_outstream) static int print_filename (to_print, full_pathname) @@ -336,14 +338,14 @@ print_filename (to_print, full_pathname) return 0; #else char *s, c, *new_full_pathname; - int extension_char = 0, slen, tlen; + int extension_char, slen, tlen; for (s = to_print; *s; s++) { PUTX (*s); - } + } - if (rl_filename_completion_desired && rl_visible_stats) + if (rl_filename_completion_desired && rl_visible_stats) { /* If to_print != full_pathname, to_print is the basename of the path passed. In this case, we try to expand the directory @@ -386,139 +388,160 @@ print_filename (to_print, full_pathname) #endif /* VISIBLE_STATS */ } -/* Complete the word at or before point. - WHAT_TO_DO says what to do with the completion. - `?' means list the possible completions. - TAB means do standard completion. - `*' means insert all of the possible completions. - `!' means to do standard completion, and list all possible completions if - there is more than one. */ -rl_complete_internal (what_to_do) - int what_to_do; +static char * +rl_quote_filename (s, rtype, qcp) + char *s; + int rtype; + char *qcp; { - char **matches; - Function *our_func; - int start, scan, end, delimiter = 0, pass_next; - char *text, *saved_line_buffer; - char *replacement; - char quote_char = '\0'; - int found_quote = 0; - - if (rl_line_buffer) - saved_line_buffer = savestring (rl_line_buffer); - else - saved_line_buffer = (char *)NULL; - - if (rl_completion_entry_function) - our_func = rl_completion_entry_function; - else - our_func = (Function *)filename_completion_function; + char *r; + + r = xmalloc (strlen (s) + 2); + *r = *rl_completer_quote_characters; + strcpy (r + 1, s); + if (qcp) + *qcp = *rl_completer_quote_characters; + return r; +} - /* Only the completion entry function can change these. */ - rl_filename_completion_desired = 0; - rl_filename_quoting_desired = 1; +/* Find the bounds of the current word for completion purposes, and leave + rl_point set to the end of the word. This function skips quoted + substrings (characters between matched pairs of characters in + rl_completer_quote_characters. First we try to find an unclosed + quoted substring on which to do matching. If one is not found, we use + the word break characters to find the boundaries of the current word. + We call an application-specific function to decide whether or not a + particular word break character is quoted; if that function returns a + non-zero result, the character does not break a word. This function + returns the opening quote character if we found an unclosed quoted + substring, '\0' otherwise. FP, if non-null, is set to a value saying + which (shell-like) quote characters we found (single quote, double + quote, or backslash) anywhere in the string. DP, if non-null, is set to + the value of the delimiter character that caused a word break. */ + +static char +find_completion_word (fp, dp) + int *fp, *dp; +{ + int scan, end, found_quote, delimiter, pass_next, isbrk; + char quote_char; - /* We now look backwards for the start of a filename/variable word. */ end = rl_point; + found_quote = delimiter = 0; + quote_char = '\0'; - if (rl_point) + if (rl_completer_quote_characters) { - if (rl_completer_quote_characters) + /* We have a list of characters which can be used in pairs to + quote substrings for the completer. Try to find the start + of an unclosed quoted substring. */ + /* FOUND_QUOTE is set so we know what kind of quotes we found. */ + for (scan = pass_next = 0; scan < end; scan++) { - /* We have a list of characters which can be used in pairs to - quote substrings for the completer. Try to find the start - of an unclosed quoted substring. */ - /* FOUND_QUOTE is set so we know what kind of quotes we found. */ - for (scan = pass_next = 0; scan < end; scan++) + if (pass_next) { - if (pass_next) - { - pass_next = 0; - continue; - } + pass_next = 0; + continue; + } - if (rl_line_buffer[scan] == '\\') - { - pass_next = 1; - found_quote |= 4; - continue; - } + if (rl_line_buffer[scan] == '\\') + { + pass_next = 1; + found_quote |= RL_QF_BACKSLASH; + continue; + } - if (quote_char != '\0') - { - /* Ignore everything until the matching close quote char. */ - if (rl_line_buffer[scan] == quote_char) - { - /* Found matching close. Abandon this substring. */ - quote_char = '\0'; - rl_point = end; - } - } - else if (strchr (rl_completer_quote_characters, rl_line_buffer[scan])) + if (quote_char != '\0') + { + /* Ignore everything until the matching close quote char. */ + if (rl_line_buffer[scan] == quote_char) { - /* Found start of a quoted substring. */ - quote_char = rl_line_buffer[scan]; - rl_point = scan + 1; - /* Shell-like quoting conventions. */ - if (quote_char == '\'') - found_quote |= 1; - else if (quote_char == '"') - found_quote |= 2; + /* Found matching close. Abandon this substring. */ + quote_char = '\0'; + rl_point = end; } } + else if (strchr (rl_completer_quote_characters, rl_line_buffer[scan])) + { + /* Found start of a quoted substring. */ + quote_char = rl_line_buffer[scan]; + rl_point = scan + 1; + /* Shell-like quoting conventions. */ + if (quote_char == '\'') + found_quote |= RL_QF_SINGLE_QUOTE; + else if (quote_char == '"') + found_quote |= RL_QF_DOUBLE_QUOTE; + } } + } - if (rl_point == end && quote_char == '\0') + if (rl_point == end && quote_char == '\0') + { + /* We didn't find an unclosed quoted substring upon which to do + completion, so use the word break characters to find the + substring on which to complete. */ + while (--rl_point) { - int quoted = 0; - /* We didn't find an unclosed quoted substring upon which to do - completion, so use the word break characters to find the - substring on which to complete. */ - while (--rl_point) - { - scan = rl_line_buffer[rl_point]; + scan = rl_line_buffer[rl_point]; - if (strchr (rl_completer_word_break_characters, scan) == 0) - continue; + if (strchr (rl_completer_word_break_characters, scan) == 0) + continue; -#if defined (SHELL) - /* Don't let word break characters in quoted substrings break - words for the completer. */ - if (found_quote && char_is_quoted (rl_line_buffer, rl_point)) - continue; -#endif /* SHELL */ - - /* Convoluted code, but it avoids an n^2 algorithm with calls - to char_is_quoted. */ - break; - } - } + /* Call the application-specific function to tell us whether + this word break character is quoted and should be skipped. */ + if (rl_char_is_quoted_p && found_quote && + (*rl_char_is_quoted_p) (rl_line_buffer, rl_point)) + continue; - /* If we are at an unquoted word break, then advance past it. */ - scan = rl_line_buffer[rl_point]; -#if defined (SHELL) - if ((found_quote == 0 || char_is_quoted (rl_line_buffer, rl_point) == 0) && - strchr (rl_completer_word_break_characters, scan)) -#else - if (strchr (rl_completer_word_break_characters, scan)) -#endif - { - /* If the character that caused the word break was a quoting - character, then remember it as the delimiter. */ - if (strchr ("\"'", scan) && (end - rl_point) > 1) - delimiter = scan; - - /* If the character isn't needed to determine something special - about what kind of completion to perform, then advance past it. */ - if (!rl_special_prefixes || strchr (rl_special_prefixes, scan) == 0) - rl_point++; + /* Convoluted code, but it avoids an n^2 algorithm with calls + to char_is_quoted. */ + break; } } - /* At this point, we know we have an open quote if quote_char != '\0'. */ - start = rl_point; - rl_point = end; - text = rl_copy_text (start, end); + /* If we are at an unquoted word break, then advance past it. */ + scan = rl_line_buffer[rl_point]; + + /* If there is an application-specific function to say whether or not + a character is quoted and we found a quote character, let that + function decide whether or not a character is a word break, even + if it is found in rl_completer_word_break_characters. */ + if (rl_char_is_quoted_p) + isbrk = (found_quote == 0 || + (*rl_char_is_quoted_p) (rl_line_buffer, rl_point) == 0) && + strchr (rl_completer_word_break_characters, scan) != 0; + else + isbrk = strchr (rl_completer_word_break_characters, scan) != 0; + + if (isbrk) + { + /* If the character that caused the word break was a quoting + character, then remember it as the delimiter. */ + if (rl_basic_quote_characters && strchr (rl_basic_quote_characters, scan) && (end - rl_point) > 1) + delimiter = scan; + + /* If the character isn't needed to determine something special + about what kind of completion to perform, then advance past it. */ + if (rl_special_prefixes == 0 || strchr (rl_special_prefixes, scan) == 0) + rl_point++; + } + + if (fp) + *fp = found_quote; + if (dp) + *dp = delimiter; + + return (quote_char); +} + +static char ** +gen_completion_matches (text, start, end, our_func, found_quote, quote_char) + char *text; + int start, end; + Function *our_func; + int found_quote, quote_char; +{ + char **matches, *temp; /* If the user wants to TRY to complete, but then wants to give up and use the default completion function, they set the @@ -530,424 +553,524 @@ rl_complete_internal (what_to_do) if (matches || rl_attempted_completion_over) { rl_attempted_completion_over = 0; - our_func = (Function *)NULL; - goto after_usual_completion; + return (matches); } } -#if defined (SHELL) /* Beware -- we're stripping the quotes here. Do this only if we know - we are doing filename completion. */ - if (found_quote && our_func == (Function *)filename_completion_function) + we are doing filename completion and the application has defined a + filename dequoting function. */ + temp = (char *)NULL; + if (found_quote && our_func == (Function *)filename_completion_function && + rl_filename_dequoting_function) { /* delete single and double quotes */ - replacement = _delete_quotes (text); - free (text); - text = replacement; - replacement = (char *)0; + temp = (*rl_filename_dequoting_function) (text, quote_char); + text = temp; /* not freeing text is not a memory leak */ } -#endif /* SHELL */ matches = completion_matches (text, our_func); + FREE (temp); + return matches; +} - after_usual_completion: - free (text); +/* Filter out duplicates in MATCHES. This frees up the strings in + MATCHES. */ +static char ** +remove_duplicate_matches (matches) + char **matches; +{ + char *lowest_common; + int i, j, newlen; + char dead_slot; + char **temp_array; - if (!matches) - ding (); - else - { - register int i; - int should_quote; + /* Sort the items. */ + for (i = 0; matches[i]; i++) + ; + + /* Sort the array without matches[0], since we need it to + stay in place no matter what. */ + if (i) + qsort (matches+1, i-1, sizeof (char *), _rl_qsort_string_compare); + + /* Remember the lowest common denominator for it may be unique. */ + lowest_common = savestring (matches[0]); - /* It seems to me that in all the cases we handle we would like - to ignore duplicate possiblilities. Scan for the text to - insert being identical to the other completions. */ - if (rl_ignore_completion_duplicates) + for (i = newlen = 0; matches[i + 1]; i++) + { + if (strcmp (matches[i], matches[i + 1]) == 0) { - char *lowest_common; - int j, newlen = 0; - char dead_slot; - char **temp_array; - - /* Sort the items. */ - /* It is safe to sort this array, because the lowest common - denominator found in matches[0] will remain in place. */ - for (i = 0; matches[i]; i++) - ; - /* Try sorting the array without matches[0], since we need it to - stay in place no matter what. */ - if (i) - qsort (matches+1, i-1, sizeof (char *), compare_strings); + free (matches[i]); + matches[i] = (char *)&dead_slot; + } + else + newlen++; + } - /* Remember the lowest common denominator for it may be unique. */ - lowest_common = savestring (matches[0]); + /* We have marked all the dead slots with (char *)&dead_slot. + Copy all the non-dead entries into a new array. */ + temp_array = (char **)xmalloc ((3 + newlen) * sizeof (char *)); + for (i = j = 1; matches[i]; i++) + { + if (matches[i] != (char *)&dead_slot) + temp_array[j++] = matches[i]; + } + temp_array[j] = (char *)NULL; - for (i = 0; matches[i + 1]; i++) - { - if (strcmp (matches[i], matches[i + 1]) == 0) - { - free (matches[i]); - matches[i] = (char *)&dead_slot; - } - else - newlen++; - } + if (matches[0] != (char *)&dead_slot) + free (matches[0]); - /* We have marked all the dead slots with (char *)&dead_slot. - Copy all the non-dead entries into a new array. */ - temp_array = (char **)xmalloc ((3 + newlen) * sizeof (char *)); - for (i = j = 1; matches[i]; i++) - { - if (matches[i] != (char *)&dead_slot) - temp_array[j++] = matches[i]; - } - temp_array[j] = (char *)NULL; + /* Place the lowest common denominator back in [0]. */ + temp_array[0] = lowest_common; + + /* If there is one string left, and it is identical to the + lowest common denominator, then the LCD is the string to + insert. */ + if (j == 2 && strcmp (temp_array[0], temp_array[1]) == 0) + { + free (temp_array[1]); + temp_array[1] = (char *)NULL; + } + return (temp_array); +} - if (matches[0] != (char *)&dead_slot) - free (matches[0]); - free (matches); +static void +display_matches (matches) + char **matches; +{ + int len, count, limit, max, printed_len; + int i, j, k, l; + char *temp; - matches = temp_array; + /* Move to the last visible line of a possibly-multiple-line command. */ + _rl_move_vert (_rl_vis_botlin); - /* Place the lowest common denominator back in [0]. */ - matches[0] = lowest_common; + /* Handle simple case first. What if there is only one answer? */ + if (matches[1] == 0) + { + temp = printable_part (matches[0]); + crlf (); + print_filename (temp, matches[0]); + crlf (); +#if 0 + rl_on_new_line (); +#else + rl_forced_update_display (); + rl_display_fixed = 1; +#endif + return; + } - /* If there is one string left, and it is identical to the - lowest common denominator, then the LCD is the string to - insert. */ - if (j == 2 && strcmp (matches[0], matches[1]) == 0) - { - free (matches[1]); - matches[1] = (char *)NULL; - } + /* There is more than one answer. Find out how many there are, + and find the maximum printed length of a single entry. */ + for (max = 0, i = 1; matches[i]; i++) + { + temp = printable_part (matches[i]); + len = strlen (temp); + + if (len > max) + max = len; + } + + len = i - 1; + + /* If there are many items, then ask the user if she really wants to + see them all. */ + if (len >= rl_completion_query_items) + { + crlf (); + fprintf (rl_outstream, "Display all %d possibilities? (y or n)", len); + fflush (rl_outstream); + if (get_y_or_n () == 0) + { + crlf (); +#if 0 + rl_on_new_line (); +#else + rl_forced_update_display (); + rl_display_fixed = 1; +#endif + return; } + } + + /* How many items of MAX length can we fit in the screen window? */ + max += 2; + limit = screenwidth / max; + if (limit != 1 && (limit * max == screenwidth)) + limit--; + + /* Avoid a possible floating exception. If max > screenwidth, + limit will be 0 and a divide-by-zero fault will result. */ + if (limit == 0) + limit = 1; + + /* How many iterations of the printing loop? */ + count = (len + (limit - 1)) / limit; - switch (what_to_do) + /* Watch out for special case. If LEN is less than LIMIT, then + just do the inner printing loop. + 0 < len <= limit implies count = 1. */ + + /* Sort the items if they are not already sorted. */ + if (rl_ignore_completion_duplicates == 0) + qsort (matches + 1, len, sizeof (char *), _rl_qsort_string_compare); + + /* Print the sorted items, up-and-down alphabetically, like ls. */ + crlf (); + + for (i = 1; i <= count; i++) + { + for (j = 0, l = i; j < limit; j++) { - case TAB: - case '!': - /* If we are matching filenames, then here is our chance to - do clever processing by re-examining the list. Call the - ignore function with the array as a parameter. It can - munge the array, deleting matches as it desires. */ - if (rl_ignore_some_completions_function && - our_func == (Function *)filename_completion_function) + if (l > len || matches[l] == 0) + break; + else { - (void)(*rl_ignore_some_completions_function)(matches); - if (matches == 0 || matches[0] == 0) - { - if (matches) - free (matches); - ding (); - return; - } + temp = printable_part (matches[l]); + printed_len = strlen (temp) + print_filename (temp, matches[l]); + + if (j + 1 < limit) + for (k = 0; k < max - printed_len; k++) + putc (' ', rl_outstream); } + l += count; + } + crlf (); + } - /* If we are doing completion on quoted substrings, and any matches - contain any of the completer_word_break_characters, then auto- - matically prepend the substring with a quote character (just pick - the first one from the list of such) if it does not already begin - with a quote string. FIXME: Need to remove any such automatically - inserted quote character when it no longer is necessary, such as - if we change the string we are completing on and the new set of - matches don't require a quoted substring. */ - replacement = matches[0]; - - should_quote = matches[0] && rl_completer_quote_characters && - rl_filename_completion_desired && - rl_filename_quoting_desired; - - if (should_quote) -#if defined (SHELL) - should_quote = should_quote && (!quote_char || quote_char == '"'); +#if 0 + rl_on_new_line (); #else - should_quote = should_quote && !quote_char; + rl_forced_update_display (); + rl_display_fixed = 1; #endif +} - if (should_quote) - { - int do_replace; - - do_replace = NO_MATCH; +static void +insert_text (text, start, end) + char *text; + int start, end; +{ + rl_begin_undo_group (); + rl_delete_text (start, end + 1); + rl_point = start; + rl_insert_text (text); + rl_end_undo_group (); +} - /* If there is a single match, see if we need to quote it. - This also checks whether the common prefix of several - matches needs to be quoted. If the common prefix should - not be checked, add !matches[1] to the if clause. */ - should_quote = rl_strpbrk (matches[0], rl_completer_word_break_characters) != 0; +static char * +make_quoted_replacement (match, mtype, quote_char) + char *match; + int mtype, quote_char; +{ + int should_quote, do_replace; + char *replacement, qc; + + /* If we are doing completion on quoted substrings, and any matches + contain any of the completer_word_break_characters, then auto- + matically prepend the substring with a quote character (just pick + the first one from the list of such) if it does not already begin + with a quote string. FIXME: Need to remove any such automatically + inserted quote character when it no longer is necessary, such as + if we change the string we are completing on and the new set of + matches don't require a quoted substring. */ + replacement = match; + + should_quote = match && rl_completer_quote_characters && + rl_filename_completion_desired && + rl_filename_quoting_desired; + + if (should_quote) #if defined (SHELL) - should_quote = should_quote || rl_strpbrk (matches[0], "#$`?*[!") != 0; + should_quote = should_quote && (!quote_char || quote_char == '"' || quote_char == '\''); +#else + should_quote = should_quote && !quote_char; #endif - if (should_quote) - do_replace = matches[1] ? MULT_MATCH : SINGLE_MATCH; - - if (do_replace != NO_MATCH) - { -#if defined (SHELL) - /* Quote the replacement, since we found an - embedded word break character in a potential - match. */ - char *rtext, *mtext; - int rlen; - extern char *double_quote (); /* in builtins/common.c */ - - /* If DO_REPLACE == MULT_MATCH, it means that there is - more than one match. In this case, we do not add - the closing quote or attempt to perform tilde - expansion. If DO_REPLACE == SINGLE_MATCH, we try - to perform tilde expansion, because double quotes - inhibit tilde expansion by the shell. */ - - mtext = matches[0]; - if (mtext[0] == '~' && do_replace == SINGLE_MATCH) - mtext = tilde_expand (matches[0]); - rtext = double_quote (mtext); - if (mtext != matches[0]) - free (mtext); - - rlen = strlen (rtext); - replacement = xmalloc (rlen + 1); - /* If we're completing on a quoted string where the user - has already supplied the opening quote, we don't want - the quote in the replacement text, and we reset - QUOTE_CHAR to 0 to avoid an extra closing quote. */ - if (quote_char == '"') - { - strcpy (replacement, rtext + 1); - rlen--; - quote_char = 0; - } - else - strcpy (replacement, rtext); - if (do_replace == MULT_MATCH) - replacement[rlen - 1] = '\0'; - free (rtext); -#else /* !SHELL */ - /* Found an embedded word break character in a potential - match, so we need to prepend a quote character if we - are replacing the completion string. */ - replacement = xmalloc (strlen (matches[0]) + 2); - quote_char = *rl_completer_quote_characters; - *replacement = quote_char; - strcpy (replacement + 1, matches[0]); -#endif /* SHELL */ - } - } + if (should_quote) + { + /* If there is a single match, see if we need to quote it. + This also checks whether the common prefix of several + matches needs to be quoted. */ + should_quote = rl_strpbrk (match, rl_filename_quote_characters) != 0; - if (replacement) + do_replace = should_quote ? mtype : NO_MATCH; + if (do_replace != NO_MATCH) + { + /* Quote the replacement, since we found an embedded + word break character in a potential match. */ + if (rl_filename_quoting_function) { - rl_begin_undo_group (); - rl_delete_text (start, rl_point); - rl_point = start; - rl_insert_text (replacement); - rl_end_undo_group (); - if (replacement != matches[0]) - free (replacement); + qc = quote_char; /* must pass a (char *) to quoting function */ + replacement = (*rl_filename_quoting_function) + (match, do_replace, &qc); + quote_char = qc; } + } + } + return (replacement); +} - /* If there are more matches, ring the bell to indicate. - If this was the only match, and we are hacking files, - check the file to see if it was a directory. If so, - add a '/' to the name. If not, and we are at the end - of the line, then add a space. */ - if (matches[1]) - { - if (what_to_do == '!') - goto display_matches; /* XXX */ - else if (rl_editing_mode != vi_mode) - ding (); /* There are other matches remaining. */ - } - else - { - char temp_string[4]; - int temp_string_index = 0; +static void +insert_match (match, start, mtype, quote_char) + char *match; + int start, mtype, quote_char; +{ + char *replacement; - if (quote_char) - temp_string[temp_string_index++] = quote_char; + replacement = make_quoted_replacement (match, mtype, quote_char); - temp_string[temp_string_index++] = delimiter ? delimiter : ' '; - temp_string[temp_string_index++] = '\0'; + /* Now insert the match. */ + if (replacement) + { + /* Don't double an opening quote character. */ + if (quote_char && start && rl_line_buffer[start - 1] == quote_char && + replacement[0] == quote_char) + start--; + insert_text (replacement, start, rl_point - 1); + if (replacement != match) + free (replacement); + } +} - if (rl_filename_completion_desired) - { - struct stat finfo; - char *filename = tilde_expand (matches[0]); - - if ((stat (filename, &finfo) == 0) && S_ISDIR (finfo.st_mode)) - { - if (rl_line_buffer[rl_point] != '/') - rl_insert_text ("/"); - } - else - { - if (rl_point == rl_end) - rl_insert_text (temp_string); - } - free (filename); - } - else - { - if (rl_point == rl_end) - rl_insert_text (temp_string); - } - } - break; +/* Append any necessary closing quote and a separator character to the + just-inserted match. If the user has specified that directories + should be marked by a trailing `/', append one of those instead. The + default trailing character */ +static void +append_to_match (text, delimiter, quote_char) + char *text; + int delimiter, quote_char; +{ + char temp_string[4], *filename; + int temp_string_index; + struct stat finfo; - case '*': - { - int i = 1; - - rl_begin_undo_group (); - rl_delete_text (start, rl_point); - rl_point = start; - if (matches[1]) - { - while (matches[i]) - { - rl_insert_text (matches[i++]); - rl_insert_text (" "); - } - } - else - { - rl_insert_text (matches[0]); - rl_insert_text (" "); - } - rl_end_undo_group (); - } - break; + temp_string_index = 0; + if (quote_char && rl_point && rl_line_buffer[rl_point - 1] != quote_char) + temp_string[temp_string_index++] = quote_char; - case '?': - { - int len, count, limit, max; - int j, k, l; - - /* Handle simple case first. What if there is only one answer? */ - if (!matches[1]) - { - char *temp; - - temp = printable_part (matches[0]); - crlf (); - print_filename (temp, matches[0]); - crlf (); - goto restart; - } - - /* There is more than one answer. Find out how many there are, - and find out what the maximum printed length of a single entry - is. */ - display_matches: - for (max = 0, i = 1; matches[i]; i++) - { - char *temp; - int name_length; - - temp = printable_part (matches[i]); - name_length = strlen (temp); - - if (name_length > max) - max = name_length; - } - - len = i - 1; - - /* If there are many items, then ask the user if she - really wants to see them all. */ - if (len >= rl_completion_query_items) - { - crlf (); - fprintf (rl_outstream, - "There are %d possibilities. Do you really", len); - crlf (); - fprintf (rl_outstream, "wish to see them all? (y or n)"); - fflush (rl_outstream); - if (!get_y_or_n ()) - { - crlf (); - goto restart; - } - } - - /* How many items of MAX length can we fit in the screen window? */ - max += 2; - limit = screenwidth / max; - if (limit != 1 && (limit * max == screenwidth)) - limit--; - - /* Avoid a possible floating exception. If max > screenwidth, - limit will be 0 and a divide-by-zero fault will result. */ - if (limit == 0) - limit = 1; - - /* How many iterations of the printing loop? */ - count = (len + (limit - 1)) / limit; - - /* Watch out for special case. If LEN is less than LIMIT, then - just do the inner printing loop. - 0 < len <= limit implies count = 1. */ - - /* Sort the items if they are not already sorted. */ - if (!rl_ignore_completion_duplicates) - qsort (matches + 1, len - 1, sizeof (char *), compare_strings); - - /* Print the sorted items, up-and-down alphabetically, like - ls might. */ - crlf (); - - for (i = 1; i <= count; i++) - { - for (j = 0, l = i; j < limit; j++) - { - if (l > len || !matches[l]) - break; - else - { - char *temp; - int printed_length; - - temp = printable_part (matches[l]); - printed_length = strlen (temp); - printed_length += print_filename (temp, matches[l]); - - if (j + 1 < limit) - { - for (k = 0; k < max - printed_length; k++) - putc (' ', rl_outstream); - } - } - l += count; - } - crlf (); - } - restart: - - rl_on_new_line (); - } - break; + if (delimiter) + temp_string[temp_string_index++] = delimiter; + else if (rl_completion_append_character) + temp_string[temp_string_index++] = rl_completion_append_character; + + temp_string[temp_string_index++] = '\0'; + + if (rl_filename_completion_desired) + { + filename = tilde_expand (text); + if (stat (filename, &finfo) == 0 && S_ISDIR (finfo.st_mode)) + { + if (_rl_complete_mark_directories && rl_line_buffer[rl_point] != '/') + rl_insert_text ("/"); + } + else + { + if (rl_point == rl_end) + rl_insert_text (temp_string); + } + free (filename); + } + else + { + if (rl_point == rl_end) + rl_insert_text (temp_string); + } +} - default: - fprintf (stderr, "\r\nreadline: bad value for what_to_do in rl_complete\n"); - abort (); +static void +insert_all_matches (matches, point, quote_char) + char **matches; + int point, quote_char; +{ + int i; + char *rp; + + rl_begin_undo_group (); + /* remove any opening quote character; make_quoted_replacement will add + it back. */ + if (quote_char && point && rl_line_buffer[point - 1] == quote_char) + point--; + rl_delete_text (point, rl_point); + rl_point = point; + + if (matches[1]) + { + for (i = 1; matches[i]; i++) + { + rp = make_quoted_replacement (matches[i], SINGLE_MATCH, quote_char); + rl_insert_text (rp); + rl_insert_text (" "); + if (rp != matches[i]) + free (rp); } + } + else + { + rp = make_quoted_replacement (matches[0], SINGLE_MATCH, quote_char); + rl_insert_text (rp); + rl_insert_text (" "); + if (rp != matches[0]) + free (rp); + } + rl_end_undo_group (); +} + +/* Complete the word at or before point. + WHAT_TO_DO says what to do with the completion. + `?' means list the possible completions. + TAB means do standard completion. + `*' means insert all of the possible completions. + `!' means to do standard completion, and list all possible completions if + there is more than one. */ +int +rl_complete_internal (what_to_do) + int what_to_do; +{ + char **matches, **temp_matches; + Function *our_func; + int start, end, delimiter, found_quote, nmatch, i; + char *text, *saved_line_buffer, *t; + char quote_char; + + saved_line_buffer = rl_line_buffer ? savestring (rl_line_buffer) : (char *)NULL; + + our_func = rl_completion_entry_function + ? rl_completion_entry_function + : (Function *)filename_completion_function; + + /* Only the completion entry function can change these. */ + rl_filename_completion_desired = 0; + rl_filename_quoting_desired = 1; + + rl_completion_type = what_to_do; + + /* We now look backwards for the start of a filename/variable word. */ + end = rl_point; + + found_quote = delimiter = 0; + quote_char = '\0'; + + if (rl_point) + /* This (possibly) changes rl_point. If it returns a non-zero char, + we know we have an open quote. */ + quote_char = find_completion_word (&found_quote, &delimiter); + + start = rl_point; + rl_point = end; + + text = rl_copy_text (start, end); + matches = gen_completion_matches (text, start, end, our_func, found_quote, quote_char); + free (text); - for (i = 0; matches[i]; i++) - free (matches[i]); + if (matches == 0) + { + ding (); + FREE (saved_line_buffer); + return 0; + } + + /* It seems to me that in all the cases we handle we would like + to ignore duplicate possiblilities. Scan for the text to + insert being identical to the other completions. */ + if (rl_ignore_completion_duplicates) + { + temp_matches = remove_duplicate_matches (matches); free (matches); + matches = temp_matches; } - /* Check to see if the line has changed through all of this manipulation. */ - if (saved_line_buffer) + /* If we are matching filenames, then here is our chance to + do clever processing by re-examining the list. Call the + ignore function with the array as a parameter. It can + munge the array, deleting matches as it desires. */ + if (rl_ignore_some_completions_function && + our_func == (Function *)filename_completion_function) { - if (strcmp (rl_line_buffer, saved_line_buffer) != 0) - completion_changed_buffer = 1; + for (nmatch = 1; matches[nmatch]; nmatch++) + ; + (void)(*rl_ignore_some_completions_function) (matches); + if (matches == 0 || matches[0] == 0) + { + FREE (matches); + ding (); + FREE (saved_line_buffer); + return 0; + } else - completion_changed_buffer = 0; + { + /* If we removed some matches, recompute the common prefix. */ + for (i = 1; matches[i]; i++) + ; + if (i > 1 && i < nmatch) + { + t = matches[0]; + compute_lcd_of_matches (matches, i - 1, text); + FREE (t); + } + } + } + switch (what_to_do) + { + case TAB: + case '!': + /* Insert the first match with proper quoting. */ + if (*matches[0]) + insert_match (matches[0], start, matches[1] ? MULT_MATCH : SINGLE_MATCH, quote_char); + + /* If there are more matches, ring the bell to indicate. + If we are in vi mode, Posix.2 says to not ring the bell. + If the `show-all-if-ambiguous' variable is set, display + all the matches immediately. Otherwise, if this was the + only match, and we are hacking files, check the file to + see if it was a directory. If so, and the `mark-directories' + variable is set, add a '/' to the name. If not, and we + are at the end of the line, then add a space. */ + if (matches[1]) + { + if (what_to_do == '!') + { + display_matches (matches); + break; + } + else if (rl_editing_mode != vi_mode) + ding (); /* There are other matches remaining. */ + } + else + append_to_match (matches[0], delimiter, quote_char); + + break; + + case '*': + insert_all_matches (matches, start, quote_char); + break; + + case '?': + display_matches (matches); + break; + + default: + fprintf (stderr, "\r\nreadline: bad value %d for what_to_do in rl_complete\n", what_to_do); + ding (); + FREE (saved_line_buffer); + return 1; + } + + for (i = 0; matches[i]; i++) + free (matches[i]); + free (matches); + + /* Check to see if the line has changed through all of this manipulation. */ + if (saved_line_buffer) + { + completion_changed_buffer = strcmp (rl_line_buffer, saved_line_buffer) != 0; free (saved_line_buffer); } + return 0; } @@ -956,7 +1079,10 @@ rl_complete_internal (what_to_do) `@' for symbolic links `/' for directories `*' for executables - `=' for sockets */ + `=' for sockets + `|' for FIFOs + `%' for character special devices + `#' for block special devices */ static int stat_char (filename) char *filename; @@ -964,7 +1090,7 @@ stat_char (filename) struct stat finfo; int character, r; -#if defined (S_ISLNK) +#if defined (HAVE_LSTAT) && defined (S_ISLNK) r = lstat (filename, &finfo); #else r = stat (filename, &finfo); @@ -976,6 +1102,10 @@ stat_char (filename) character = 0; if (S_ISDIR (finfo.st_mode)) character = '/'; + else if (S_ISCHR (finfo.st_mode)) + character = '%'; + else if (S_ISBLK (finfo.st_mode)) + character = '#'; #if defined (S_ISLNK) else if (S_ISLNK (finfo.st_mode)) character = '@'; @@ -984,6 +1114,10 @@ stat_char (filename) else if (S_ISSOCK (finfo.st_mode)) character = '='; #endif /* S_ISSOCK */ +#if defined (S_ISFIFO) + else if (S_ISFIFO (finfo.st_mode)) + character = '|'; +#endif else if (S_ISREG (finfo.st_mode)) { if (access (filename, X_OK) == 0) @@ -993,20 +1127,6 @@ stat_char (filename) } #endif /* VISIBLE_STATS */ -/* Stupid comparison routine for qsort () ing strings. */ -static int -compare_strings (s1, s2) - char **s1, **s2; -{ - int result; - - result = **s1 - **s2; - if (result == 0) - result = strcmp (*s1, *s2); - - return result; -} - /* A completion function for usernames. TEXT contains a partial username preceded by a random character (usually `~'). */ @@ -1015,24 +1135,20 @@ username_completion_function (text, state) int state; char *text; { -#if defined (__GO32__) +#if defined (__GO32__) || defined (__WIN32__) return (char *)NULL; #else /* !__GO32__ */ static char *username = (char *)NULL; static struct passwd *entry; static int namelen, first_char, first_char_loc; + char *value; - if (!state) + if (state == 0) { - if (username) - free (username); + FREE (username); first_char = *text; - - if (first_char == '~') - first_char_loc = 1; - else - first_char_loc = 0; + first_char_loc = first_char == '~'; username = savestring (&text[first_char_loc]); namelen = strlen (username); @@ -1042,21 +1158,18 @@ username_completion_function (text, state) while (entry = getpwent ()) { /* Null usernames should result in all users as possible completions. */ - if (namelen == 0) - break; - else if ((username[0] == entry->pw_name[0]) && - (strncmp (username, entry->pw_name, namelen) == 0)) + if (namelen == 0 || (STREQN (username, entry->pw_name, namelen))) break; } - if (!entry) + if (entry == 0) { endpwent (); return ((char *)NULL); } else { - char *value = xmalloc (2 + strlen (entry->pw_name)); + value = xmalloc (2 + strlen (entry->pw_name)); *value = *text; @@ -1069,7 +1182,7 @@ username_completion_function (text, state) } #endif /* !__GO32__ */ } - + /* **************************************************************** */ /* */ /* Completion */ @@ -1079,6 +1192,70 @@ username_completion_function (text, state) /* Non-zero means that case is not significant in completion. */ int completion_case_fold = 0; +/* Find the common prefix of the list of matches, and put it into + matches[0]. */ +static int +compute_lcd_of_matches (match_list, matches, text) + char **match_list; + int matches; + char *text; +{ + register int i, c1, c2, si; + int low; /* Count of max-matched characters. */ + + /* If only one match, just use that. Otherwise, compare each + member of the list with the next, finding out where they + stop matching. */ + if (matches == 1) + { + match_list[0] = match_list[1]; + match_list[1] = (char *)NULL; + return 1; + } + + for (i = 1, low = 100000; i < matches; i++) + { + if (completion_case_fold) + { + for (si = 0; + (c1 = _rl_to_lower(match_list[i][si])) && + (c2 = _rl_to_lower(match_list[i + 1][si])); + si++) + if (c1 != c2) + break; + } + else + { + for (si = 0; + (c1 = match_list[i][si]) && + (c2 = match_list[i + 1][si]); + si++) + if (c1 != c2) + break; + } + + if (low > si) + low = si; + } + + /* If there were multiple matches, but none matched up to even the + first character, and the user typed something, use that as the + value of matches[0]. */ + if (low == 0 && text && *text) + { + match_list[0] = xmalloc (strlen (text) + 1); + strcpy (match_list[0], text); + } + else + { + match_list[0] = xmalloc (low + 1); + strncpy (match_list[0], match_list[1], low); + match_list[0][low] = '\0'; + } + + return matches; +} + /* Return an array of (char *) which is a list of completions for TEXT. If there are no completions, return a NULL pointer. The first entry in the returned array is the substitution for TEXT. @@ -1100,15 +1277,17 @@ completion_matches (text, entry_function) int match_list_size; /* The list of matches. */ - char **match_list = - (char **)xmalloc (((match_list_size = 10) + 1) * sizeof (char *)); + char **match_list; /* Number of matches actually found. */ - int matches = 0; + int matches; /* Temporary string binder. */ char *string; + matches = 0; + match_list_size = 10; + match_list = (char **)xmalloc ((match_list_size + 1) * sizeof (char *)); match_list[1] = (char *)NULL; while (string = (*entry_function) (text, matches)) @@ -1124,50 +1303,7 @@ completion_matches (text, entry_function) /* If there were any matches, then look through them finding out the lowest common denominator. That then becomes match_list[0]. */ if (matches) - { - register int i = 1; - int low = 100000; /* Count of max-matched characters. */ - - /* If only one match, just use that. */ - if (matches == 1) - { - match_list[0] = match_list[1]; - match_list[1] = (char *)NULL; - } - else - { - /* Otherwise, compare each member of the list with - the next, finding out where they stop matching. */ - - while (i < matches) - { - register int c1, c2, si; - - if (completion_case_fold) - { - for (si = 0; - (c1 = to_lower(match_list[i][si])) && - (c2 = to_lower(match_list[i + 1][si])); - si++) - if (c1 != c2) break; - } - else - { - for (si = 0; - (c1 = match_list[i][si]) && - (c2 = match_list[i + 1][si]); - si++) - if (c1 != c2) break; - } - - if (low > si) low = si; - i++; - } - match_list[0] = xmalloc (low + 1); - strncpy (match_list[0], match_list[1], low); - match_list[0][low] = '\0'; - } - } + compute_lcd_of_matches (match_list, matches, text); else /* There were no matches. */ { free (match_list); @@ -1190,20 +1326,20 @@ filename_completion_function (text, state) static char *dirname = (char *)NULL; static char *users_dirname = (char *)NULL; static int filename_len; - - struct dirent *entry = (struct dirent *)NULL; + char *temp; + int dirlen; + struct dirent *entry; /* If we don't have any state, then do some initialization. */ - if (!state) + if (state == 0) { - char *temp; - - if (dirname) free (dirname); - if (filename) free (filename); - if (users_dirname) free (users_dirname); + FREE (dirname); + FREE (filename); + FREE (users_dirname); filename = savestring (text); - if (!*text) text = "."; + if (*text == 0) + text = "."; dirname = savestring (text); temp = strrchr (dirname, '/'); @@ -1214,29 +1350,29 @@ filename_completion_function (text, state) *temp = '\0'; } else - strcpy (dirname, "."); + { + dirname[0] = '.'; + dirname[1] = '\0'; + } /* We aren't done yet. We also support the "~user" syntax. */ /* Save the version of the directory that the user typed. */ users_dirname = savestring (dirname); - { - char *temp_dirname; - int replace_dirname; - - temp_dirname = tilde_expand (dirname); - free (dirname); - dirname = temp_dirname; - - replace_dirname = 0; - if (rl_directory_completion_hook) - replace_dirname = (*rl_directory_completion_hook) (&dirname); - if (replace_dirname) - { - free (users_dirname); - users_dirname = savestring (dirname); - } - } + + if (*dirname == '~') + { + temp = tilde_expand (dirname); + free (dirname); + dirname = temp; + } + + if (rl_directory_completion_hook && (*rl_directory_completion_hook) (&dirname)) + { + free (users_dirname); + users_dirname = savestring (dirname); + } + directory = opendir (dirname); filename_len = strlen (filename); @@ -1251,14 +1387,16 @@ filename_completion_function (text, state) /* Now that we have some state, we can read the directory. */ + entry = (struct dirent *)NULL; while (directory && (entry = readdir (directory))) { /* Special case for no filename. All entries except "." and ".." match. */ - if (!filename_len) + if (filename_len == 0) { - if ((strcmp (entry->d_name, ".") != 0) && - (strcmp (entry->d_name, "..") != 0)) + if (entry->d_name[0] != '.' || + (entry->d_name[1] && + (entry->d_name[1] != '.' || entry->d_name[2]))) break; } else @@ -1272,7 +1410,7 @@ filename_completion_function (text, state) } } - if (!entry) + if (entry == 0) { if (directory) { @@ -1299,34 +1437,33 @@ filename_completion_function (text, state) } else { - char *temp; - /* dirname && (strcmp (dirname, ".") != 0) */ if (dirname && (dirname[0] != '.' || dirname[1])) { if (rl_complete_with_tilde_expansion && *users_dirname == '~') { - int dirlen = strlen (dirname); + dirlen = strlen (dirname); temp = xmalloc (2 + dirlen + D_NAMLEN (entry)); strcpy (temp, dirname); - /* Canonicalization cuts off any final slash present. We need - to add it back. */ + /* Canonicalization cuts off any final slash present. We + may need to add it back. */ if (dirname[dirlen - 1] != '/') { - temp[dirlen] = '/'; - temp[dirlen + 1] = '\0'; + temp[dirlen++] = '/'; + temp[dirlen] = '\0'; } } else { - temp = xmalloc (1 + strlen (users_dirname) + D_NAMLEN (entry)); + dirlen = strlen (users_dirname); + temp = xmalloc (1 + dirlen + D_NAMLEN (entry)); strcpy (temp, users_dirname); } - strcat (temp, entry->d_name); + strcpy (temp + dirlen, entry->d_name); /* strcat (temp, entry->d_name); */ } else - temp = (savestring (entry->d_name)); + temp = savestring (entry->d_name); return (temp); } @@ -1338,7 +1475,8 @@ rl_tilde_expand (ignore, key) int ignore, key; { register int start, end; - char *homedir; + char *homedir, *temp; + int len; end = rl_point; start = end - 1; @@ -1346,20 +1484,20 @@ rl_tilde_expand (ignore, key) if (rl_point == rl_end && rl_line_buffer[rl_point] == '~') { homedir = tilde_expand ("~"); - goto insert; + insert_text (homedir, start, end); + return (0); } else if (rl_line_buffer[start] != '~') { - for (; !whitespace (rl_line_buffer[start]) && start >= 0; start--); + for (; !whitespace (rl_line_buffer[start]) && start >= 0; start--) + ; start++; } end = start; do - { - end++; - } - while (!whitespace (rl_line_buffer[end]) && end < rl_end); + end++; + while (whitespace (rl_line_buffer[end]) == 0 && end < rl_end); if (whitespace (rl_line_buffer[end]) || end >= rl_end) end--; @@ -1369,9 +1507,6 @@ rl_tilde_expand (ignore, key) nothing. */ if (rl_line_buffer[start] == '~') { - char *temp; - int len; - len = end - start + 1; temp = xmalloc (len + 1); strncpy (temp, rl_line_buffer + start, len); @@ -1379,12 +1514,7 @@ rl_tilde_expand (ignore, key) homedir = tilde_expand (temp); free (temp); - insert: - rl_begin_undo_group (); - rl_delete_text (start, end + 1); - rl_point = start; - rl_insert_text (homedir); - rl_end_undo_group (); + insert_text (homedir, start, end); } return (0); @@ -1410,50 +1540,3 @@ rl_strpbrk (string1, string2) } return ((char *)NULL); } - -#if defined (STATIC_MALLOC) - -/* **************************************************************** */ -/* */ -/* xmalloc and xrealloc () */ -/* */ -/* **************************************************************** */ - -static void memory_error_and_abort (); - -static char * -xmalloc (bytes) - int bytes; -{ - char *temp = (char *)malloc (bytes); - - if (!temp) - memory_error_and_abort (); - return (temp); -} - -static char * -xrealloc (pointer, bytes) - char *pointer; - int bytes; -{ - char *temp; - - if (!pointer) - temp = (char *)malloc (bytes); - else - temp = (char *)realloc (pointer, bytes); - - if (!temp) - memory_error_and_abort (); - - return (temp); -} - -static void -memory_error_and_abort () -{ - fprintf (stderr, "readline: Out of virtual memory!\n"); - abort (); -} -#endif /* STATIC_MALLOC */ diff --git a/lib/readline/display.c b/lib/readline/display.c index daf736c..c0dff1f 100644 --- a/lib/readline/display.c +++ b/lib/readline/display.c @@ -22,7 +22,7 @@ #define READLINE_LIBRARY #if defined (HAVE_CONFIG_H) -# include "config.h" +# include #endif #include @@ -43,6 +43,9 @@ /* System-specific feature definitions and include files. */ #include "rldefs.h" +/* Termcap library stuff. */ +#include "tcap.h" + /* Some standard library routines. */ #include "readline.h" #include "history.h" @@ -55,20 +58,22 @@ extern char *strchr (), *strrchr (); imported from readline.c. */ extern char *rl_prompt; extern int readline_echoing_p; -extern char *term_clreol, *term_im, *term_ic, *term_ei, *term_DC; -/* Termcap variables. */ -extern char *term_up, *term_dc, *term_cr, *term_IC; -extern int screenheight, screenwidth, screenchars; -extern int terminal_can_insert, term_xn; - -extern void _rl_output_some_chars (); -extern int _rl_output_character_function (); extern int _rl_output_meta_chars; extern int _rl_horizontal_scroll_mode; extern int _rl_mark_modified_lines; extern int _rl_prefer_visible_bell; +/* Variables and functions imported from terminal.c */ +extern void _rl_output_some_chars (); +extern int _rl_output_character_function (); +extern int _rl_backspace (); + +extern char *term_clreol, *term_im, *term_ic, *term_ei, *term_DC; +extern char *term_up, *term_dc, *term_cr, *term_IC; +extern int screenheight, screenwidth, screenchars; +extern int terminal_can_insert, _rl_term_autowrap; + /* Pseudo-global functions (local to the readline library) exported by this file. */ void _rl_move_cursor_relative (), _rl_output_some_chars (); @@ -76,6 +81,9 @@ void _rl_move_vert (); static void update_line (), clear_to_eol (), space_to_eol (); static void delete_chars (), insert_some_chars (); +static void cr (); + +static int *inv_lbreaks, *vis_lbreaks; extern char *xmalloc (), *xrealloc (); @@ -110,10 +118,15 @@ extern char *xmalloc (), *xrealloc (); this function know that the display has been fixed by setting the RL_DISPLAY_FIXED variable. This is good for efficiency. */ +/* Application-specific redisplay function. */ +VFunction *rl_redisplay_function = rl_redisplay; + /* Global variables declared here. */ /* What YOU turn on when you have handled all redisplay yourself. */ int rl_display_fixed = 0; +int _rl_suppress_redisplay = 0; + /* The stuff that gets printed out before the actual text of the line. This is usually pointing to rl_prompt. */ char *rl_display_prompt = (char *)NULL; @@ -129,7 +142,7 @@ int _rl_vis_botlin = 0; /* Variables used only in this file. */ /* The last left edge of text that was displayed. This is used when doing horizontal scrolling. It shifts in thirds of a screenwidth. */ -static int last_lmargin = 0; +static int last_lmargin; /* The line display buffers. One is the line currently displayed on the screen. The other is the line about to be displayed. */ @@ -140,26 +153,32 @@ static char *invisible_line = (char *)NULL; static char msg_buf[128]; /* Non-zero forces the redisplay even if we thought it was unnecessary. */ -static int forced_display = 0; +static int forced_display; /* Default and initial buffer size. Can grow. */ static int line_size = 1024; -static char *last_prompt_string = (char *)NULL; static char *local_prompt, *local_prompt_prefix; static int visible_length, prefix_length; /* The number of invisible characters in the line currently being displayed on the screen. */ -static int visible_wrap_offset = 0; +static int visible_wrap_offset; + +/* static so it can be shared between rl_redisplay and update_line */ +static int wrap_offset; + +/* The index of the last invisible_character in the prompt string. */ +static int last_invisible; /* The length (buffer offset) of the first line of the last (possibly multi-line) buffer displayed on the screen. */ -static int visible_first_line_len = 0; +static int visible_first_line_len; /* Expand the prompt string S and return the number of visible characters in *LP, if LP is not null. This is currently more-or-less - a placeholder for expansion. */ + a placeholder for expansion. LIP, if non-null is a place to store the + index of the last invisible character in ther eturned string. */ /* Current implementation: \001 (^A) start non-visible characters @@ -169,12 +188,12 @@ static int visible_first_line_len = 0; \002 are assumed to be `visible'. */ static char * -expand_prompt (pmt, lp) +expand_prompt (pmt, lp, lip) char *pmt; - int *lp; + int *lp, *lip; { char *r, *ret, *p; - int l, rl, ignoring; + int l, rl, last, ignoring; /* Short-circuit if we can. */ if (strchr (pmt, RL_PROMPT_START_IGNORE) == 0) @@ -185,10 +204,10 @@ expand_prompt (pmt, lp) return r; } - l = pmt ? strlen (pmt) : 0; + l = strlen (pmt); r = ret = xmalloc (l + 1); - for (rl = ignoring = 0, p = pmt; p && *p; p++) + for (rl = ignoring = last = 0, p = pmt; p && *p; p++) { /* This code strips the invisible character string markers RL_PROMPT_START_IGNORE and RL_PROMPT_END_IGNORE */ @@ -200,6 +219,7 @@ expand_prompt (pmt, lp) else if (ignoring && *p == RL_PROMPT_END_IGNORE) { ignoring = 0; + last = r - ret - 1; continue; } else @@ -213,6 +233,8 @@ expand_prompt (pmt, lp) *r = '\0'; if (lp) *lp = rl; + if (lip) + *lip = last; return ret; } @@ -246,15 +268,16 @@ rl_expand_prompt (prompt) if (local_prompt_prefix) free (local_prompt_prefix); local_prompt = local_prompt_prefix = (char *)0; + last_invisible = 0; - if (prompt == 0 || *prompt == '\0') + if (prompt == 0 || *prompt == 0) return (0); p = strrchr (prompt, '\n'); if (!p) { /* The prompt is only one line. */ - local_prompt = expand_prompt (prompt, &visible_length); + local_prompt = expand_prompt (prompt, &visible_length, &last_invisible); local_prompt_prefix = (char *)0; return (visible_length); } @@ -262,11 +285,11 @@ rl_expand_prompt (prompt) { /* The prompt spans multiple lines. */ t = ++p; - local_prompt = expand_prompt (p, &visible_length); + local_prompt = expand_prompt (p, &visible_length, &last_invisible); c = *t; *t = '\0'; /* The portion of the prompt string up to and including the final newline is now null-terminated. */ - local_prompt_prefix = expand_prompt (prompt, &prefix_length); + local_prompt_prefix = expand_prompt (prompt, &prefix_length, (int *)NULL); *t = c; return (prefix_length); } @@ -276,9 +299,10 @@ rl_expand_prompt (prompt) void rl_redisplay () { - register int in, out, c, linenum; - register char *line = invisible_line; - int c_pos = 0, inv_botlin = 0, wrap_offset, wrap_column; + register int in, out, c, linenum, cursor_linenum; + register char *line; + int c_pos, inv_botlin, lb_botlin, lb_linenum; + int newlines, lpos; char *prompt_this_line; if (!readline_echoing_p) @@ -287,25 +311,32 @@ rl_redisplay () if (!rl_display_prompt) rl_display_prompt = ""; - if (!invisible_line) + if (invisible_line == 0) { visible_line = xmalloc (line_size); invisible_line = xmalloc (line_size); - line = invisible_line; for (in = 0; in < line_size; in++) { visible_line[in] = 0; invisible_line[in] = 1; } + + /* should be enough, but then again, this is just for testing. */ + inv_lbreaks = (int *)malloc (256 * sizeof (int)); + vis_lbreaks = (int *)malloc (256 * sizeof (int)); + inv_lbreaks[0] = vis_lbreaks[0] = 0; + rl_on_new_line (); } /* Draw the line into the buffer. */ c_pos = -1; + line = invisible_line; + out = inv_botlin = 0; + /* Mark the line as modified or not. We only do this for history lines. */ - out = 0; if (_rl_mark_modified_lines && current_history () && rl_undo_list) { line[out++] = '*'; @@ -322,15 +353,17 @@ rl_redisplay () one passed to readline()), use the values we have already expanded. If not, use what's already in rl_display_prompt. WRAP_OFFSET is the number of non-visible characters in the prompt string. */ - if (rl_display_prompt == rl_prompt) + if (rl_display_prompt == rl_prompt || local_prompt) { int local_len = local_prompt ? strlen (local_prompt) : 0; if (local_prompt_prefix && forced_display) _rl_output_some_chars (local_prompt_prefix, strlen (local_prompt_prefix)); if (local_len > 0) - strncpy (line + out, local_prompt, local_len); - out += local_len; + { + strncpy (line + out, local_prompt, local_len); + out += local_len; + } line[out] = '\0'; wrap_offset = local_len - visible_length; } @@ -344,7 +377,13 @@ rl_redisplay () { prompt_this_line++; if (forced_display) - _rl_output_some_chars (rl_display_prompt, prompt_this_line - rl_display_prompt); + { + _rl_output_some_chars (rl_display_prompt, prompt_this_line - rl_display_prompt); + /* Make sure we are at column zero even after a newline, + regardless of the state of terminal output processing. */ + if (prompt_this_line[-2] != '\r') + cr (); + } } pmtlen = strlen (prompt_this_line); @@ -354,7 +393,20 @@ rl_redisplay () wrap_offset = 0; } - for (in = 0; in < rl_end; in++) +#define CHECK_LPOS() \ + do { \ + lpos++; \ + if (lpos >= screenwidth) \ + { \ + inv_lbreaks[++newlines] = out; \ + lpos = 0; \ + } \ + } while (0) + + /* inv_lbreaks[i] is where line i starts in the buffer. */ + inv_lbreaks[newlines = 0] = 0; + + for (in = 0, lpos = out - wrap_offset; in < rl_end; in++) { c = (unsigned char)rl_line_buffer[in]; @@ -367,42 +419,88 @@ rl_redisplay () } if (in == rl_point) - c_pos = out; + { + c_pos = out; + lb_linenum = newlines; + } if (META_CHAR (c)) { if (_rl_output_meta_chars == 0) { sprintf (line + out, "\\%o", c); + + if (lpos + 4 >= screenwidth) + { + register int temp; + + temp = screenwidth - lpos; + inv_lbreaks[++newlines] = out + temp; + lpos = 4 - temp; + } + else + lpos += 4; + out += 4; } else - line[out++] = c; + { + line[out++] = c; + CHECK_LPOS(); + } } #if defined (DISPLAY_TABS) else if (c == '\t') { - register int newout = (out | (int)7) + 1; - while (out < newout) - line[out++] = ' '; + register int temp, newout; + newout = (out | (int)7) + 1; + temp = newout - out; + if (lpos + temp >= screenwidth) + { + register int temp2; + temp2 = screenwidth - lpos; + inv_lbreaks[++newlines] = out + temp2; + lpos = temp - temp2; + while (out < newout) + line[out++] = ' '; + } + else + { + while (out < newout) + line[out++] = ' '; + lpos += temp; + } } #endif - else if (c < ' ') + else if (c == '\n' && _rl_horizontal_scroll_mode == 0 && term_up && *term_up) + { + line[out++] = '\0'; /* XXX - sentinel */ + inv_lbreaks[++newlines] = out; + lpos = 0; + } + else if (CTRL_CHAR (c) || c == RUBOUT) { line[out++] = '^'; - line[out++] = UNCTRL (c); /* XXX was c ^ 0x40 */ + CHECK_LPOS(); + line[out++] = CTRL_CHAR (c) ? UNCTRL (c) : '?'; + CHECK_LPOS(); } - else if (c == 127) + else { - line[out++] = '^'; - line[out++] = '?'; + line[out++] = c; + CHECK_LPOS(); } - else - line[out++] = c; } line[out] = '\0'; if (c_pos < 0) - c_pos = out; + { + c_pos = out; + lb_linenum = newlines; + } + + inv_botlin = lb_botlin = newlines; + inv_lbreaks[newlines+1] = out; + cursor_linenum = lb_linenum; /* C_POS == position in buffer where cursor should be placed. */ @@ -415,10 +513,9 @@ rl_redisplay () otherwise, let long lines display in a single terminal line, and horizontally scroll it. */ - if (!_rl_horizontal_scroll_mode && term_up && *term_up) + if (_rl_horizontal_scroll_mode == 0 && term_up && *term_up) { - int total_screen_chars = screenchars; - int nleft, cursor_linenum, pos, changed_screen_line; + int nleft, pos, changed_screen_line; if (!rl_display_fixed || forced_display) { @@ -426,42 +523,35 @@ rl_redisplay () /* If we have more than a screenful of material to display, then only display a screenful. We should display the last screen, - not the first. I'll fix this in a minute. */ - if (out >= total_screen_chars) - out = total_screen_chars - 1; - - /* Number of screen lines to display. The first line wraps at - (screenwidth + wrap_offset) chars, the rest of the lines have - screenwidth chars. */ - nleft = out - wrap_offset + term_xn - 1; - inv_botlin = (nleft > 0) ? nleft / screenwidth : 0; + not the first. */ + if (out >= screenchars) + out = screenchars - 1; /* The first line is at character position 0 in the buffer. The - second and subsequent lines start at N * screenwidth, offset by - OFFSET. OFFSET is wrap_offset for the invisible line and - visible_wrap_offset for the line currently displayed. */ + second and subsequent lines start at inv_lbreaks[N], offset by + OFFSET (which has already been calculated above). */ #define W_OFFSET(line, offset) ((line) == 0 ? offset : 0) -#define L_OFFSET(n, offset) ((n) > 0 ? ((n) * screenwidth) + (offset) : 0) -#define VIS_CHARS(line) &visible_line[L_OFFSET((line), visible_wrap_offset)] +#define VIS_LLEN(l) ((l) > _rl_vis_botlin ? 0 : (vis_lbreaks[l+1] - vis_lbreaks[l])) +#define INV_LLEN(l) (inv_lbreaks[l+1] - inv_lbreaks[l]) +#define VIS_CHARS(line) (visible_line + vis_lbreaks[line]) #define VIS_LINE(line) ((line) > _rl_vis_botlin) ? "" : VIS_CHARS(line) -#define INV_LINE(line) &invisible_line[L_OFFSET((line), wrap_offset)] +#define INV_LINE(line) (invisible_line + inv_lbreaks[line]) /* For each line in the buffer, do the updating display. */ for (linenum = 0; linenum <= inv_botlin; linenum++) { update_line (VIS_LINE(linenum), INV_LINE(linenum), linenum, - screenwidth + W_OFFSET(linenum, visible_wrap_offset), - screenwidth + W_OFFSET(linenum, wrap_offset), - inv_botlin); + VIS_LLEN(linenum), INV_LLEN(linenum), inv_botlin); /* If this is the line with the prompt, we might need to compensate for invisible characters in the new line. Do this only if there is not more than one new line (which implies that we completely overwrite the old visible line) - and the new line is shorter than the old. */ + and the new line is shorter than the old. Make sure we are + at the end of the new line before clearing. */ if (linenum == 0 && - inv_botlin == 0 && + inv_botlin == 0 && _rl_last_c_pos == out && (wrap_offset > visible_wrap_offset) && (_rl_last_c_pos < visible_first_line_len)) { @@ -472,7 +562,7 @@ rl_redisplay () /* Since the new first line is now visible, save its length. */ if (linenum == 0) - visible_first_line_len = (inv_botlin > 0) ? screenwidth : out - wrap_offset; + visible_first_line_len = (inv_botlin > 0) ? inv_lbreaks[1] : out - wrap_offset; } /* We may have deleted some lines. If so, clear the left over @@ -491,11 +581,6 @@ rl_redisplay () } _rl_vis_botlin = inv_botlin; - /* Move the cursor where it should be. */ - /* Which line? */ - nleft = c_pos - wrap_offset + term_xn - 1; - cursor_linenum = (nleft > 0) ? nleft / screenwidth : 0; - /* CHANGED_SCREEN_LINE is set to 1 if we have moved to a different screen line during this redisplay. */ changed_screen_line = _rl_last_v_pos != cursor_linenum; @@ -512,10 +597,12 @@ rl_redisplay () /* We have to reprint the prompt if it contains invisible characters, since it's not generally OK to just reprint - the characters from the current cursor position. */ + the characters from the current cursor position. But we + only need to reprint it if the cursor is before the last + invisible character in the prompt string. */ nleft = visible_length + wrap_offset; if (cursor_linenum == 0 && wrap_offset > 0 && _rl_last_c_pos > 0 && - _rl_last_c_pos <= nleft && local_prompt) + _rl_last_c_pos <= last_invisible && local_prompt) { if (term_cr) tputs (term_cr, 1, _rl_output_character_function); @@ -525,17 +612,17 @@ rl_redisplay () /* Where on that line? And where does that line start in the buffer? */ - pos = L_OFFSET(cursor_linenum, wrap_offset); + pos = inv_lbreaks[cursor_linenum]; /* nleft == number of characters in the line buffer between the start of the line and the cursor position. */ nleft = c_pos - pos; - /* Since backspace() doesn't know about invisible characters in the + /* Since _rl_backspace() doesn't know about invisible characters in the prompt, and there's no good way to tell it, we compensate for - those characters here and call backspace() directly. */ + those characters here and call _rl_backspace() directly. */ if (wrap_offset && cursor_linenum == 0 && nleft < _rl_last_c_pos) { - backspace (_rl_last_c_pos - nleft); + _rl_backspace (_rl_last_c_pos - nleft); _rl_last_c_pos = nleft; } @@ -638,8 +725,11 @@ rl_redisplay () /* Swap visible and non-visible lines. */ { char *temp = visible_line; + int *itemp = vis_lbreaks; visible_line = invisible_line; invisible_line = temp; + vis_lbreaks = inv_lbreaks; + inv_lbreaks = itemp; rl_display_fixed = 0; /* If we are displaying on a single line, and last_lmargin is > 0, we are not displaying any invisible characters, so set visible_wrap_offset @@ -670,10 +760,11 @@ new: eddie> Oh, my little buggy says to me, as lurgid as static void update_line (old, new, current_line, omax, nmax, inv_botlin) register char *old, *new; - int current_line, omax, nmax; + int current_line, omax, nmax, inv_botlin; { register char *ofd, *ols, *oe, *nfd, *nls, *ne; int temp, lendiff, wsatend, od, nd; + int current_invis_chars; /* If we're at the right edge of a terminal that supports xn, we're ready to wrap around, so do so. This fixes problems with knowing @@ -681,7 +772,7 @@ update_line (old, new, current_line, omax, nmax, inv_botlin) emulators. In this calculation, TEMP is the physical screen position of the cursor. */ temp = _rl_last_c_pos - W_OFFSET(_rl_last_v_pos, visible_wrap_offset); - if (temp == screenwidth && term_xn && !_rl_horizontal_scroll_mode + if (temp == screenwidth && _rl_term_autowrap && !_rl_horizontal_scroll_mode && _rl_last_v_pos == current_line - 1) { if (new[0]) @@ -734,33 +825,53 @@ update_line (old, new, current_line, omax, nmax, inv_botlin) nls++; } - _rl_move_vert (current_line); + /* count of invisible characters in the current invisible line. */ + current_invis_chars = W_OFFSET (current_line, wrap_offset); + if (_rl_last_v_pos != current_line) + { + _rl_move_vert (current_line); + if (current_line == 0 && visible_wrap_offset) + _rl_last_c_pos += visible_wrap_offset; + } /* If this is the first line and there are invisible characters in the - prompt string, and the prompt string has not changed, then redraw - the entire prompt string. We can only do this reliably if the - terminal supports a `cr' capability. + prompt string, and the prompt string has not changed, and the current + cursor position is before the last invisible character in the prompt, + and the index of the character to move to is past the end of the prompt + string, then redraw the entire prompt string. We can only do this + reliably if the terminal supports a `cr' capability. - This is more than just an efficiency hack -- there is a problem with - redrawing portions of the prompt string if they contain terminal - escape sequences (like drawing the `unbold' sequence without a - corresponding `bold') that manifests itself on certain terminals. */ + This is not an efficiency hack -- there is a problem with redrawing + portions of the prompt string if they contain terminal escape + sequences (like drawing the `unbold' sequence without a corresponding + `bold') that manifests itself on certain terminals. */ lendiff = local_prompt ? strlen (local_prompt) : 0; + od = ofd - old; /* index of first difference in visible line */ if (current_line == 0 && !_rl_horizontal_scroll_mode && - lendiff > visible_length && - _rl_last_c_pos > 0 && (ofd - old) >= lendiff && term_cr) + term_cr && lendiff > visible_length && _rl_last_c_pos > 0 && + od > lendiff && _rl_last_c_pos < last_invisible) { tputs (term_cr, 1, _rl_output_character_function); _rl_output_some_chars (local_prompt, lendiff); _rl_last_c_pos = lendiff; } - _rl_move_cursor_relative (ofd - old, old); + _rl_move_cursor_relative (od, old); /* if (len (new) > len (old)) */ lendiff = (nls - nfd) - (ols - ofd); + /* If we are changing the number of invisible characters in a line, and + the spot of first difference is before the end of the invisible chars, + lendiff needs to be adjusted. */ + if (current_line == 0 && !_rl_horizontal_scroll_mode && + current_invis_chars != visible_wrap_offset) + { + temp = visible_wrap_offset - current_invis_chars; + lendiff += temp; + } + /* Insert (diff (len (old), len (new)) ch. */ temp = ne - nfd; if (lendiff > 0) @@ -771,25 +882,36 @@ update_line (old, new, current_line, omax, nmax, inv_botlin) use the terminal's capabilities. If we're growing the number of lines, make sure we actually cause the new line to wrap around on auto-wrapping terminals. */ - if (terminal_can_insert && ((2 * temp) >= lendiff || term_IC) && (!term_xn || !gl)) + if (terminal_can_insert && ((2 * temp) >= lendiff || term_IC) && (!_rl_term_autowrap || !gl)) { /* If lendiff > visible_length and _rl_last_c_pos == 0 and _rl_horizontal_scroll_mode == 1, inserting the characters with term_IC or term_ic will screw up the screen because of the invisible characters. We need to just draw them. */ if (*ols && (!_rl_horizontal_scroll_mode || _rl_last_c_pos > 0 || - lendiff <= visible_length)) + lendiff <= visible_length || !current_invis_chars)) { insert_some_chars (nfd, lendiff); _rl_last_c_pos += lendiff; } - else + else if (*ols == 0) { /* At the end of a line the characters do not have to be "inserted". They can just be placed on the screen. */ + /* However, this screws up the rest of this block, which + assumes you've done the insert because you can. */ _rl_output_some_chars (nfd, lendiff); _rl_last_c_pos += lendiff; } + else + { + /* We have horizontal scrolling and we are not inserting at + the end. We have invisible characters in this line. This + is a dumb update. */ + _rl_output_some_chars (nfd, temp); + _rl_last_c_pos += temp; + return; + } /* Copy (new) chars to screen from first diff to last match. */ temp = nls - nfd; if ((temp - lendiff) > 0) @@ -837,7 +959,7 @@ update_line (old, new, current_line, omax, nmax, inv_botlin) _rl_last_c_pos += temp; } lendiff = (oe - old) - (ne - new); - if (term_xn && current_line < inv_botlin) + if (_rl_term_autowrap && current_line < inv_botlin) space_to_eol (lendiff); else clear_to_eol (lendiff); @@ -846,6 +968,7 @@ update_line (old, new, current_line, omax, nmax, inv_botlin) } /* Tell the update routines that we have moved onto a new (empty) line. */ +int rl_on_new_line () { if (visible_line) @@ -853,21 +976,26 @@ rl_on_new_line () _rl_last_c_pos = _rl_last_v_pos = 0; _rl_vis_botlin = last_lmargin = 0; + if (vis_lbreaks) + vis_lbreaks[0] = vis_lbreaks[1] = 0; + visible_wrap_offset = 0; return 0; } /* Actually update the display, period. */ +int rl_forced_update_display () { if (visible_line) { register char *temp = visible_line; - while (*temp) *temp++ = '\0'; + while (*temp) + *temp++ = '\0'; } rl_on_new_line (); forced_display++; - rl_redisplay (); + (*rl_redisplay_function) (); return 0; } @@ -888,7 +1016,8 @@ _rl_move_cursor_relative (new, data) of moving backwards. */ /* i == current physical cursor position. */ i = _rl_last_c_pos - W_OFFSET(_rl_last_v_pos, visible_wrap_offset); - if (CR_FASTER (new, _rl_last_c_pos) || (term_xn && i == screenwidth)) + if (new == 0 || CR_FASTER (new, _rl_last_c_pos) || + (_rl_term_autowrap && i == screenwidth)) { #if defined (__MSDOS__) putc ('\r', rl_outstream); @@ -924,7 +1053,7 @@ _rl_move_cursor_relative (new, data) #endif /* HACK_TERMCAP_MOTION */ } else if (_rl_last_c_pos != new) - backspace (_rl_last_c_pos - new); + _rl_backspace (_rl_last_c_pos - new); _rl_last_c_pos = new; } @@ -966,6 +1095,7 @@ _rl_move_vert (to) /* Physically print C on rl_outstream. This is for functions which know how to optimize the display. Return the number of characters output. */ +int rl_show_char (c) int c; { @@ -978,14 +1108,14 @@ rl_show_char (c) } #if defined (DISPLAY_TABS) - if (c < 32 && c != '\t') + if ((CTRL_CHAR (c) && c != '\t') || c == RUBOUT) #else - if (c < 32) + if (CTRL_CHAR (c) || c == RUBOUT) #endif /* !DISPLAY_TABS */ { fprintf (rl_outstream, "C-"); n += 2; - c += 64; + c = CTRL_CHAR (c) ? UNCTRL (c) : '?'; } putc (c, rl_outstream); @@ -1013,47 +1143,65 @@ rl_character_len (c, pos) #endif /* !DISPLAY_TABS */ } + if (CTRL_CHAR (c) || c == RUBOUT) + return (2); + return ((isprint (uc)) ? 1 : 2); } /* How to print things in the "echo-area". The prompt is treated as a mini-modeline. */ -#if defined (HAVE_VARARGS_H) +#if defined (USE_VARARGS) +int +#if defined (PREFER_STDARG) +rl_message (const char *format, ...) +#else rl_message (va_alist) va_dcl +#endif { - char *format; va_list args; +#if defined (PREFER_VARARGS) + char *format; +#endif +#if defined (PREFER_STDARG) + va_start (args, format); +#else va_start (args); format = va_arg (args, char *); +#endif + vsprintf (msg_buf, format, args); va_end (args); rl_display_prompt = msg_buf; - rl_redisplay (); + (*rl_redisplay_function) (); return 0; } -#else /* !HAVE_VARARGS_H */ +#else /* !USE_VARARGS */ +int rl_message (format, arg1, arg2) char *format; { sprintf (msg_buf, format, arg1, arg2); rl_display_prompt = msg_buf; - rl_redisplay (); + (*rl_redisplay_function) (); return 0; } -#endif /* !HAVE_VARARGS_H */ +#endif /* !USE_VARARGS */ /* How to clear things from the "echo-area". */ +int rl_clear_message () { rl_display_prompt = rl_prompt; - rl_redisplay (); + (*rl_redisplay_function) (); return 0; } +int rl_reset_line_state () { rl_on_new_line (); @@ -1063,6 +1211,70 @@ rl_reset_line_state () return 0; } +static char *saved_local_prompt; +static char *saved_local_prefix; +static int saved_last_invisible; +static int saved_visible_length; + +void +_rl_save_prompt () +{ + saved_local_prompt = local_prompt; + saved_local_prefix = local_prompt_prefix; + saved_last_invisible = last_invisible; + saved_visible_length = visible_length; + + local_prompt = local_prompt_prefix = (char *)0; + last_invisible = visible_length = 0; +} + +void +_rl_restore_prompt () +{ + if (local_prompt) + free (local_prompt); + if (local_prompt_prefix) + free (local_prompt_prefix); + + local_prompt = saved_local_prompt; + local_prompt_prefix = saved_local_prefix; + last_invisible = saved_last_invisible; + visible_length = saved_visible_length; +} + +char * +_rl_make_prompt_for_search (pchar) + int pchar; +{ + int len; + char *pmt; + + _rl_save_prompt (); + + if (saved_local_prompt == 0) + { + len = (rl_prompt && *rl_prompt) ? strlen (rl_prompt) : 0; + pmt = xmalloc (len + 2); + if (len) + strcpy (pmt, rl_prompt); + pmt[len] = pchar; + pmt[len+1] = '\0'; + } + else + { + len = *saved_local_prompt ? strlen (saved_local_prompt) : 0; + pmt = xmalloc (len + 2); + if (len) + strcpy (pmt, saved_local_prompt); + pmt[len] = pchar; + pmt[len+1] = '\0'; + local_prompt = savestring (pmt); + last_invisible = saved_last_invisible; + visible_length = saved_visible_length + 1; + } + return pmt; +} + /* Quick redisplay hack when erasing characters at the end of the line. */ void _rl_erase_at_end_of_line (l) @@ -1070,10 +1282,10 @@ _rl_erase_at_end_of_line (l) { register int i; - backspace (l); + _rl_backspace (l); for (i = 0; i < l; i++) putc (' ', rl_outstream); - backspace (l); + _rl_backspace (l); for (i = 0; i < l; i++) visible_line[--_rl_last_c_pos] = '\0'; rl_display_fixed++; @@ -1132,7 +1344,7 @@ insert_some_chars (string, count) /* If IC is defined, then we do not have to "enter" insert mode. */ if (term_IC) { - char *tgoto (), *buffer; + char *buffer; buffer = tgoto (term_IC, 0, count); tputs (buffer, 1, _rl_output_character_function); _rl_output_some_chars (string, count); @@ -1186,7 +1398,7 @@ delete_chars (count) if (term_DC && *term_DC) { - char *tgoto (), *buffer; + char *buffer; buffer = tgoto (term_DC, count, count); tputs (buffer, count, _rl_output_character_function); } @@ -1205,17 +1417,20 @@ _rl_update_final () int full_lines; full_lines = 0; - if (_rl_vis_botlin && visible_line[screenwidth * _rl_vis_botlin] == 0) + /* If the cursor is the only thing on an otherwise-blank last line, + compensate so we don't print an extra CRLF. */ + if (_rl_vis_botlin && _rl_last_c_pos == 0 && + visible_line[inv_lbreaks[_rl_vis_botlin]+1] == 0) { _rl_vis_botlin--; full_lines = 1; } _rl_move_vert (_rl_vis_botlin); - if (full_lines && term_xn) + /* If we've wrapped lines, remove the final xterm line-wrap flag. */ + if (full_lines && _rl_term_autowrap && (VIS_LLEN(_rl_vis_botlin) == screenwidth)) { - /* Remove final line-wrap flag in xterm. */ char *last_line; - last_line = &visible_line[screenwidth * _rl_vis_botlin]; + last_line = &visible_line[inv_lbreaks[_rl_vis_botlin]]; _rl_move_cursor_relative (screenwidth - 1, last_line); clear_to_eol (0); putc (last_line[screenwidth - 1], rl_outstream); @@ -1274,3 +1489,15 @@ _rl_redisplay_after_sigwinch () else rl_forced_update_display (); } + +void +_rl_clean_up_for_exit () +{ + if (readline_echoing_p) + { + _rl_move_vert (_rl_vis_botlin); + _rl_vis_botlin = 0; + fflush (rl_outstream); + rl_restart_output (); + } +} diff --git a/lib/readline/doc/Makefile b/lib/readline/doc/Makefile index 72b8ce7..9dbab24 100644 --- a/lib/readline/doc/Makefile +++ b/lib/readline/doc/Makefile @@ -1,10 +1,11 @@ -# This makefile for History library documentation is in -*- text -*- mode. +# This makefile for Readline library documentation is in -*- text -*- mode. # Emacs likes it that way. +TEXI2DVI = texi2dvi -DOC_SUPPORT = ../../doc-support/ -TEXINDEX = $(DOC_SUPPORT)/texindex +RM = rm -f -TEX = tex +INSTALL_DATA = cp +infodir = /usr/local/info RLSRC = rlman.texinfo rluser.texinfo rltech.texinfo HISTSRC = hist.texinfo hsuser.texinfo hstech.texinfo @@ -12,26 +13,23 @@ HISTSRC = hist.texinfo hsuser.texinfo hstech.texinfo DVIOBJ = readline.dvi history.dvi INFOOBJ = readline.info history.info PSOBJ = readline.ps history.ps +HTMLOBJ = readline.html history.html -all: info dvi +all: info dvi html readline.dvi: $(RLSRC) - $(TEX) rlman.texinfo - $(TEXINDEX) rlman.?? - $(TEX) rlman.texinfo + $(TEXI2DVI) rlman.texinfo mv rlman.dvi readline.dvi readline.info: $(RLSRC) - makeinfo rlman.texinfo + makeinfo --no-split -o $@ rlman.texinfo history.dvi: ${HISTSRC} - $(TEX) hist.texinfo - $(TEXINDEX) hist.?? - $(TEX) hist.texinfo + $(TEXI2DVI) hist.texinfo mv hist.dvi history.dvi history.info: ${HISTSRC} - makeinfo hist.texinfo + makeinfo --no-split -o $@ hist.texinfo readline.ps: readline.dvi dvips -D 300 -o $@ readline.dvi @@ -39,17 +37,33 @@ readline.ps: readline.dvi history.ps: history.dvi dvips -D 300 -o $@ history.dvi +readline.html: ${RLSRC} + texi2html rlman.texinfo + sed -e 's:rlman.html:readline.html:' -e 's:rlman_toc.html:readline_toc.html:' rlman.html > readline.html + sed -e 's:rlman.html:readline.html:' -e 's:rlman_toc.html:readline_toc.html:' rlman_toc.html > readline_toc.html + rm -f rlman.html rlman_toc.html + +history.html: ${HISTSRC} + texi2html hist.texinfo + sed -e 's:hist.html:history.html:' -e 's:hist_toc.html:history_toc.html:' hist.html > history.html + sed -e 's:hist.html:history.html:' -e 's:hist_toc.html:history_toc.html:' hist_toc.html > history_toc.html + rm -f hist.html hist_toc.html + info: $(INFOOBJ) dvi: $(DVIOBJ) ps: $(PSOBJ) +html: $(HTMLOBJ) +clean: + $(RM) *.aux *.cp *.fn *.ky *.log *.pg *.toc *.tp *.vr *.cps *.pgs \ + *.fns *.kys *.tps *.vrs *.o core -$(TEXINDEX): - (cd $(DOC_SUPPORT); $(MAKE) $(MFLAGS) CFLAGS='$(CFLAGS)' texindex) +distclean: clean +mostlyclean: clean -distclean mostlyclean clean: - rm -f *.aux *.cp *.fn *.ky *.log *.pg *.toc *.tp *.vr *.cps *.pgs \ - *.fns *.kys *.tps *.vrs *.o core +maintainer-clean: clean + $(RM) *.dvi *.info *.info-* *.ps *.html -maintainer-clean realclean: clean - rm -f *.dvi *.info *.info-* *.ps +install: info + ${INSTALL_DATA} readline.info $(infodir)/readline.info + ${INSTALL_DATA} history.info $(infodir)/history.info diff --git a/lib/readline/doc/hist.texinfo b/lib/readline/doc/hist.texinfo index cc80efa..aa04553 100644 --- a/lib/readline/doc/hist.texinfo +++ b/lib/readline/doc/hist.texinfo @@ -7,20 +7,20 @@ @setchapternewpage odd @ignore -last change: Wed Jul 20 09:57:17 EDT 1994 +last change: Thu Mar 21 16:07:29 EST 1996 @end ignore -@set EDITION 2.0 -@set VERSION 2.0 -@set UPDATED 20 July 1994 -@set UPDATE-MONTH July 1994 +@set EDITION 2.1 +@set VERSION 2.1 +@set UPDATED 21 March 1996 +@set UPDATE-MONTH March 1996 @ifinfo This document describes the GNU History library, a programming tool that provides a consistent user interface for recalling lines of previously typed input. -Copyright (C) 1988, 1991 Free Software Foundation, Inc. +Copyright (C) 1988, 1991, 1993, 1995, 1996 Free Software Foundation, Inc. Permission is granted to make and distribute verbatim copies of this manual provided the copyright notice and this permission notice @@ -45,7 +45,6 @@ by the Foundation. @end ifinfo @titlepage -@sp 10 @title GNU History Library @subtitle Edition @value{EDITION}, for @code{History Library} Version @value{VERSION}. @subtitle @value{UPDATE-MONTH} diff --git a/lib/readline/doc/history.dvi b/lib/readline/doc/history.dvi deleted file mode 100644 index 60d7376..0000000 Binary files a/lib/readline/doc/history.dvi and /dev/null differ diff --git a/lib/readline/doc/history.info b/lib/readline/doc/history.info deleted file mode 100644 index 6df0bd9..0000000 --- a/lib/readline/doc/history.info +++ /dev/null @@ -1,744 +0,0 @@ -This is Info file history.info, produced by Makeinfo-1.55 from the -input file hist.texinfo. - - This document describes the GNU History library, a programming tool -that provides a consistent user interface for recalling lines of -previously typed input. - - Copyright (C) 1988, 1991 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. - - 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. - - -File: history.info, Node: Top, Next: Using History Interactively, Prev: (DIR), Up: (DIR) - -GNU History Library -******************* - - This document describes the GNU History library, a programming tool -that provides a consistent user interface for recalling lines of -previously typed input. - -* Menu: - -* Using History Interactively:: GNU History User's Manual. -* Programming with GNU History:: GNU History Programmer's Manual. -* Concept Index:: Index of concepts described in this manual. -* Function and Variable Index:: Index of externally visible functions - and variables. - - -File: history.info, Node: Using History Interactively, Next: Programming with GNU History, Prev: Top, Up: Top - -Using History Interactively -*************************** - - This chapter describes how to use the GNU History Library -interactively, from a user's standpoint. It should be considered a -user's guide. For information on using the GNU History Library in your -own programs, *note Programming with GNU History::.. - -* Menu: - -* History Interaction:: What it feels like using History as a user. - - -File: history.info, Node: History Interaction, Up: Using History Interactively - -History Interaction -=================== - - The History library provides a history expansion feature that is -similar to the history expansion provided by `csh'. The following text -describes the syntax used to manipulate the history information. - - History expansion takes place in two parts. The first is to -determine which line from the previous history should be used during -substitution. The second is to select portions of that line for -inclusion into the current one. The line selected from the previous -history is called the "event", and the portions of that line that are -acted upon are called "words". The line is broken into words in the -same fashion that Bash does, so that several English (or Unix) words -surrounded by quotes are considered as one word. - -* Menu: - -* Event Designators:: How to specify which history line to use. -* Word Designators:: Specifying which words are of interest. -* Modifiers:: Modifying the results of substitution. - - -File: history.info, Node: Event Designators, Next: Word Designators, Up: History Interaction - -Event Designators ------------------ - - An event designator is a reference to a command line entry in the -history list. - -`!' - Start a history substitution, except when followed by a space, tab, - the end of the line, = or (. - -`!!' - Refer to the previous command. This is a synonym for `!-1'. - -`!n' - Refer to command line N. - -`!-n' - Refer to the command N lines back. - -`!string' - Refer to the most recent command starting with STRING. - -`!?string'[`?'] - Refer to the most recent command containing STRING. - -`!#' - The entire command line typed so far. - -`^string1^string2^' - Quick Substitution. Repeat the last command, replacing STRING1 - with STRING2. Equivalent to `!!:s/string1/string2/'. - - -File: history.info, Node: Word Designators, Next: Modifiers, Prev: Event Designators, Up: History Interaction - -Word Designators ----------------- - - A : separates the event specification from the word designator. It -can be omitted if the word designator begins with a ^, $, * or %. -Words are numbered from the beginning of the line, with the first word -being denoted by a 0 (zero). - -`0 (zero)' - The `0'th word. For many applications, this is the command word. - -`n' - The Nth word. - -`^' - The first argument; that is, word 1. - -`$' - The last argument. - -`%' - The word matched by the most recent `?string?' search. - -`x-y' - A range of words; `-Y' abbreviates `0-Y'. - -`*' - All of the words, except the `0'th. This is a synonym for `1-$'. - It is not an error to use * if there is just one word in the event; - the empty string is returned in that case. - -`x*' - Abbreviates `x-$' - -`x-' - Abbreviates `x-$' like `x*', but omits the last word. - - -File: history.info, Node: Modifiers, Prev: Word Designators, Up: History Interaction - -Modifiers ---------- - - After the optional word designator, you can add a sequence of one or -more of the following modifiers, each preceded by a :. - -`h' - Remove a trailing pathname component, leaving only the head. - -`r' - Remove a trailing suffix of the form `.'SUFFIX, leaving the - basename. - -`e' - Remove all but the trailing suffix. - -`t' - Remove all leading pathname components, leaving the tail. - -`p' - Print the new command but do not execute it. - -`s/old/new/' - Substitute NEW for the first occurrence of OLD in the event line. - Any delimiter may be used in place of /. The delimiter may be - quoted in OLD and NEW with a single backslash. If & appears in - NEW, it is replaced by OLD. A single backslash will quote the &. - The final delimiter is optional if it is the last character on the - input line. - -`&' - Repeat the previous substitution. - -`g' - Cause changes to be applied over the entire event line. Used in - conjunction with `s', as in `gs/old/new/', or with `&'. - - -File: history.info, Node: Programming with GNU History, Next: Concept Index, Prev: Using History Interactively, Up: Top - -Programming with GNU History -**************************** - - This chapter describes how to interface programs that you write with -the GNU History Library. It should be considered a technical guide. -For information on the interactive use of GNU History, *note Using -History Interactively::.. - -* Menu: - -* Introduction to History:: What is the GNU History library for? -* History Storage:: How information is stored. -* History Functions:: Functions that you can use. -* History Variables:: Variables that control behaviour. -* History Programming Example:: Example of using the GNU History Library. - - -File: history.info, Node: Introduction to History, Next: History Storage, Up: Programming with GNU History - -Introduction to History -======================= - - Many programs read input from the user a line at a time. The GNU -History library is able to keep track of those lines, associate -arbitrary data with each line, and utilize information from previous -lines in composing new ones. - - The programmer using the History library has available functions for -remembering lines on a history list, associating arbitrary data with a -line, removing lines from the list, searching through the list for a -line containing an arbitrary text string, and referencing any line in -the list directly. In addition, a history "expansion" function is -available which provides for a consistent user interface across -different programs. - - The user using programs written with the History library has the -benefit of a consistent user interface with a set of well-known -commands for manipulating the text of previous lines and using that text -in new commands. The basic history manipulation commands are similar to -the history substitution provided by `csh'. - - If the programmer desires, he can use the Readline library, which -includes some history manipulation by default, and has the added -advantage of command line editing. - - -File: history.info, Node: History Storage, Next: History Functions, Prev: Introduction to History, Up: Programming with GNU History - -History Storage -=============== - - The history list is an array of history entries. A history entry is -declared as follows: - - typedef struct _hist_entry { - char *line; - char *data; - } HIST_ENTRY; - - The history list itself might therefore be declared as - - HIST_ENTRY **the_history_list; - - The state of the History library is encapsulated into a single -structure: - - /* A structure used to pass the current state of the history stuff around. */ - typedef struct _hist_state { - HIST_ENTRY **entries; /* Pointer to the entries themselves. */ - int offset; /* The location pointer within this array. */ - int length; /* Number of elements within this array. */ - int size; /* Number of slots allocated to this array. */ - int flags; - } HISTORY_STATE; - - If the flags member includes `HS_STIFLED', the history has been -stifled. - - -File: history.info, Node: History Functions, Next: History Variables, Prev: History Storage, Up: Programming with GNU History - -History Functions -================= - - This section describes the calling sequence for the various functions -present in GNU History. - -* Menu: - -* Initializing History and State Management:: Functions to call when you - want to use history in a - program. -* History List Management:: Functions used to manage the list - of history entries. -* Information About the History List:: Functions returning information about - the history list. -* Moving Around the History List:: Functions used to change the position - in the history list. -* Searching the History List:: Functions to search the history list - for entries containing a string. -* Managing the History File:: Functions that read and write a file - containing the history list. -* History Expansion:: Functions to perform csh-like history - expansion. - - -File: history.info, Node: Initializing History and State Management, Next: History List Management, Up: History Functions - -Initializing History and State Management ------------------------------------------ - - This section describes functions used to initialize and manage the -state of the History library when you want to use the history functions -in your program. - - - Function: void using_history () - Begin a session in which the history functions might be used. This - initializes the interactive variables. - - - Function: HISTORY_STATE * history_get_history_state () - Return a structure describing the current state of the input - history. - - - Function: void history_set_history_state (HISTORY_STATE *state) - Set the state of the history list according to STATE. - - -File: history.info, Node: History List Management, Next: Information About the History List, Prev: Initializing History and State Management, Up: History Functions - -History List Management ------------------------ - - These functions manage individual entries on the history list, or set -parameters managing the list itself. - - - Function: void add_history (char *string) - Place STRING at the end of the history list. The associated data - field (if any) is set to `NULL'. - - - Function: HIST_ENTRY * remove_history (int which) - Remove history entry at offset WHICH from the history. The - removed element is returned so you can free the line, data, and - containing structure. - - - Function: HIST_ENTRY * replace_history_entry (int which, char *line, - char *data) - Make the history entry at offset WHICH have LINE and DATA. This - returns the old entry so you can dispose of the data. In the case - of an invalid WHICH, a `NULL' pointer is returned. - - - Function: void stifle_history (int max) - Stifle the history list, remembering only the last MAX entries. - - - Function: int unstifle_history () - Stop stifling the history. This returns the previous amount the - history was stifled. The value is positive if the history was - stifled, negative if it wasn't. - - - Function: int history_is_stifled () - Returns non-zero if the history is stifled, zero if it is not. - - -File: history.info, Node: Information About the History List, Next: Moving Around the History List, Prev: History List Management, Up: History Functions - -Information About the History List ----------------------------------- - - These functions return information about the entire history list or -individual list entries. - - - Function: HIST_ENTRY ** history_list () - Return a `NULL' terminated array of `HIST_ENTRY' which is the - current input history. Element 0 of this list is the beginning of - time. If there is no history, return `NULL'. - - - Function: int where_history () - Returns the offset of the current history element. - - - Function: HIST_ENTRY * current_history () - Return the history entry at the current position, as determined by - `where_history ()'. If there is no entry there, return a `NULL' - pointer. - - - Function: HIST_ENTRY * history_get (int offset) - Return the history entry at position OFFSET, starting from - `history_base'. If there is no entry there, or if OFFSET is - greater than the history length, return a `NULL' pointer. - - - Function: int history_total_bytes () - Return the number of bytes that the primary history entries are - using. This function returns the sum of the lengths of all the - lines in the history. - - -File: history.info, Node: Moving Around the History List, Next: Searching the History List, Prev: Information About the History List, Up: History Functions - -Moving Around the History List ------------------------------- - - These functions allow the current index into the history list to be -set or changed. - - - Function: int history_set_pos (int pos) - Set the position in the history list to POS, an absolute index - into the list. - - - Function: HIST_ENTRY * previous_history () - Back up the current history offset to the previous history entry, - and return a pointer to that entry. If there is no previous - entry, return a `NULL' pointer. - - - Function: HIST_ENTRY * next_history () - Move the current history offset forward to the next history entry, - and return the a pointer to that entry. If there is no next - entry, return a `NULL' pointer. - - -File: history.info, Node: Searching the History List, Next: Managing the History File, Prev: Moving Around the History List, Up: History Functions - -Searching the History List --------------------------- - - These functions allow searching of the history list for entries -containing a specific string. Searching may be performed both forward -and backward from the current history position. The search may be -"anchored", meaning that the string must match at the beginning of the -history entry. - - - Function: int history_search (char *string, int direction) - Search the history for STRING, starting at the current history - offset. If DIRECTION < 0, then the search is through previous - entries, else through subsequent. If STRING is found, then the - current history index is set to that history entry, and the value - returned is the offset in the line of the entry where STRING was - found. Otherwise, nothing is changed, and a -1 is returned. - - - Function: int history_search_prefix (char *string, int direction) - Search the history for STRING, starting at the current history - offset. The search is anchored: matching lines must begin with - STRING. If DIRECTION < 0, then the search is through previous - entries, else through subsequent. If STRING is found, then the - current history index is set to that entry, and the return value - is 0. Otherwise, nothing is changed, and a -1 is returned. - - - Function: int history_search_pos (char *string, int direction, int - pos) - Search for STRING in the history list, starting at POS, an - absolute index into the list. If DIRECTION is negative, the search - proceeds backward from POS, otherwise forward. Returns the - absolute index of the history element where STRING was found, or - -1 otherwise. - - -File: history.info, Node: Managing the History File, Next: History Expansion, Prev: Searching the History List, Up: History Functions - -Managing the History File -------------------------- - - The History library can read the history from and write it to a file. -This section documents the functions for managing a history file. - - - Function: int read_history (char *filename) - Add the contents of FILENAME to the history list, a line at a - time. If FILENAME is `NULL', then read from `~/.history'. - Returns 0 if successful, or errno if not. - - - Function: int read_history_range (char *filename, int from, int to) - Read a range of lines from FILENAME, adding them to the history - list. Start reading at line FROM and end at TO. If FROM is zero, - start at the beginning. If TO is less than FROM, then read until - the end of the file. If FILENAME is `NULL', then read from - `~/.history'. Returns 0 if successful, or `errno' if not. - - - Function: int write_history (char *filename) - Write the current history to FILENAME, overwriting FILENAME if - necessary. If FILENAME is `NULL', then write the history list to - `~/.history'. Values returned are as in `read_history ()'. - - - Function: int append_history (int nelements, char *filename) - Append the last NELEMENTS of the history list to FILENAME. - - - Function: int history_truncate_file (char *filename, int nlines) - Truncate the history file FILENAME, leaving only the last NLINES - lines. - - -File: history.info, Node: History Expansion, Prev: Managing the History File, Up: History Functions - -History Expansion ------------------ - - These functions implement `csh'-like history expansion. - - - Function: int history_expand (char *string, char **output) - Expand STRING, placing the result into OUTPUT, a pointer to a - string (*note History Interaction::.). Returns: - `0' - If no expansions took place (or, if the only change in the - text was the de-slashifying of the history expansion - character); - - `1' - if expansions did take place; - - `-1' - if there was an error in expansion; - - `2' - if the returned line should only be displayed, but not - executed, as with the `:p' modifier (*note Modifiers::.). - - If an error ocurred in expansion, then OUTPUT contains a - descriptive error message. - - - Function: char * history_arg_extract (int first, int last, char - *string) - Extract a string segment consisting of the FIRST through LAST - arguments present in STRING. Arguments are broken up as in Bash. - - - Function: char * get_history_event (char *string, int *cindex, int - qchar) - Returns the text of the history event beginning at STRING + - *CINDEX. *CINDEX is modified to point to after the event - specifier. At function entry, CINDEX points to the index into - STRING where the history event specification begins. QCHAR is a - character that is allowed to end the event specification in - addition to the "normal" terminating characters. - - - Function: char ** history_tokenize (char *string) - Return an array of tokens parsed out of STRING, much as the shell - might. The tokens are split on white space and on the characters - `()<>;&|$', and shell quoting conventions are obeyed. - - -File: history.info, Node: History Variables, Next: History Programming Example, Prev: History Functions, Up: Programming with GNU History - -History Variables -================= - - This section describes the externally visible variables exported by -the GNU History Library. - - - Variable: int history_base - The logical offset of the first entry in the history list. - - - Variable: int history_length - The number of entries currently stored in the history list. - - - Variable: int max_input_history - The maximum number of history entries. This must be changed using - `stifle_history ()'. - - - Variable: char history_expansion_char - The character that starts a history event. The default is `!'. - - - Variable: char history_subst_char - The character that invokes word substitution if found at the start - of a line. The default is `^'. - - - Variable: char history_comment_char - During tokenization, if this character is seen as the first - character of a word, then it and all subsequent characters up to a - newline are ignored, suppressing history expansion for the - remainder of the line. This is disabled by default. - - - Variable: char * history_no_expand_chars - The list of characters which inhibit history expansion if found - immediately following HISTORY_EXPANSION_CHAR. The default is - whitespace and `='. - - -File: history.info, Node: History Programming Example, Prev: History Variables, Up: Programming with GNU History - -History Programming Example -=========================== - - The following program demonstrates simple use of the GNU History -Library. - - main () - { - char line[1024], *t; - int len, done = 0; - - line[0] = 0; - - using_history (); - while (!done) - { - printf ("history$ "); - fflush (stdout); - t = fgets (line, sizeof (line) - 1, stdin); - if (t && *t) - { - len = strlen (t); - if (t[len - 1] == '\n') - t[len - 1] = '\0'; - } - - if (!t) - strcpy (line, "quit"); - - if (line[0]) - { - char *expansion; - int result; - - result = history_expand (line, &expansion); - if (result) - fprintf (stderr, "%s\n", expansion); - - if (result < 0 || result == 2) - { - free (expansion); - continue; - } - - add_history (expansion); - strncpy (line, expansion, sizeof (line) - 1); - free (expansion); - } - - if (strcmp (line, "quit") == 0) - done = 1; - else if (strcmp (line, "save") == 0) - write_history ("history_file"); - else if (strcmp (line, "read") == 0) - read_history ("history_file"); - else if (strcmp (line, "list") == 0) - { - register HIST_ENTRY **the_list; - register int i; - - the_list = history_list (); - if (the_list) - for (i = 0; the_list[i]; i++) - printf ("%d: %s\n", i + history_base, the_list[i]->line); - } - else if (strncmp (line, "delete", 6) == 0) - { - int which; - if ((sscanf (line + 6, "%d", &which)) == 1) - { - HIST_ENTRY *entry = remove_history (which); - if (!entry) - fprintf (stderr, "No such entry %d\n", which); - else - { - free (entry->line); - free (entry); - } - } - else - { - fprintf (stderr, "non-numeric arg given to `delete'\n"); - } - } - } - } - - -File: history.info, Node: Concept Index, Next: Function and Variable Index, Prev: Programming with GNU History, Up: Top - -Concept Index -************* - -* Menu: - -* anchored search: Searching the History List. -* event designators: Event Designators. -* expansion: History Interaction. -* history events: Event Designators. -* History Searching: Searching the History List. - - -File: history.info, Node: Function and Variable Index, Prev: Concept Index, Up: Top - -Function and Variable Index -*************************** - -* Menu: - -* add_history: History List Management. -* append_history: Managing the History File. -* current_history: Information About the History List. -* get_history_event: History Expansion. -* history_arg_extract: History Expansion. -* history_base: History Variables. -* history_comment_char: History Variables. -* history_expand: History Expansion. -* history_expansion_char: History Variables. -* history_get: Information About the History List. -* history_get_history_state: Initializing History and State Management. -* history_is_stifled: History List Management. -* history_length: History Variables. -* history_list: Information About the History List. -* history_no_expand_chars: History Variables. -* history_search: Searching the History List. -* history_search_pos: Searching the History List. -* history_search_prefix: Searching the History List. -* history_set_history_state: Initializing History and State Management. -* history_set_pos: Moving Around the History List. -* history_subst_char: History Variables. -* history_tokenize: History Expansion. -* history_total_bytes: Information About the History List. -* history_truncate_file: Managing the History File. -* max_input_history: History Variables. -* next_history: Moving Around the History List. -* previous_history: Moving Around the History List. -* read_history: Managing the History File. -* read_history_range: Managing the History File. -* remove_history: History List Management. -* replace_history_entry: History List Management. -* stifle_history: History List Management. -* unstifle_history: History List Management. -* using_history: Initializing History and State Management. -* where_history: Information About the History List. -* write_history: Managing the History File. - - - -Tag Table: -Node: Top975 -Node: Using History Interactively1569 -Node: History Interaction2077 -Node: Event Designators3122 -Node: Word Designators3952 -Node: Modifiers4936 -Node: Programming with GNU History6065 -Node: Introduction to History6791 -Node: History Storage8112 -Node: History Functions9205 -Node: Initializing History and State Management10176 -Node: History List Management10968 -Node: Information About the History List12396 -Node: Moving Around the History List13702 -Node: Searching the History List14587 -Node: Managing the History File16419 -Node: History Expansion17925 -Node: History Variables19769 -Node: History Programming Example21138 -Node: Concept Index23742 -Node: Function and Variable Index24223 - -End Tag Table diff --git a/lib/readline/doc/history.ps b/lib/readline/doc/history.ps deleted file mode 100644 index 839598f..0000000 --- a/lib/readline/doc/history.ps +++ /dev/null @@ -1,2037 +0,0 @@ -%!PS-Adobe-2.0 -%%Creator: dvipsk 5.490s Copyright 1986, 1992 Radical Eye Software -%%Title: history.dvi -%%Pages: 22 1 -%%BoundingBox: 0 0 612 792 -%%EndComments -%DVIPSCommandLine: dvips -D 300 -o history.ps history.dvi -%%BeginProcSet: tex.pro -%! -/TeXDict 250 dict def TeXDict begin /N{def}def /B{bind def}N /S{exch}N /X{S N} -B /TR{translate}N /isls false N /vsize 11 72 mul N /@rigin{isls{[0 -1 1 0 0 0] -concat}if 72 Resolution div 72 VResolution div neg scale isls{Resolution hsize --72 div mul 0 TR}if Resolution VResolution vsize -72 div 1 add mul TR matrix -currentmatrix dup dup 4 get round 4 exch put dup dup 5 get round 5 exch put -setmatrix}N /@landscape{/isls true N}B /@manualfeed{statusdict /manualfeed -true put}B /@copies{/#copies X}B /FMat[1 0 0 -1 0 0]N /FBB[0 0 0 0]N /nn 0 N -/IE 0 N /ctr 0 N /df-tail{/nn 8 dict N nn begin /FontType 3 N /FontMatrix -fntrx N /FontBBox FBB N string /base X array /BitMaps X /BuildChar{ -CharBuilder}N /Encoding IE N end dup{/foo setfont}2 array copy cvx N load 0 nn -put /ctr 0 N[}B /df{/sf 1 N /fntrx FMat N df-tail}B /dfs{div /sf X /fntrx[sf 0 -0 sf neg 0 0]N df-tail}B /E{pop nn dup definefont setfont}B /ch-width{ch-data -dup length 5 sub get}B /ch-height{ch-data dup length 4 sub get}B /ch-xoff{128 -ch-data dup length 3 sub get sub}B /ch-yoff{ch-data dup length 2 sub get 127 -sub}B /ch-dx{ch-data dup length 1 sub get}B /ch-image{ch-data dup type -/stringtype ne{ctr get /ctr ctr 1 add N}if}B /id 0 N /rw 0 N /rc 0 N /gp 0 N -/cp 0 N /G 0 N /sf 0 N /CharBuilder{save 3 1 roll S dup /base get 2 index get -S /BitMaps get S get /ch-data X pop /ctr 0 N ch-dx 0 ch-xoff ch-yoff ch-height -sub ch-xoff ch-width add ch-yoff setcachedevice ch-width ch-height true[1 0 0 --1 -.1 ch-xoff sub ch-yoff .1 add]{ch-image}imagemask restore}B /D{/cc X dup -type /stringtype ne{]}if nn /base get cc ctr put nn /BitMaps get S ctr S sf 1 -ne{dup dup length 1 sub dup 2 index S get sf div put}if put /ctr ctr 1 add N} -B /I{cc 1 add D}B /bop{userdict /bop-hook known{bop-hook}if /SI save N @rigin -0 0 moveto /V matrix currentmatrix dup 1 get dup mul exch 0 get dup mul add -.99 lt{/FV}{/RV}ifelse load def pop}N /eop{SI restore showpage userdict -/eop-hook known{eop-hook}if}N /@start{userdict /start-hook known{start-hook} -if /VResolution X /Resolution X 1000 div /DVImag X /IE 256 array N 0 1 255{IE -S 1 string dup 0 3 index put cvn put}for 65781.76 div /vsize X 65781.76 div -/hsize X}N /p{show}N /RMat[1 0 0 -1 0 0]N /BDot 260 string N /rulex 0 N /ruley -0 N /v{/ruley X /rulex X V}B /V{}B /RV statusdict begin /product where{pop -product dup length 7 ge{0 7 getinterval dup(Display)eq exch 0 4 getinterval -(NeXT)eq or}{pop false}ifelse}{false}ifelse end{{gsave TR -.1 -.1 TR 1 1 scale -rulex ruley false RMat{BDot}imagemask grestore}}{{gsave TR -.1 -.1 TR rulex -ruley scale 1 1 false RMat{BDot}imagemask grestore}}ifelse B /FV{gsave -transform round exch round exch itransform moveto rulex 0 rlineto 0 ruley neg -rlineto rulex neg 0 rlineto fill grestore}B /a{moveto}B /delta 0 N /tail{dup -/delta X 0 rmoveto}B /M{S p delta add tail}B /b{S p tail}B /c{-4 M}B /d{-3 M} -B /e{-2 M}B /f{-1 M}B /g{0 M}B /h{1 M}B /i{2 M}B /j{3 M}B /k{4 M}B /w{0 -rmoveto}B /l{p -4 w}B /m{p -3 w}B /n{p -2 w}B /o{p -1 w}B /q{p 1 w}B /r{p 2 w} -B /s{p 3 w}B /t{p 4 w}B /x{0 S rmoveto}B /y{3 2 roll p a}B /bos{/SS save N}B -/eos{SS restore}B end -%%EndProcSet -TeXDict begin 40258431 52099146 1000 300 300 @start /Fa 1 59 -df<70F8F8F87005057C840D>58 D E /Fb 1 59 df<78FCFCFCFC7806067B8510>58 -D E /Fc 24 123 df<1FC0007FF000707800201800001C00001C0007FC001FFC003C1C00701C00 -E01C00E01C00E01C00707C003FFF800F8F8011107E8F14>97 DI<03F80FFC1C1C380870006000E000E0 -00E000E00060007000380E1C1E0FFC03F00F107E8F14>I<007E00007E00000E00000E00000E00 -000E00000E0007CE000FFE001C3E00301E00700E00E00E00E00E00E00E00E00E00E00E00E00E00 -700E00301E00383E001FEFC007CFC012177F9614>I<07E00FF01C38301C700CE00EE00EFFFEFF -FEE00060007000380E1C1E0FFC03F00F107E8F14>I<007C00FE01CE03840380038003807FFEFF -FE0380038003800380038003800380038003800380038003807FFC7FFC0F177F9614>I<07CF00 -1FFF80383B80301800701C00701C00701C003018003838003FF00037C0007000007000003FF800 -1FFC003FFE00700F00E00380E00380E00380E003807007003C1E001FFC0007F00011197F8F14> -II<03 -0007800780030000000000000000007F807F800380038003800380038003800380038003800380 -03800380FFFCFFFC0E187D9714>I107 DIII<07C01FF03C78701C701CE00EE00EE00EE0 -0EE00EE00E701C783C3C781FF007C00F107E8F14>II -114 D<0FD83FF86038C038C038F0007F803FF007F8001C6006E006F006F81CFFF8CFE00F107E8F -14>I<030007000700070007007FFCFFFC07000700070007000700070007000700070E070E070E -070C03FC00F00F157F9414>IIII<7E3F007E3F001E38000E780007700007E0 -0003E00001C00003C00003E0000770000E78000E38001C1C00FE3F80FE3F8011107F8F14>II< -3FFF7FFF700E701C7038007000E001C0038007000E001C0738077007FFFFFFFF10107F8F14>I -E /Fd 1 59 df<60F0F06004047D830B>58 D E /Fe 25 122 df<078018603030303060186018 -E01CE01CE01CE01CE01CE01CE01CE01CE01CE01CE01CE01C6018601870383030186007800E187E -9713>48 D<03000700FF0007000700070007000700070007000700070007000700070007000700 -070007000700070007000700FFF00C187D9713>I<0F80106020304038803CC01CE01C401C003C -003800380070006000C001800100020004040804100430083FF87FF8FFF80E187E9713>I<01E0 -06100C1818383038300070006000E000E7C0E860F030F018E018E01CE01CE01C601C601C701830 -183030186007C00E187E9713>54 D<40007FFE7FFC7FFC40088010801080200040004000800180 -01800100030003000300030007000700070007000700070002000F197E9813>I<078018603030 -201860186018601870103C303E600F8007C019F030F86038401CC00CC00CC00CC00C6008201018 -600FC00E187E9713>I<07801860303070306018E018E018E01CE01CE01C601C603C303C185C0F -9C001C00180018003870307060604021801F000E187E9713>I72 -D<0FC21836200E6006C006C002C002C002E00070007E003FE01FF807FC003E000E000700038003 -80038003C002C006E004D81887E0101A7E9915>83 D<3F8070C070E020700070007007F01C7030 -707070E070E071E071E0F171FB1E3C10107E8F13>97 D<07F80C1C381C30087000E000E000E000 -E000E000E0007000300438080C1807E00E107F8F11>99 D<007E00000E00000E00000E00000E00 -000E00000E00000E00000E00000E0003CE000C3E00380E00300E00700E00E00E00E00E00E00E00 -E00E00E00E00E00E00600E00700E00381E001C2E0007CFC0121A7F9915>I<07C01C3030187018 -600CE00CFFFCE000E000E000E0006000300438080C1807E00E107F8F11>I<0FCE187330307038 -703870387038303018602FC02000600070003FF03FFC1FFE600FC003C003C003C0036006381C07 -E010187F8F13>103 DI<18003C003C001800000000000000000000000000FC00 -1C001C001C001C001C001C001C001C001C001C001C001C001C001C00FF80091A80990A>I110 D<07E01C38300C700E6006E007E007E007E007E007E00760 -06700E381C1C3807E010107F8F13>II114 D<1F2060E04020C020C020F0007F003FC01FE000F0807080 -30C030C020F0408F800C107F8F0F>I<0400040004000C000C001C003C00FFC01C001C001C001C -001C001C001C001C001C201C201C201C201C200E4003800B177F960F>I118 D120 DI E /Ff 2 42 -df<007000E001C00380078007000E001E001E003C003C003C0078007800780078007000F000F0 -00F000F000F000F000F000F000F000F000F000F000700078007800780078003C003C003C001E00 -1E000E0007000780038001C000E000700C2E7EA112>40 DI E /Fg 25 123 df<0007F800007FFC0001FC0E0003F01F0007E03F000FC03F000F -C03F000FC03F000FC01E000FC00C000FC000000FC000000FC0FF80FFFFFF80FFFFFF800FC01F80 -0FC01F800FC01F800FC01F800FC01F800FC01F800FC01F800FC01F800FC01F800FC01F800FC01F -800FC01F800FC01F800FC01F800FC01F800FC01F800FC01F800FC01F807FF8FFF07FF8FFF01C23 -7FA220>12 D<000FFF80007FFF8001FC1F8003F03F8007E03F800FC03F800FC01F800FC01F800F -C01F800FC01F800FC01F800FC01F800FC01F80FFFFFF80FFFFFF800FC01F800FC01F800FC01F80 -0FC01F800FC01F800FC01F800FC01F800FC01F800FC01F800FC01F800FC01F800FC01F800FC01F -800FC01F800FC01F800FC01F800FC01F800FC01F807FF8FFF07FF8FFF01C237FA220>I<07FE00 -001FFF80003F07E0003F03F0003F01F0003F01F8001E01F8000001F8000001F800003FF80003FD -F8001F81F8003E01F8007C01F800F801F800F801F800F801F800F801F8007C02F8007E0CF8001F -F87F8007E03F8019167E951C>97 DI<00FF8007FFE00F83F01F03F03E03F07E03F07C01E07C0000FC0000FC0000FC0000 -FC0000FC0000FC00007C00007E00007E00003F00301F00600FC0E007FF8000FE0014167E9519> -I<0001FF000001FF0000003F0000003F0000003F0000003F0000003F0000003F0000003F000000 -3F0000003F0000003F0000003F0000FE3F0007FFBF000FC1FF001F007F003E003F007E003F007C -003F007C003F00FC003F00FC003F00FC003F00FC003F00FC003F00FC003F00FC003F007C003F00 -7E003F003E003F001F007F000F81FF0007FF3FE001FC3FE01B237EA220>I<00FE0007FF800F83 -C01F01E03E00F07E00F07C00F87C0078FC0078FFFFF8FFFFF8FC0000FC0000FC00007C00007C00 -003E00183E00181F00300F80E003FFC000FF0015167E951A>I<00FE0F8003FF9FC00F83E3C01F -01F3C01E00F0003E00F8003E00F8003E00F8003E00F8003E00F8001E00F0001F01F0000F83E000 -0BFF800008FE000018000000180000001C0000001FFFE0001FFFFC000FFFFF0007FFFF001FFFFF -807C001FC078000FC0F80007C0F80007C0F80007C07C000F803E001F001F807E000FFFFC0001FF -E0001A217F951D>103 DI<1E003F007F807F807F807F803F001E00000000000000000000000000FF80FF801F801F801F -801F801F801F801F801F801F801F801F801F801F801F801F801F801F801F80FFF0FFF00C247EA3 -0F>I107 -DI< -FF03F803F800FF0FFE0FFE001F183F183F001F201F201F001F401FC01F801F401FC01F801F801F -801F801F801F801F801F801F801F801F801F801F801F801F801F801F801F801F801F801F801F80 -1F801F801F801F801F801F801F801F801F801F801F801F801F801F801F801F801F801F801F801F -801F80FFF0FFF0FFF0FFF0FFF0FFF02C167D9531>II< -00FF0007FFE00F81F01F00F83E007C7C003E7C003E7C003EFC003FFC003FFC003FFC003FFC003F -FC003FFC003F7C003E7E007E3E007C1F00F80F81F007FFE000FF0018167E951D>II114 D<07F9801FFF80380780700380F00180F00180F80000FF0000FFF8007FFE -003FFF001FFF8007FF80003FC0C007C0C003C0E003C0E003C0F00380FC0F00EFFE00C3F8001216 -7E9517>I<00C00000C00000C00000C00001C00001C00003C00007C0000FC0001FC000FFFF00FF -FF000FC0000FC0000FC0000FC0000FC0000FC0000FC0000FC0000FC0000FC0000FC0000FC1800F -C1800FC1800FC1800FC18007C18007E30003FE0000FC0011207F9F16>IIIIII<7FFFE07FFFE0780FC0701FC0601F80E03F00 -C07F00C07E00C0FC0001FC0001F80003F00007F03007E0300FC0301FC0701F80703F00607F00E0 -7E03E0FFFFE0FFFFE014167E9519>I E /Fh 22 119 df<00E00000E00000E00000E00040E040 -F0E1E0F8E3E07EEFC01FFF0007FC0003F80007FC001FFF007EEFC0F8E3E0F0E1E040E04000E000 -00E00000E00000E00013157D991A>42 D<003800007C00007C00006C0000EE0000EE0000EE0000 -EE0000C60001C70001C70001C70001C7000383800383800383800383800783C00701C007FFC007 -FFC007FFC00E00E00E00E00E00E00E00E01C00707F83FCFF83FE7F83FC171E7F9D1A>65 -D<7FFFFCFFFFFC7FFFFC0E001C0E001C0E001C0E001C0E001C0E00000E00000E07000E07000E07 -000FFF000FFF000FFF000E07000E07000E07000E00000E00000E00000E000E0E000E0E000E0E00 -0E0E000E7FFFFEFFFFFE7FFFFE171E7F9D1A>69 D -72 DI78 D<0FFE003FFF807FFFC07C07C07001C0F001E0E000E0E000E0E000E0E000E0E000E0E000E0 -E000E0E000E0E000E0E000E0E000E0E000E0E000E0E000E0E000E0E000E0E000E0F001E0F001E0 -7001C07C07C07FFFC03FFF800FFE00131E7D9D1A>I82 D<03F1C00FFDC03FFFC07C0FC07003C0E003C0E001C0E001C0E001C0E00000700000780000 -3F00001FF00007FE0000FF00000F800003C00001C00000E00000E06000E0E000E0E000E0E001C0 -F001C0FC0780FFFF80EFFE00E3F800131E7D9D1A>I<7FFFFEFFFFFEFFFFFEE0380EE0380EE038 -0EE0380EE0380E0038000038000038000038000038000038000038000038000038000038000038 -0000380000380000380000380000380000380000380000380003FF8007FFC003FF80171E7F9D1A ->I89 D<7FFFC0FFFFE0FFFFE07FFFC013047D7E1A ->95 D<1FF0003FFC007FFE00780F00300700000380000380007F8007FF801FFF803F8380780380 -700380E00380E00380E00380700780780F803FFFFC1FFDFC07F0FC16157D941A>97 -D<00FF8003FFC00FFFE01F01E03C00C0780000700000700000E00000E00000E00000E00000E000 -007000007000007800703C00701F01F00FFFE003FFC000FE0014157D941A>99 -D<001FC0001FC0001FC00001C00001C00001C00001C00001C00001C001F1C007FDC00FFFC01E0F -C03C07C07803C07001C0E001C0E001C0E001C0E001C0E001C0E001C0E001C07003C07003C03807 -C03E0FC01FFFFC07FDFC01F1FC161E7E9D1A>I -104 D<01C00003E00003E00003E00001C0000000000000000000000000000000007FE000FFE000 -7FE00000E00000E00000E00000E00000E00000E00000E00000E00000E00000E00000E00000E000 -00E00000E00000E000FFFFC0FFFFC0FFFFC0121F7C9E1A>I110 D<01F00007FC001FFF003E0F803C07807803C07001 -C0E000E0E000E0E000E0E000E0E000E0E000E0F001E07001C07803C03C07803E0F801FFF0007FC -0001F00013157D941A>I114 D<00C00001C00001C00001C00001C00001C00001C0007FFFE0FFFFE0FFFFE001C00001 -C00001C00001C00001C00001C00001C00001C00001C00001C00001C07001C07001C07001C07000 -E0E000FFE0007FC0001F00141C7F9B1A>116 D<7FC7FCFFC7FE7FC7FC0E00E00E00E00F01E007 -01C00701C00783C003838003838003838001C70001C70001C70000EE0000EE0000EE00007C0000 -7C0000380017157F941A>118 D E /Fi 41 123 df<0003FC00003FFE00007E070001F80F8003 -F01F8003E01F8007E01F8007E01F8007E01F8007E0060007E0000007E0000007E0000007E0FFC0 -FFFFFFC0FFFFFFC007E00FC007E00FC007E00FC007E00FC007E00FC007E00FC007E00FC007E00F -C007E00FC007E00FC007E00FC007E00FC007E00FC007E00FC007E00FC007E00FC007E00FC007E0 -0FC007E00FC007E00FC07FFC7FFC7FFC7FFC1E267FA522>12 D<3C7EFFFFFFFF7E3C08087C8711 ->46 D<001C00003C0000FC00FFFC00FFFC0000FC0000FC0000FC0000FC0000FC0000FC0000FC00 -00FC0000FC0000FC0000FC0000FC0000FC0000FC0000FC0000FC0000FC0000FC0000FC0000FC00 -00FC0000FC0000FC0000FC0000FC0000FC0000FC0000FC007FFFFC7FFFFC16237CA21F>49 -D<01FF0007FFC01E07F03803F86001FC7C00FEFE00FEFE00FFFE007FFE007F7C007F3800FF0000 -FF0000FE0000FE0001FC0001F80003F00007E0000780000F00001E00003C0000700000E00301C0 -030380070700060600060FFFFE1FFFFE3FFFFE7FFFFCFFFFFCFFFFFC18237DA21F>I<01FF0007 -FFE01E03F03801F83C01FC7E00FE7E00FE7E00FE3E00FE1C01FE0001FC0001FC0003F80007F000 -0FC001FF0001FF000007E00001F00001F80000FC0000FE0000FF0000FF1000FF7C00FFFE00FFFE -00FFFE00FEFE00FE7C01FC7001F83E07F00FFFC001FF0018237DA21F>I<000038000000780000 -0078000000F8000001F8000003F8000007F8000006F800000CF800001CF8000038F8000030F800 -0060F80000E0F80001C0F8000180F8000300F8000700F8000E00F8001C00F8001800F8003000F8 -007000F800E000F800FFFFFFC0FFFFFFC00001F8000001F8000001F8000001F8000001F8000001 -F8000001F800007FFFC0007FFFC01A237EA21F>I<18000C1F007C1FFFF81FFFF01FFFE01FFFC0 -1FFF801FFE0018000018000018000018000018000018FF001BFFE01F01F01C00F80800FC00007E -00007E00007E00007F00007F78007FFC007FFC007FFC007FFC007EF8007E6000FC7000FC3801F8 -1E07E007FFC001FE0018237DA21F>I<001FC0007FF001F83803E00C07803E0F807E1F007E3F00 -7E3F007E7E003C7E00007E00007E0000FE3FC0FE7FF0FE80F8FF80FCFF007CFF007EFE007EFE00 -7FFE007FFE007FFE007F7E007F7E007F7E007F7E007F3E007E3F007E1F007C0F80F807C1F003FF -C0007F0018237DA21F>I<300000003C0000003FFFFFC03FFFFFC03FFFFF807FFFFF007FFFFE00 -7FFFFC006000180060001800E0003000C0006000C000C000000180000001800000030000000700 -0000060000000E0000001E0000001E0000001E0000003C0000003C0000007C0000007C0000007C -0000007C000000FC000000FC000000FC000000FC000000FC000000FC000000FC00000078000000 -3000001A257DA41F>I<00001C00000000001C00000000003E00000000003E00000000003E0000 -0000007F00000000007F0000000000FF8000000000FF8000000000FF80000000019FC000000001 -9FC0000000031FE0000000030FE0000000030FE00000000607F00000000607F00000000C07F800 -00000C03F80000001C03FC0000001801FC0000001801FC0000003001FE0000003000FE0000007F -FFFF0000007FFFFF00000060007F000000C0007F800000C0003F800001C0003FC0000180001FC0 -000180001FC0000300000FE0000300000FE0000780000FF000FFF801FFFF80FFF801FFFF802925 -7EA42E>65 D -68 DI< -FFFFFFFE00FFFFFFFE0003F800FE0003F8001F0003F8000F0003F800070003F800070003F80003 -0003F800030003F800030003F800018003F806018003F806018003F806000003F806000003F80E -000003F81E000003FFFE000003FFFE000003F81E000003F80E000003F806000003F806000003F8 -06000003F806000003F800000003F800000003F800000003F800000003F800000003F800000003 -F800000003F800000003F800000003F8000000FFFFF00000FFFFF0000021257EA427>I72 -DI -76 DI<00FF0080 -07FFE3800F80F7801E001F803C000F807800078078000380F8000380F8000180F8000180FC0001 -80FC000000FF0000007FE000007FFF00003FFFE0003FFFF8001FFFFE0007FFFF0003FFFF80007F -FF800003FFC000003FC000000FE0000007E0000007E0C00003E0C00003E0C00003E0C00003C0E0 -0003C0F00007C0F8000780FC000F00FFC03E00E3FFF800803FE0001B257DA422>83 -D87 -D<07FF00001FFFC0003E03E0003F01F0003F01F8003F00FC001E00FC000000FC000000FC000000 -FC00003FFC0003FCFC000FC0FC003F00FC007E00FC007E00FC00FC00FC00FC00FC00FC00FC00FC -017C007E017C003F067C001FFC3FE007F01FE01B187E971E>97 DI<007FE003FFF807C07C -1F80FC1F00FC3F00FC7E00787E0000FE0000FE0000FE0000FE0000FE0000FE0000FE0000FE0000 -7E00007F00003F000C1F800C1FC01807E07003FFE0007F0016187E971B>I<0001FF800001FF80 -00001F8000001F8000001F8000001F8000001F8000001F8000001F8000001F8000001F8000001F -8000001F8000001F80007F1F8003FFDF8007E0FF801F803F803F001F803F001F807E001F807E00 -1F80FE001F80FE001F80FE001F80FE001F80FE001F80FE001F80FE001F80FE001F807E001F807E -001F803F001F803F003F801F807F800FC0FF8003FF9FF800FE1FF81D267EA522>I<007F0003FF -C007C1F00F80F81F00F83F007C7E007C7E007EFE007EFE007EFFFFFEFFFFFEFE0000FE0000FE00 -007E00007E00007E00063F00061F000C0F801807E07003FFE0007F8017187E971C>I<000FC000 -7FF000F8F001F1F803F1F803E1F807E0F007E00007E00007E00007E00007E00007E00007E000FF -FF00FFFF0007E00007E00007E00007E00007E00007E00007E00007E00007E00007E00007E00007 -E00007E00007E00007E00007E00007E00007E00007E00007E0007FFF007FFF0015267EA513>I< -01FF07C007FFDFE00F83F1E01F01F1E03E00F8007E00FC007E00FC007E00FC007E00FC007E00FC -007E00FC003E00F8001F01F0000F83E0000FFFC00011FF00003000000030000000380000003C00 -00003FFFE0001FFFFC001FFFFE000FFFFF001FFFFF803C003F8078000FC0F80007C0F80007C0F8 -0007C0F80007C07C000F803E001F001F807E0007FFF80000FFC0001B247E971F>II<0F00 -1F803FC03FC03FC03FC01F800F000000000000000000000000000000FFC0FFC00FC00FC00FC00F -C00FC00FC00FC00FC00FC00FC00FC00FC00FC00FC00FC00FC00FC00FC00FC00FC0FFF8FFF80D27 -7EA611>I108 DII<007F800003FFF0 -0007C0F8001F807E003F003F003F003F007E001F807E001F80FE001FC0FE001FC0FE001FC0FE00 -1FC0FE001FC0FE001FC0FE001FC0FE001FC07E001F807E001F803F003F003F003F001F807E000F -C0FC0003FFF000007F80001A187E971F>II114 D<07F9801FFF803C0F80700380F00180F00180F00180FC0000FF8000 -7FFC007FFE003FFF800FFFC003FFC0001FE00003E0C001E0C001E0E001E0E001C0F003C0FC0780 -EFFF00C3FC0013187E9718>I<00600000600000600000600000E00000E00001E00001E00003E0 -0007E0001FE000FFFFC0FFFFC007E00007E00007E00007E00007E00007E00007E00007E00007E0 -0007E00007E00007E00007E06007E06007E06007E06007E06007E06003E0C003F0C001FF80007E -0013237FA218>III120 DI<3FFF -F83FFFF83E03F03807F0300FE0700FC0701F80603F80603F00607E0000FE0000FC0001F80003F8 -1803F01807E0180FE0180FC0381F80303F80707F00707E01F0FFFFF0FFFFF015187E971B>I -E /Fj 29 122 df<0003F07C001E0DC600380F0F00701E0F00E01E0E00E00C0001C01C0001C01C -0001C01C0001C01C0001C01C00038038007FFFFFC0038038000380380003803800038038000700 -700007007000070070000700700007007000070070000E00E0000E00E0000E00E0000E00E0000E -00E0000E00E0001C01C0001E01E000FF8FFE0020207E9F1B>11 D<0003E0001C1800381800703C -00E03C00E03801C00001C00001C00001C00001C0000380007FFFF0038070038070038070038070 -0700E00700E00700E00700E00700E00700E00E01C00E01C00E01C00E01C00E01C00E01C01C0380 -1E03C0FF0FF816207E9F19>I<0003F03F00001E09E08000380F80C000701F01E000E03E01E000 -E01E01C001C01C000001C01C000001C01C000001C01C000001C01C000003803800007FFFFFFF80 -038038038003803803800380380380038038038007007007000700700700070070070007007007 -00070070070007007007000E00E00E000E00E00E000E00E00E000E00E00E000E00E00E000E00E0 -0E001C01C01C001E01E01E00FF8FF8FFC023207E9F26>14 D<0020000060000060000060000060 -007061C03843800E4E0007580001E00001E00006B8001C9C00708700E083800180000180000180 -0001800001000012147AA117>42 D45 D<000C001C00FC0F3800380038 -00380038003800700070007000700070007000E000E000E000E000E000E001C001C001C001C001 -C001C0038003C0FFFE0F1E7C9D17>49 D<003F8000C1E00100F00200780400780400780F007C0F -807C0F807C0F00780600780000F80000F00001E00001C0000380000700000E00001C0000380000 -600000C0000180000300200600200800401000403FFFC07FFF80FFFF80161E7E9D17>I<07F800 -0C0C001E06001E07001C070000070000070000070000FF0007C7001E07003C0E00780E00F00E10 -F00E10F00E10F01E10F02E20784F401F878014147D9317>97 D<01FC07060E0F1C0F380E780070 -00F000F000F000F000E000E000E000E000F0027004300818300FC010147C9314>99 -D<0000700003F00000F00000700000700000E00000E00000E00000E00000E00000E00001C000F9 -C00305C00E03C01C03C03801C0780380700380F00380F00380F00380F00380E00700E00700E007 -00E00700E00700700F00301E00186F000F8FE014207C9F19>I<00F800070E000E07001C070038 -0380780380700380F00380F00380FFFF80F00000E00000E00000E00000E00000F0010070020030 -04001C180007E00011147D9314>I<0007800018C00031E00061E000E1C000C00001C00001C000 -01C00001C00001C0000380007FF800038000038000038000038000070000070000070000070000 -0700000700000E00000E00000E00000E00000E00000E00001C00001E0000FFE00013207E9F0E> -I<00000E003E1100E1A301C1C20381E00780E00701E00F01E00F01E00F01E00703C00703800787 -0004FC000800000800001800001C00000FFF000FFFC007FFE01800F0300030600030C00030C000 -30C000306000603000C01C070007FC00181F809417>I<00E00007E00001E00000E00000E00001 -C00001C00001C00001C00001C00001C000038000038F800390E003A0E003C0600380600780E007 -00E00700E00700E00700E00700E00E01C00E01C00E01C00E01C00E01C00E01C01C03801E03C0FF -CFF815207E9F19>I<01C003E003E003C0018000000000000000000000000003801F8007800380 -03800700070007000700070007000E000E000E000E000E000E001C001E00FF800B1F7F9E0C>I< -00E007E001E000E000E001C001C001C001C001C001C00380038003800380038003800700070007 -000700070007000E000E000E000E000E000E001C001E00FFC00B207F9F0C>108 -D<0387C07C001F9861860007A072070003C0340300038038030007807807000700700700070070 -07000700700700070070070007007007000E00E00E000E00E00E000E00E00E000E00E00E000E00 -E00E000E00E00E001C01C01C001E01E01E00FFCFFCFFC022147E9326>I<038F801F90E007A0E0 -03C0600380600780E00700E00700E00700E00700E00700E00E01C00E01C00E01C00E01C00E01C0 -0E01C01C03801E03C0FFCFF815147E9319>I<00FC000387000E01801C00C03800E03800E07000 -F0F000F0F000F0F000F0F000F0E001E0E001E0E001C0E003C0F00380700700380E001C1C0007E0 -0014147D9317>I<00E3E007EC3800F01C00E01E00E00E01C00E01C00F01C00F01C00F01C00F01 -C00F03801E03801E03801C03803C0380380380700740E00721C0071F000700000700000700000E -00000E00000E00000E00001E0000FFC000181D809319>I<00F040038CC00E04C01C03C03C03C0 -780380780380F00380F00380F00380F00380E00700E00700E00700F00700F00F00700F00301E00 -186E000F8E00000E00000E00000E00001C00001C00001C00001C00003C0001FF80121D7C9318> -I<038E001FB38007C78003C7800383000780000700000700000700000700000700000E00000E00 -000E00000E00000E00000E00001C00001E0000FFE00011147E9312>I<01F2060E080618061802 -380438001E001FE00FF003F8003C401C400C400C600C6018E010D0608FC00F147E9312>I<0080 -010001000100030007000F001E00FFF80E000E000E000E001C001C001C001C001C001C00380038 -203820382038203840384018800F000D1C7C9B12>I<1C0380FC1F803C07801C03801C03803807 -00380700380700380700380700380700700E00700E00700E00700E00701E00701E00703C00305E -001F9FC012147B9319>II< -FF9FE1FC3E0780701C0300601C0300401C0380401C0380800E0780800E0581000E0981000E09C2 -000E11C2000731C4000721C4000760C8000740C8000780F0000780F0000300E000030060000200 -40001E147C9321>I<1FF0FF03C07801C06001C04000E08000E180007300007600003C00003C00 -001C00002E00004E000087000107000203800603800C01C03E03E0FF07FC18147F9318>I<0FF8 -3F8001E00E0001C00C0001C0080000E0180000E0100000E0200000E0200000F040000070400000 -708000007080000071000000390000003A0000003E0000003C0000003800000018000000100000 -0010000000200000002000000040000070C00000F0800000F1000000E20000007C000000191D80 -9318>I E /Fk 36 122 df<0001C0000003C000000FC000007FC0001FFFC000FFFFC000FFBFC0 -00E03FC000003FC000003FC000003FC000003FC000003FC000003FC000003FC000003FC000003F -C000003FC000003FC000003FC000003FC000003FC000003FC000003FC000003FC000003FC00000 -3FC000003FC000003FC000003FC000003FC000003FC000003FC000003FC000003FC000003FC000 -003FC000003FC000003FC000003FC000003FC000003FC000003FC0007FFFFFE07FFFFFE07FFFFF -E01B2E7AAD28>49 D<003FE00001FFFE0007FFFF800F80FFC01E003FE038001FF07C000FF87E00 -07FCFF0007FCFF8007FEFF8007FEFF8003FEFF8003FE7F0003FE3E0007FE000007FE000007FC00 -0007FC00000FF800000FF800000FF000001FE000001FC000003F8000007F0000007E000000F800 -0001F0000003E0000007C000000F0000001E000E003C000E0038000E0070001E00E0001C01C000 -1C0300003C07FFFFFC0FFFFFFC1FFFFFFC3FFFFFFC7FFFFFF8FFFFFFF8FFFFFFF8FFFFFFF81F2E -7CAD28>I<0000007800000000000078000000000000FC000000000000FC000000000000FC0000 -00000001FE000000000001FE000000000003FF000000000003FF000000000007FF800000000007 -FF800000000007FF80000000000FFFC0000000000E7FC0000000001E7FE0000000001C3FE00000 -00001C3FE000000000383FF000000000381FF000000000781FF800000000700FF800000000700F -F800000000E00FFC00000000E007FC00000001E007FE00000001C003FE00000001C003FE000000 -038003FF000000038001FF000000078001FF800000070000FF800000070000FF8000000FFFFFFF -C000000FFFFFFFC000001FFFFFFFE000001C00003FE000003C00003FF000003800001FF0000038 -00001FF000007000001FF800007000000FF80000F000000FFC0000E0000007FC0000E0000007FC -0001C0000007FE0003E0000003FE00FFFF8001FFFFFCFFFF8001FFFFFCFFFF8001FFFFFC36317D -B03D>65 DI<000003FF80018000003FFFF003800001FFFFFC07800007FF003F0F80001FF800079F80 -003FC00001FF8000FF800000FF8001FE0000007F8003FC0000003F8007FC0000001F8007F80000 -000F800FF00000000F801FF000000007801FF000000007803FE000000007803FE000000003807F -E000000003807FE000000003807FC000000000007FC00000000000FFC00000000000FFC0000000 -0000FFC00000000000FFC00000000000FFC00000000000FFC00000000000FFC00000000000FFC0 -0000000000FFC000000000007FC000000000007FC000000000007FE000000000007FE000000003 -803FE000000003803FE000000003801FF000000003801FF000000007800FF0000000070007F800 -0000070007FC0000000E0003FC0000001E0001FE0000001C0000FF8000007800003FC00000F000 -001FF80003E0000007FF003F80000001FFFFFE000000003FFFF80000000003FF80000031317CB0 -3A>I70 -D<000003FF00030000007FFFF007000001FFFFFC0F000007FF007E1F00001FF0000FBF00007FC0 -0003FF0000FF800001FF0001FE0000007F0003FC0000007F0007FC0000003F000FF80000001F00 -0FF00000001F001FF00000000F001FF00000000F003FE000000007003FE000000007007FE00000 -0007007FE000000007007FC00000000000FFC00000000000FFC00000000000FFC00000000000FF -C00000000000FFC00000000000FFC00000000000FFC00000000000FFC00000000000FFC0000000 -0000FFC00000000000FFC00007FFFFFC7FC00007FFFFFC7FE00007FFFFFC7FE0000001FF003FE0 -000001FF003FE0000001FF001FF0000001FF001FF0000001FF000FF0000001FF000FF8000001FF -0007FC000001FF0003FC000001FF0001FE000001FF0000FF800001FF00007FC00003FF00001FF8 -00077F000007FF003E3F000001FFFFFC1F0000007FFFF00F00000003FF80030036317CB03F>I< -FFFFFF807FFFFFC0FFFFFF807FFFFFC0FFFFFF807FFFFFC000FF8000007FC00000FF8000007FC0 -0000FF8000007FC00000FF8000007FC00000FF8000007FC00000FF8000007FC00000FF8000007F -C00000FF8000007FC00000FF8000007FC00000FF8000007FC00000FF8000007FC00000FF800000 -7FC00000FF8000007FC00000FF8000007FC00000FF8000007FC00000FF8000007FC00000FF8000 -007FC00000FF8000007FC00000FF8000007FC00000FFFFFFFFFFC00000FFFFFFFFFFC00000FFFF -FFFFFFC00000FF8000007FC00000FF8000007FC00000FF8000007FC00000FF8000007FC00000FF -8000007FC00000FF8000007FC00000FF8000007FC00000FF8000007FC00000FF8000007FC00000 -FF8000007FC00000FF8000007FC00000FF8000007FC00000FF8000007FC00000FF8000007FC000 -00FF8000007FC00000FF8000007FC00000FF8000007FC00000FF8000007FC00000FF8000007FC0 -0000FF8000007FC00000FF8000007FC000FFFFFF807FFFFFC0FFFFFF807FFFFFC0FFFFFF807FFF -FFC03A317EB03F>II78 D80 D<7FFFFFFFFFFF007FFFFFFFFFFF007FFFFFFFFFFF007F -C00FF801FF007E000FF8003F007C000FF8001F0078000FF8000F0078000FF8000F0070000FF800 -0700F0000FF8000780F0000FF8000780F0000FF8000780E0000FF8000380E0000FF8000380E000 -0FF8000380E0000FF8000380E0000FF800038000000FF800000000000FF800000000000FF80000 -0000000FF800000000000FF800000000000FF800000000000FF800000000000FF800000000000F -F800000000000FF800000000000FF800000000000FF800000000000FF800000000000FF8000000 -00000FF800000000000FF800000000000FF800000000000FF800000000000FF800000000000FF8 -00000000000FF800000000000FF800000000000FF800000000000FF800000000000FF800000000 -000FF800000000000FF800000000000FF8000000007FFFFFFF0000007FFFFFFF0000007FFFFFFF -000031307DAF38>84 DII<00FFF0000003FFFE00000F803F80000FC00FE0001F -E007F0001FE007F0001FE003F8000FC003FC00078003FC00000003FC00000003FC00000003FC00 -000003FC000000FFFC00001FFFFC0000FFE3FC0003FC03FC000FF003FC001FC003FC003FC003FC -007F8003FC007F8003FC00FF0003FC00FF0003FC00FF0003FC00FF0007FC00FF0007FC007F800D -FC003FC019FE001FE070FFF007FFE07FF000FF803FF024207E9F27>97 D<01F8000000FFF80000 -00FFF8000000FFF80000000FF800000007F800000007F800000007F800000007F800000007F800 -000007F800000007F800000007F800000007F800000007F800000007F800000007F800000007F8 -00000007F83FE00007F8FFFC0007FBE07F0007FF001F8007FE000FC007FC000FE007F80007F007 -F80007F807F80007F807F80003FC07F80003FC07F80003FC07F80003FE07F80003FE07F80003FE -07F80003FE07F80003FE07F80003FE07F80003FE07F80003FE07F80003FC07F80003FC07F80003 -FC07F80007F807F80007F807F80007F007FC000FE007FE000FC007E7003F8007C3C0FE000780FF -F80007003FC00027327EB12D>I<000FFF00007FFFC001FC01F003F003F007E007F80FE007F81F -C007F83FC003F03FC001E07F8000007F8000007F800000FF800000FF800000FF800000FF800000 -FF800000FF800000FF800000FF8000007F8000007F8000007F8000003FC0001C3FC0001C1FC000 -380FE0003807E0007003F001E001FC07C0007FFF00000FF8001E207D9F24>I<0000000FC00000 -07FFC0000007FFC0000007FFC00000007FC00000003FC00000003FC00000003FC00000003FC000 -00003FC00000003FC00000003FC00000003FC00000003FC00000003FC00000003FC00000003FC0 -0000003FC00007F83FC0003FFF3FC000FE07BFC003F801FFC007E0007FC00FE0007FC01FC0003F -C03FC0003FC03FC0003FC07F80003FC07F80003FC07F80003FC0FF80003FC0FF80003FC0FF8000 -3FC0FF80003FC0FF80003FC0FF80003FC0FF80003FC0FF80003FC07F80003FC07F80003FC07F80 -003FC03FC0003FC03FC0003FC01FC0003FC00FE0007FC007E000FFC003F003FFE001FC0F3FFE00 -7FFE3FFE000FF03FFE27327DB12D>I<000FFC00007FFF8001FC0FC003F003E007E001F00FE001 -F81FC000FC3FC000FE3FC000FE7F80007E7F80007F7F80007FFF80007FFF80007FFFFFFFFFFFFF -FFFFFF800000FF800000FF800000FF8000007F8000007F8000007F8000003FC000071FC000071F -C0000E0FE0000E07F0001C03F8007800FE03E0003FFFC00007FE0020207E9F25>I<0001FE0000 -0FFF80001FC3C0007F07E000FE0FF001FE0FF001FC0FF003FC0FF003FC07E003FC018003FC0000 -03FC000003FC000003FC000003FC000003FC000003FC000003FC0000FFFFFC00FFFFFC00FFFFFC -0003FC000003FC000003FC000003FC000003FC000003FC000003FC000003FC000003FC000003FC -000003FC000003FC000003FC000003FC000003FC000003FC000003FC000003FC000003FC000003 -FC000003FC000003FC000003FC000003FC000003FC000003FC00007FFFF0007FFFF0007FFFF000 -1C327EB119>I<001FF007C000FFFE3FE001F83F79F007E00FC3F00FE00FE1F00FC007E0E01FC0 -07F0001FC007F0003FC007F8003FC007F8003FC007F8003FC007F8003FC007F8001FC007F0001F -C007F0000FC007E0000FE00FE00007E00FC00003F83F000006FFFE00000E1FF000000E00000000 -1E000000001E000000001F000000001F800000001FFFFF80000FFFFFF0000FFFFFFC0007FFFFFE -0003FFFFFF0003FFFFFF800FFFFFFFC01F00007FC07E00001FE07C00000FE0FC000007E0FC0000 -07E0FC000007E0FC000007E07E00000FC03E00000F803F00001F800FC0007E0007F803FC0001FF -FFF000001FFF0000242F7E9F28>I<01F8000000FFF8000000FFF8000000FFF80000000FF80000 -0007F800000007F800000007F800000007F800000007F800000007F800000007F800000007F800 -000007F800000007F800000007F800000007F800000007F800000007F807F80007F83FFE0007F8 -783F0007F8C03F8007F9801FC007FB001FC007FE001FE007FC001FE007FC001FE007FC001FE007 -F8001FE007F8001FE007F8001FE007F8001FE007F8001FE007F8001FE007F8001FE007F8001FE0 -07F8001FE007F8001FE007F8001FE007F8001FE007F8001FE007F8001FE007F8001FE007F8001F -E007F8001FE007F8001FE007F8001FE0FFFFC3FFFFFFFFC3FFFFFFFFC3FFFF28327DB12D>I<03 -C00007E0000FF0001FF8001FF8001FF8001FF8000FF00007E00003C00000000000000000000000 -000000000000000000000000000000000001F800FFF800FFF800FFF8000FF80007F80007F80007 -F80007F80007F80007F80007F80007F80007F80007F80007F80007F80007F80007F80007F80007 -F80007F80007F80007F80007F80007F80007F80007F80007F800FFFF80FFFF80FFFF8011337DB2 -17>I<01F800FFF800FFF800FFF8000FF80007F80007F80007F80007F80007F80007F80007F800 -07F80007F80007F80007F80007F80007F80007F80007F80007F80007F80007F80007F80007F800 -07F80007F80007F80007F80007F80007F80007F80007F80007F80007F80007F80007F80007F800 -07F80007F80007F80007F80007F80007F80007F80007F80007F800FFFFC0FFFFC0FFFFC012327D -B117>108 D<03F007F8001FE000FFF03FFE00FFF800FFF0783F01E0FC00FFF0C03F8300FE000F -F1801FC6007F0007F3001FCC007F0007F6001FF8007F8007FC001FF0007F8007FC001FF0007F80 -07FC001FF0007F8007F8001FE0007F8007F8001FE0007F8007F8001FE0007F8007F8001FE0007F -8007F8001FE0007F8007F8001FE0007F8007F8001FE0007F8007F8001FE0007F8007F8001FE000 -7F8007F8001FE0007F8007F8001FE0007F8007F8001FE0007F8007F8001FE0007F8007F8001FE0 -007F8007F8001FE0007F8007F8001FE0007F8007F8001FE0007F8007F8001FE0007F8007F8001F -E0007F80FFFFC3FFFF0FFFFCFFFFC3FFFF0FFFFCFFFFC3FFFF0FFFFC3E207D9F43>I<03F007F8 -00FFF03FFE00FFF0783F00FFF0C03F800FF1801FC007F3001FC007F6001FE007FC001FE007FC00 -1FE007FC001FE007F8001FE007F8001FE007F8001FE007F8001FE007F8001FE007F8001FE007F8 -001FE007F8001FE007F8001FE007F8001FE007F8001FE007F8001FE007F8001FE007F8001FE007 -F8001FE007F8001FE007F8001FE007F8001FE007F8001FE0FFFFC3FFFFFFFFC3FFFFFFFFC3FFFF -28207D9F2D>I<0007FC0000007FFFC00001FC07F00003F001F80007E000FC000FC0007E001FC0 -007F003FC0007F803F80003F807F80003FC07F80003FC07F80003FC0FF80003FE0FF80003FE0FF -80003FE0FF80003FE0FF80003FE0FF80003FE0FF80003FE0FF80003FE07F80003FC07F80003FC0 -7F80003FC03FC0007F803FC0007F801FC0007F000FE000FE0007E000FC0003F803F80001FE0FF0 -00007FFFC0000007FC000023207E9F28>I<01F83FE000FFF8FFFC00FFFBE07F00FFFF003F8007 -FE001FC007FC000FE007F8000FF007F80007F807F80007F807F80007FC07F80003FC07F80003FC -07F80003FE07F80003FE07F80003FE07F80003FE07F80003FE07F80003FE07F80003FE07F80003 -FE07F80003FC07F80007FC07F80007FC07F80007F807F80007F807F8000FF007FC000FE007FE00 -1FC007FF003F8007FBC0FE0007F8FFF80007F83FC00007F800000007F800000007F800000007F8 -00000007F800000007F800000007F800000007F800000007F800000007F800000007F8000000FF -FFC00000FFFFC00000FFFFC00000272E7E9F2D>I<03F03F00FFF07FC0FFF1C3E0FFF187E00FF3 -0FF007F60FF007F60FF007FC07E007FC03C007FC000007FC000007F8000007F8000007F8000007 -F8000007F8000007F8000007F8000007F8000007F8000007F8000007F8000007F8000007F80000 -07F8000007F8000007F8000007F8000007F80000FFFFE000FFFFE000FFFFE0001C207E9F21> -114 D<01FF860007FFFE001F00FE003C003E0078001E0078000E00F8000E00F8000E00F8000E00 -FC000000FF800000FFFC00007FFFC0007FFFF0003FFFF8001FFFFC0007FFFE0001FFFF00003FFF -000000FF8000003F8060001F80E0000F80E0000F80F0000F80F0000F00F8000F00FC001E00FE00 -1C00FF807800F3FFF000C07F800019207D9F20>I<001C0000001C0000001C0000001C0000001C -0000003C0000003C0000003C0000007C0000007C000000FC000001FC000003FC000007FC00001F -FFFE00FFFFFE00FFFFFE0003FC000003FC000003FC000003FC000003FC000003FC000003FC0000 -03FC000003FC000003FC000003FC000003FC000003FC000003FC000003FC000003FC000003FC03 -8003FC038003FC038003FC038003FC038003FC038003FC038001FC038001FC070000FE0700007F -0E00003FFC000007F000192E7FAD1F>I<01F80007E0FFF803FFE0FFF803FFE0FFF803FFE00FF8 -003FE007F8001FE007F8001FE007F8001FE007F8001FE007F8001FE007F8001FE007F8001FE007 -F8001FE007F8001FE007F8001FE007F8001FE007F8001FE007F8001FE007F8001FE007F8001FE0 -07F8001FE007F8001FE007F8001FE007F8001FE007F8003FE007F8003FE003F8007FE003F8007F -E001FC00DFF000FE039FFF007FFF1FFF000FFC1FFF28207D9F2D>II< -FFFF1FFFE07FF8FFFF1FFFE07FF8FFFF1FFFE07FF80FF000FE0007800FF800FE00078007F800FE -00070007F8007F00070003FC007F000E0003FC00FF800E0003FE00FF801E0001FE00FF801C0001 -FE01DFC01C0001FF01DFC03C0000FF03DFE0380000FF838FE07800007F838FE07000007F8707F0 -7000007FC707F0F000003FCF07F8E000003FCE03F8E000001FEE03F9C000001FFC01FDC000001F -FC01FFC000000FFC01FF8000000FF800FF80000007F800FF00000007F0007F00000007F0007F00 -000003F0007E00000003E0003E00000001E0003C00000001C0001C000035207E9F3A>I<7FFF80 -7FFC7FFF807FFC7FFF807FFC03FE000F0001FE001E0000FF003C0000FF807800007FC07800003F -E0F000001FE1E000000FF3C000000FFF80000007FF00000003FE00000001FE00000000FF000000 -00FF80000000FFC0000001FFC0000003DFE00000078FF00000078FF800000F07FC00001E03FC00 -003C01FE00007800FF0000F000FF8000E0007FC001E0003FC0FFFC01FFFFFFFC01FFFFFFFC01FF -FF28207F9F2B>II E /Fl 1 14 df<0001FE00000007FF8000001E01E000007800780000 -E0001C000180000600030000030006000001800C000000C00C000000C018000000603000000030 -30000000303000000030600000001860000000186000000018C00000000CC00000000CC0000000 -0CC00000000CC00000000CC00000000CC00000000CC00000000CC00000000C6000000018600000 -0018600000001830000000303000000030300000003018000000600C000000C00C000000C00600 -0001800300000300018000060000E0001C000078007800001E01E0000007FF80000001FE000026 -2B7DA02D>13 D E /Fm 46 122 df<3C007F00FF80FF80FFC0FFC0FFC07FC03EC000C000C00180 -018001800300030006000E001C00380030000A157B8813>44 D<1C007F007F00FF80FF80FF807F -007F001C0009097B8813>46 D<000E00001E00007E0007FE00FFFE00FFFE00F8FE0000FE0000FE -0000FE0000FE0000FE0000FE0000FE0000FE0000FE0000FE0000FE0000FE0000FE0000FE0000FE -0000FE0000FE0000FE0000FE0000FE0000FE0000FE0000FE0000FE0000FE0000FE0000FE0000FE -0000FE007FFFFE7FFFFE7FFFFE17277BA622>49 D<00FF800007FFF0000FFFFC001E03FE003800 -FF807C003F80FE003FC0FF001FC0FF001FE0FF000FE0FF000FE07E000FE03C001FE000001FE000 -001FC000001FC000003F8000003F0000007E000000FC000000F8000001F0000003E00000078000 -000F0000001E0000003C00E0007000E000E000E001C001C0038001C0060001C00FFFFFC01FFFFF -C03FFFFFC07FFFFFC0FFFFFF80FFFFFF80FFFFFF801B277DA622>I<007F800003FFF00007FFFC -000F80FE001F007F003F807F003F803F803F803F803F803F801F803F801F003F8000007F000000 -7F0000007E000000FC000001F8000007F00000FFC00000FFC0000001F80000007E0000003F0000 -003F8000001FC000001FC000001FE000001FE03C001FE07E001FE0FF001FE0FF001FE0FF001FC0 -FF003FC0FE003F807C007F003F00FE001FFFFC0007FFF00000FF80001B277DA622>I<00000E00 -00001E0000003E0000007E000000FE000000FE000001FE000003FE0000077E00000E7E00000E7E -00001C7E0000387E0000707E0000E07E0000E07E0001C07E0003807E0007007E000E007E000E00 -7E001C007E0038007E0070007E00E0007E00FFFFFFF8FFFFFFF8FFFFFFF80000FE000000FE0000 -00FE000000FE000000FE000000FE000000FE000000FE00007FFFF8007FFFF8007FFFF81D277EA6 -22>I<180003001F801F001FFFFE001FFFFC001FFFF8001FFFF0001FFFC0001FFF00001C000000 -1C0000001C0000001C0000001C0000001C0000001C0000001C7FC0001DFFF8001F80FC001E003F -0008003F0000001F8000001FC000001FC000001FE000001FE018001FE07C001FE0FE001FE0FE00 -1FE0FE001FE0FE001FC0FC001FC078003F8078003F803C007F001F01FE000FFFFC0003FFF00000 -FF80001B277DA622>I<380000003E0000003FFFFFF03FFFFFF03FFFFFF07FFFFFE07FFFFFC07F -FFFF807FFFFF0070000E0070000E0070001C00E0003800E0007000E000E0000001E0000001C000 -000380000007800000070000000F0000001F0000001E0000003E0000003E0000007E0000007C00 -00007C000000FC000000FC000000FC000000FC000001FC000001FC000001FC000001FC000001FC -000001FC000001FC000000F80000007000001C297CA822>55 D<00000780000000000780000000 -000FC0000000000FC0000000000FC0000000001FE0000000001FE0000000003FF0000000003FF0 -000000003FF00000000077F80000000077F800000000F7FC00000000E3FC00000000E3FC000000 -01C1FE00000001C1FE00000003C1FF0000000380FF0000000380FF00000007007F80000007007F -8000000F007FC000000E003FC000000E003FC000001C001FE000001C001FE000003FFFFFF00000 -3FFFFFF000003FFFFFF00000700007F80000700007F80000F00007FC0000E00003FC0000E00003 -FC0001C00001FE0001C00001FE0003C00001FF00FFFE003FFFFCFFFE003FFFFCFFFE003FFFFC2E -297EA833>65 DI<00007FE0030007FFFC07001FFFFF0F -007FF00F9F00FF0001FF01FC0000FF03F800007F07F000003F0FE000001F1FC000001F1FC00000 -0F3F8000000F3F800000077F800000077F800000077F00000000FF00000000FF00000000FF0000 -0000FF00000000FF00000000FF00000000FF00000000FF00000000FF000000007F000000007F80 -0000007F800000073F800000073F800000071FC00000071FC000000E0FE000000E07F000001C03 -F800003C01FC00007800FF0001F0007FF007C0001FFFFF800007FFFE0000007FF00028297CA831 ->I69 DI<0000 -7FE003000007FFFC0700001FFFFF0F00007FF00F9F0000FF0001FF0001FC0000FF0003F800007F -0007F000003F000FE000001F001FC000001F001FC000000F003F8000000F003F80000007007F80 -000007007F80000007007F0000000000FF0000000000FF0000000000FF0000000000FF00000000 -00FF0000000000FF0000000000FF0000000000FF0000000000FF0000FFFFF87F0000FFFFF87F80 -00FFFFF87F800000FF003F800000FF003F800000FF001FC00000FF001FC00000FF000FE00000FF -0007F00000FF0003F80000FF0001FC0000FF0000FF0001FF00007FF007FF00001FFFFF9F000007 -FFFE0F0000007FF003002D297CA835>III77 -DI80 -D82 D<00FF00C003FFE1C00FFFF9C01F80FFC03F00 -3FC03E000FC07C0007C07C0007C0FC0003C0FC0003C0FC0001C0FE0001C0FE0001C0FF000000FF -C000007FFC00007FFFE0003FFFF8001FFFFE001FFFFF0007FFFF8003FFFFC000FFFFC0000FFFE0 -00007FE000001FF000000FF0000007F0E00003F0E00003F0E00003F0E00003F0F00003E0F00003 -E0F80007E0FC0007C0FF000F80FFE01F80E3FFFF00E1FFFC00C01FF0001C297CA825>I85 DII<03FF80000FFFF0001F01FC003F80FE003F -807F003F803F003F803F801F003F8000003F8000003F8000003F8000003F80003FFF8001FC3F80 -0FE03F801F803F803F003F807E003F80FC003F80FC003F80FC003F80FC003F80FC005F807E00DF -803F839FFC1FFE0FFC03F803FC1E1B7E9A21>97 D -I<003FF00001FFFC0003F03E000FC07F001F807F003F007F003F007F007F003E007E0000007E00 -0000FE000000FE000000FE000000FE000000FE000000FE000000FE0000007E0000007E0000007F -0000003F0003803F8003801F8007000FE00E0003F83C0001FFF800003FC000191B7E9A1E>I<00 -007FF000007FF000007FF0000007F0000007F0000007F0000007F0000007F0000007F0000007F0 -000007F0000007F0000007F0000007F0000007F0003F87F001FFF7F007F03FF00FC00FF01F8007 -F03F0007F03F0007F07E0007F07E0007F07E0007F0FE0007F0FE0007F0FE0007F0FE0007F0FE00 -07F0FE0007F0FE0007F0FE0007F07E0007F07E0007F03F0007F03F0007F01F800FF00FC01FF007 -E07FFF01FFE7FF007F87FF202A7EA925>I<003FC00001FFF00003E07C000F803E001F801F001F -001F003F000F807E000F807E000FC07E000FC0FE0007C0FE0007C0FFFFFFC0FFFFFFC0FE000000 -FE000000FE0000007E0000007E0000007F0000003F0001C01F0001C00F80038007C0070003F01E -0000FFFC00003FE0001A1B7E9A1F>I<0007F8003FFC007E3E01FC7F03F87F03F07F07F07F07F0 -3E07F00007F00007F00007F00007F00007F00007F000FFFFC0FFFFC0FFFFC007F00007F00007F0 -0007F00007F00007F00007F00007F00007F00007F00007F00007F00007F00007F00007F00007F0 -0007F00007F00007F00007F00007F0007FFF807FFF807FFF80182A7EA915>I<007F80F001FFE3 -F807C0FE1C0F807C7C1F003E7C1F003E103F003F003F003F003F003F003F003F003F003F003F00 -3F001F003E001F003E000F807C0007C0F80005FFE0000C7F8000180000001C0000001C0000001E -0000001FFFF8001FFFFF000FFFFFC007FFFFE003FFFFF00FFFFFF03E0007F07C0001F8F80000F8 -F80000F8F80000F8F80000F87C0001F07C0001F03F0007E00FC01F8007FFFF00007FF0001E287E -9A22>II<07000F801FC03FE03FE03FE01FC00F80 -07000000000000000000000000000000FFE0FFE0FFE00FE00FE00FE00FE00FE00FE00FE00FE00F -E00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE0FFFEFFFEFFFE0F2B7EAA12>I108 DII<003FE00001FFFC0003F07E000FC01F801F800FC03F0007E03F00 -07E07E0003F07E0003F07E0003F0FE0003F8FE0003F8FE0003F8FE0003F8FE0003F8FE0003F8FE -0003F8FE0003F87E0003F07E0003F03F0007E03F0007E01F800FC00FC01F8007F07F0001FFFC00 -003FE0001D1B7E9A22>II114 D<03FE300FFFF03E03F0 -7800F07000F0F00070F00070F80070FE0000FFE0007FFF007FFFC03FFFE01FFFF007FFF800FFF8 -0007FC0000FCE0007CE0003CF0003CF00038F80038FC0070FF01E0E7FFC0C1FF00161B7E9A1B> -I<00700000700000700000700000F00000F00000F00001F00003F00003F00007F0001FFFE0FFFF -E0FFFFE007F00007F00007F00007F00007F00007F00007F00007F00007F00007F00007F00007F0 -0007F00007F07007F07007F07007F07007F07007F07007F07003F0E001F8C000FFC0003F001426 -7FA51A>II -IIII E /Fn 75 127 df<70F8F8F8F8F8F8F8F8F8F8F8 -F8F8F8F8F870000000000070F8F8F870051C779B18>33 D<4010E038F078E038E038E038E038E0 -38E038E038E038E038E03860300D0E7B9C18>I<030600078F00078F00078F00078F00078F0007 -8F007FFFC0FFFFE0FFFFE07FFFC00F1E000F1E000F1E000F1E000F1E000F1E007FFFC0FFFFE0FF -FFE07FFFC01E3C001E3C001E3C001E3C001E3C001E3C000C1800131C7E9B18>I<00C00001C000 -01C00001C00003F0000FFC003FFE007DCF0071C700E1C380E1C780E1C780E1C780F1C00079C000 -3DC0001FE0000FF80003FC0001DE0001CF0001C70061C380F1C380F1C380E1C380E1C70071C700 -79DE003FFE001FF80007E00001C00001C00001C00000C00011247D9F18>I<3803007C07807C07 -80EE0F80EE0F00EE0F00EE1F00EE1E00EE1E00EE3E007C3C007C3C00387C0000780000780000F8 -0000F00001F00001E00001E00003E00003C00003C00007C0000783800787C00F87C00F0EE00F0E -E01F0EE01E0EE01E0EE03E0EE03C07C03C07C018038013247E9F18>I<01C00007E0000FF0000E -70001C38001C38001C38001C38001C73F01C73F01CE3F00FE3800FC7000F87000F07001F0E003F -0E007B8E0073DC00E1DC00E0F800E0F800E07070E0787070FC707FFFE03FCFE00F03C0141C7F9B -18>I<387C7C7E3E0E0E0E1C1C38F8F0C0070E789B18>I<007000F001E003C007800F001E001C00 -380038007000700070007000E000E000E000E000E000E000E000E0007000700070007000380038 -001C001E000F00078003C001F000F000700C24799F18>I<6000F00078003C001E000F00078003 -8001C001C000E000E000E000E00070007000700070007000700070007000E000E000E000E001C0 -01C0038007800F001E003C007800F00060000C247C9F18>I<01C00001C00001C00001C000C1C1 -80F1C780F9CF807FFF001FFC0007F00007F0001FFC007FFF00F9CF80F1C780C1C18001C00001C0 -0001C00001C00011147D9718>I<00600000F00000F00000F00000F00000F00000F00000F0007F -FFC0FFFFE0FFFFE07FFFC000F00000F00000F00000F00000F00000F00000F00000600013147E97 -18>I<1C3E7E7F3F1F070E1E7CF860080C788518>I<7FFF00FFFF80FFFF807FFF0011047D8F18> -I<3078FCFC78300606778518>I<000300000780000780000F80000F00001F00001E00001E0000 -3E00003C00007C0000780000780000F80000F00001F00001E00003E00003C00003C00007C00007 -80000F80000F00000F00001F00001E00003E00003C00003C00007C0000780000F80000F00000F0 -000060000011247D9F18>I<01F00007FC000FFE001F1F001C07003803807803C07001C07001C0 -E000E0E000E0E000E0E000E0E000E0E000E0E000E0E000E0E000E0F001E07001C07001C07803C0 -3803801C07001F1F000FFE0007FC0001F000131C7E9B18>I<01800380038007800F803F80FF80 -FB80438003800380038003800380038003800380038003800380038003800380038003807FFCFF -FE7FFC0F1C7B9B18>I<03F0000FFE003FFF007C0F807003C0E001C0F000E0F000E06000E00000 -E00000E00001C00001C00003C0000780000F00001E00003C0000780000F00001E00007C0000F80 -001E00E03C00E07FFFE0FFFFE07FFFE0131C7E9B18>I<001F00003F0000770000770000E70001 -E70001C7000387000787000707000E07001E07003C0700380700780700F00700FFFFF8FFFFF8FF -FFF8000700000700000700000700000700000700007FF000FFF8007FF0151C7F9B18>52 -D<007E0001FF0007FF800F83C01E03C01C03C0380180380000700000700000E1F800E7FE00FFFF -00FE0780F803C0F001C0F000E0E000E0F000E07000E07000E07000E03801C03C03C01E07800FFF -0007FE0001F800131C7E9B18>54 D<3078FCFC783000000000000000003078FCFC783006147793 -18>58 D<183C7E7E3C180000000000000000183C7E7E3E1E0E1C3C78F060071A789318>I<0003 -00000780001F80003F00007E0001FC0003F00007E0001FC0003F00007E0000FC0000FC00007E00 -003F00001FC00007E00003F00001FC00007E00003F00001F8000078000030011187D9918>I<7F -FFC0FFFFE0FFFFE0FFFFE0000000000000000000000000FFFFE0FFFFE0FFFFE07FFFC0130C7E93 -18>I<600000F00000FC00007E00003F00001FC00007E00003F00001FC00007E00003F00001F80 -001F80003F00007E0001FC0003F00007E0001FC0003F00007E0000FC0000F0000060000011187D -9918>I<0FF0003FFC007FFF00700F00F00380F00380600780000F00003E00007C0001F00001E0 -0003C00003C00003C00003C00003C00003800000000000000000000000000000000003800007C0 -0007C00007C000038000111C7D9B18>I<00700000F80000F80000D80000D80001DC0001DC0001 -DC00018C00038E00038E00038E00038E000306000707000707000707000707000FFF800FFF800F -FF800E03800E03801C01C01C01C07F07F0FF8FF87F07F0151C7F9B18>65 -D<7FF800FFFE007FFF001C0F801C03C01C03C01C01E01C00E01C00E01C00F01C00701C00701C00 -701C00701C00701C00701C00701C00701C00F01C00E01C00E01C01E01C01C01C03C01C0F807FFF -00FFFE007FF800141C7F9B18>68 DII<7F07F0FF8FF87F07F01C01C01C01C01C01C01C01C01C01C01C01C01C01C01C01C01C01C01F -FFC01FFFC01FFFC01C01C01C01C01C01C01C01C01C01C01C01C01C01C01C01C01C01C01C01C07F -07F0FF8FF87F07F0151C7F9B18>72 D<7FFF00FFFF807FFF0001C00001C00001C00001C00001C0 -0001C00001C00001C00001C00001C00001C00001C00001C00001C00001C00001C00001C00001C0 -0001C00001C00001C00001C0007FFF00FFFF807FFF00111C7D9B18>I<7FE000FFE0007FE0000E -00000E00000E00000E00000E00000E00000E00000E00000E00000E00000E00000E00000E00000E -00000E00000E00000E00000E00700E00700E00700E00700E00707FFFF0FFFFF07FFFF0141C7F9B -18>76 D<7E07F0FF0FF87F07F01D81C01D81C01D81C01DC1C01CC1C01CC1C01CE1C01CE1C01CE1 -C01C61C01C71C01C71C01C31C01C39C01C39C01C39C01C19C01C19C01C1DC01C0DC01C0DC01C0D -C07F07C0FF87C07F03C0151C7F9B18>78 D<0FF8003FFE007FFF00780F00700700F00780E00380 -E00380E00380E00380E00380E00380E00380E00380E00380E00380E00380E00380E00380E00380 -E00380E00380F00780700700780F007FFF003FFE000FF800111C7D9B18>II<7FF800FFFE007FFF001C0F801C03801C03C01C01C01C01C01C01C01C03C01C03801C -0F801FFF001FFE001FFE001C0F001C07001C03801C03801C03801C03801C03801C039C1C039C1C -039C7F01F8FF81F87F00F0161C7F9B18>82 D<03F3801FFF803FFF807C0F80700780E00380E003 -80E00380E000007000007800003F00001FF00007FE0000FF00000F800003C00001C00000E00000 -E06000E0E000E0E001E0F001C0F80780FFFF80FFFE00E7F800131C7E9B18>I<7FFFF8FFFFF8FF -FFF8E07038E07038E07038E0703800700000700000700000700000700000700000700000700000 -700000700000700000700000700000700000700000700000700000700007FF0007FF0007FF0015 -1C7F9B18>II89 -D91 D<600000F00000F00000F800007800007C00003C00003C00003E00001E00001F00000F0000 -0F00000F800007800007C00003C00003C00003E00001E00001F00000F00000F800007800007800 -007C00003C00003E00001E00001E00001F00000F00000F8000078000078000030011247D9F18> -II<018007C01FF07EFCF83EE00E0F067C9B18>I<7FFF00FFFF80FFFF807FFF0011047D7F18>I< -061E3E387070E0E0E0F8FC7C7C38070E789E18>I<1FE0003FF8007FFC00781E00300E00000700 -00070000FF0007FF001FFF007F0700780700E00700E00700E00700F00F00781F003FFFF01FFBF0 -07E1F014147D9318>I<7E0000FE00007E00000E00000E00000E00000E00000E00000E3E000EFF -800FFFC00FC1E00F80E00F00700E00700E00380E00380E00380E00380E00380E00380F00700F00 -700F80E00FC1E00FFFC00EFF80063E00151C809B18>I<01FE0007FF001FFF803E078038030070 -0000700000E00000E00000E00000E00000E00000E000007000007001C03801C03E03C01FFF8007 -FF0001FC0012147D9318>I<001F80003F80001F8000038000038000038000038000038003E380 -0FFB801FFF803C1F80380F80700780700380E00380E00380E00380E00380E00380E00380700780 -700780380F803C1F801FFFF00FFBF803E3F0151C7E9B18>I<01F00007FC001FFE003E0F003807 -80700380700380E001C0E001C0FFFFC0FFFFC0FFFFC0E000007000007001C03801C03E03C01FFF -8007FF0001FC0012147D9318>I<001F80007FC000FFE000E1E001C0C001C00001C00001C0007F -FFC0FFFFC0FFFFC001C00001C00001C00001C00001C00001C00001C00001C00001C00001C00001 -C00001C00001C00001C0007FFF007FFF007FFF00131C7F9B18>I<01E1F007FFF80FFFF81E1E30 -1C0E003807003807003807003807003807001C0E001E1E001FFC001FF80039E0003800001C0000 -1FFE001FFFC03FFFE07801F0700070E00038E00038E00038E000387800F07E03F01FFFC00FFF80 -01FC00151F7F9318>I<7E0000FE00007E00000E00000E00000E00000E00000E00000E3E000EFF -800FFFC00FC1C00F80E00F00E00E00E00E00E00E00E00E00E00E00E00E00E00E00E00E00E00E00 -E00E00E00E00E07FC3FCFFE7FE7FC3FC171C809B18>I<03800007C00007C00007C00003800000 -00000000000000000000007FC000FFC0007FC00001C00001C00001C00001C00001C00001C00001 -C00001C00001C00001C00001C00001C00001C00001C000FFFF00FFFF80FFFF00111D7C9C18>I< -7FE000FFE0007FE00000E00000E00000E00000E00000E00000E00000E00000E00000E00000E000 -00E00000E00000E00000E00000E00000E00000E00000E00000E00000E00000E00000E0007FFFC0 -FFFFE07FFFC0131C7E9B18>108 D<7CE0E000FFFBF8007FFFF8001F1F1C001E1E1C001E1E1C00 -1C1C1C001C1C1C001C1C1C001C1C1C001C1C1C001C1C1C001C1C1C001C1C1C001C1C1C001C1C1C -001C1C1C007F1F1F00FFBFBF807F1F1F001914819318>I<7E3E00FEFF807FFFC00FC1C00F80E0 -0F00E00E00E00E00E00E00E00E00E00E00E00E00E00E00E00E00E00E00E00E00E00E00E07FC3FC -FFE7FE7FC3FC1714809318>I<01F0000FFE001FFF003E0F803803807001C07001C0E000E0E000 -E0E000E0E000E0E000E0F001E07001C07803C03C07803E0F801FFF000FFE0001F00013147E9318 ->I<7E3E00FEFF807FFFC00FC1E00F80E00F00700E00700E00380E00380E00380E00380E00380E -00380F00700F00700F80E00FC1E00FFFC00EFF800E3E000E00000E00000E00000E00000E00000E -00000E00007FC000FFE0007FC000151E809318>I<01E38007FB801FFF803E1F80380F80700780 -700780E00380E00380E00380E00380E00380E00380700780700780380F803C1F801FFF800FFB80 -03E380000380000380000380000380000380000380000380003FF8003FF8003FF8151E7E9318> -I<7F87E0FF9FF07FBFF803F87803F03003E00003C00003C0000380000380000380000380000380 -000380000380000380000380007FFE00FFFF007FFE0015147F9318>I<07F7003FFF007FFF0078 -0F00E00700E00700E007007C00007FE0001FFC0003FE00001F00600780E00380E00380F00380F8 -0F00FFFF00FFFC00E7F00011147D9318>I<0180000380000380000380000380007FFFC0FFFFC0 -FFFFC00380000380000380000380000380000380000380000380000380000380400380E00380E0 -0380E001C1C001FFC000FF80003E0013197F9818>I<7E07E0FE0FE07E07E00E00E00E00E00E00 -E00E00E00E00E00E00E00E00E00E00E00E00E00E00E00E00E00E00E00E01E00F03E007FFFC03FF -FE01FCFC1714809318>I<7F8FF0FF8FF87F8FF01E03C00E03800E03800E038007070007070007 -0700038E00038E00038E00038E0001DC0001DC0001DC0000F80000F80000700015147F9318>I< -FF8FF8FF8FF8FF8FF83800E03800E03800E01C01C01C01C01C71C01CF9C01CF9C01CD9C01CD9C0 -0DDD800DDD800DDD800D8D800F8F800F8F8007070015147F9318>I<7F8FF07F9FF07F8FF00707 -00078E00039E0001DC0001F80000F80000700000F00000F80001DC00039E00038E000707000F07 -807F8FF0FF8FF87F8FF015147F9318>I<7F8FF0FF8FF87F8FF00E01C00E03800E038007038007 -0700070700038700038600038E0001CE0001CE0000CC0000CC0000DC0000780000780000780000 -700000700000700000F00000E00079E0007BC0007F80003F00001E0000151E7F9318>I<3FFFF0 -7FFFF07FFFF07001E07003C0700780000F00001E00003C0000F80001F00003C0000780000F0070 -1E00703C0070780070FFFFF0FFFFF0FFFFF014147F9318>I<0007E0001FE0007FE000780000E0 -0000E00000E00000E00000E00000E00000E00000E00000E00000E00000E00001E0007FC000FF80 -00FF80007FC00001E00000E00000E00000E00000E00000E00000E00000E00000E00000E00000E0 -0000E000007800007FE0001FE00007E013247E9F18>I<60F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0 -F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0600424769F18>I<7C0000FF0000FFC00003C000 -00E00000E00000E00000E00000E00000E00000E00000E00000E00000E00000E00000F000007FC0 -003FE0003FE0007FC000F00000E00000E00000E00000E00000E00000E00000E00000E00000E000 -00E00000E00003C000FFC000FF00007C000013247E9F18>I<060C1F1E3FBEFBF8F1F060C00F06 -7C9B18>I E /Fo 75 123 df<001F83E000F06E3001C078780380F8780300F030070070000700 -70000700700007007000070070000700700007007000FFFFFF8007007000070070000700700007 -007000070070000700700007007000070070000700700007007000070070000700700007007000 -07007000070070000700700007007000070070007FE3FF001D20809F1B>11 -D<003F0000E0C001C0C00381E00701E00701E0070000070000070000070000070000070000FFFF -E00700E00700E00700E00700E00700E00700E00700E00700E00700E00700E00700E00700E00700 -E00700E00700E00700E00700E00700E07FC3FE1720809F19>I<003FE000E0E001C1E00381E007 -00E00700E00700E00700E00700E00700E00700E00700E0FFFFE00700E00700E00700E00700E007 -00E00700E00700E00700E00700E00700E00700E00700E00700E00700E00700E00700E00700E007 -00E07FE7FE1720809F19>I<001F81F80000F04F040001C07C06000380F80F000300F00F000700 -F00F00070070000007007000000700700000070070000007007000000700700000FFFFFFFF0007 -007007000700700700070070070007007007000700700700070070070007007007000700700700 -070070070007007007000700700700070070070007007007000700700700070070070007007007 -00070070070007007007007FE3FE3FF02420809F26>I<7038F87CFC7EFC7E743A040204020402 -0804080410081008201040200F0E7E9F17>34 D<70F8FCFC74040404080810102040060E7C9F0D ->39 D<0020004000800100020006000C000C00180018003000300030007000600060006000E000 -E000E000E000E000E000E000E000E000E000E000E0006000600060007000300030003000180018 -000C000C000600020001000080004000200B2E7DA112>I<800040002000100008000C00060006 -000300030001800180018001C000C000C000C000E000E000E000E000E000E000E000E000E000E0 -00E000E000C000C000C001C001800180018003000300060006000C00080010002000400080000B -2E7DA112>I<70F8FCFC74040404080810102040060E7C840D>44 DI<70 -F8F8F87005057C840D>I<03F0000E1C001C0E00180600380700700380700380700380700380F0 -03C0F003C0F003C0F003C0F003C0F003C0F003C0F003C0F003C0F003C0F003C0F003C0F003C070 -03807003807003807807803807001806001C0E000E1C0003F000121F7E9D17>48 -D<018003800F80F380038003800380038003800380038003800380038003800380038003800380 -03800380038003800380038003800380038007C0FFFE0F1E7C9D17>I<03F0000C1C00100E0020 -0700400780800780F007C0F803C0F803C0F803C02007C00007C0000780000780000F00000E0000 -1C0000380000700000600000C0000180000300000600400C00401800401000803FFF807FFF80FF -FF80121E7E9D17>I<03F0000C1C00100E00200F00780F80780780780780380F80000F80000F00 -000F00000E00001C0000380003F000003C00000E00000F000007800007800007C02007C0F807C0 -F807C0F807C0F00780400780400F00200E001C3C0003F000121F7E9D17>I<000600000600000E -00000E00001E00002E00002E00004E00008E00008E00010E00020E00020E00040E00080E00080E -00100E00200E00200E00400E00C00E00FFFFF0000E00000E00000E00000E00000E00000E00000E -0000FFE0141E7F9D17>I<1803001FFE001FFC001FF8001FE00010000010000010000010000010 -000010000011F000161C00180E001007001007800003800003800003C00003C00003C07003C0F0 -03C0F003C0E00380400380400700200600100E000C380003E000121F7E9D17>I<007C00018200 -0701000E03800C07801C0780380300380000780000700000700000F1F000F21C00F40600F80700 -F80380F80380F003C0F003C0F003C0F003C0F003C07003C07003C0700380380380380700180700 -0C0E00061C0001F000121F7E9D17>I<4000007FFFC07FFF807FFF804001008002008002008004 -0000080000080000100000200000200000400000400000C00000C00001C0000180000380000380 -00038000038000078000078000078000078000078000078000078000030000121F7D9D17>I<03 -F0000C0C001006003003002001806001806001806001807001807803003E03003F06001FC8000F -F00003F80007FC000C7E00103F00300F806003804001C0C001C0C000C0C000C0C000C0C0008060 -01802001001002000C0C0003F000121F7E9D17>I<03F0000E18001C0C00380600380700700700 -700380F00380F00380F003C0F003C0F003C0F003C0F003C07007C07007C03807C0180BC00E13C0 -03E3C0000380000380000380000700300700780600780E00700C002018001070000FC000121F7E -9D17>I<70F8F8F8700000000000000000000070F8F8F87005147C930D>I<70F8F8F87000000000 -00000000000070F0F8F878080808101010202040051D7C930D>I<000100000003800000038000 -000380000007C0000007C0000007C0000009E0000009E0000009E0000010F0000010F0000010F0 -0000207800002078000020780000403C0000403C0000403C0000801E0000801E0000FFFE000100 -0F0001000F0001000F00020007800200078002000780040003C00E0003C01F0007E0FFC03FFE1F -207F9F22>65 DI<000FC040007030C001C009C0038005C00700 -03C00E0001C01E0000C01C0000C03C0000C07C0000407C00004078000040F8000000F8000000F8 -000000F8000000F8000000F8000000F8000000F8000000F8000000780000007C0000407C000040 -3C0000401C0000401E0000800E000080070001000380020001C0040000703800000FC0001A217D -9F21>IIII<000FE0200078186000E004E0038002E0070001E00F0000E01E0000601E000060 -3C0000603C0000207C00002078000020F8000000F8000000F8000000F8000000F8000000F80000 -00F8000000F8007FFCF80003E0780001E07C0001E03C0001E03C0001E01E0001E01E0001E00F00 -01E0070001E0038002E000E0046000781820000FE0001E217D9F24>III<0FFFC0007C -00003C00003C00003C00003C00003C00003C00003C00003C00003C00003C00003C00003C00003C -00003C00003C00003C00003C00003C00003C00003C00003C00203C00F83C00F83C00F83C00F038 -0040780040700030E0000F800012207E9E17>I76 DII<001F800000F0F00001C0380007801E -000F000F000E0007001E0007803C0003C03C0003C07C0003E0780001E0780001E0F80001F0F800 -01F0F80001F0F80001F0F80001F0F80001F0F80001F0F80001F0F80001F0780001E07C0003E07C -0003E03C0003C03C0003C01E0007800E0007000F000F0007801E0001C0380000F0F000001F8000 -1C217D9F23>II<001F800000F0F00001C0380007801E000F00 -0F000E0007001E0007803C0003C03C0003C07C0003E07C0003E0780001E0F80001F0F80001F0F8 -0001F0F80001F0F80001F0F80001F0F80001F0F80001F0F80001F0780001E0780001E07C0003E0 -3C0003C03C0F03C01E1087800E2047000F204F0007A03E0001E0380000F0F010001FB010000030 -10000038300000387000003FF000001FE000001FE000000FC0000007801C297D9F23>II<07E0800C1980100780300380600180600180E00180E00080 -E00080E00080F00000F000007800007F00003FF0001FFC000FFE0003FF00001F800007800003C0 -0003C00001C08001C08001C08001C08001C0C00180C00380E00300F00600CE0C0081F80012217D -9F19>I<7FFFFFE0780F01E0600F0060400F0020400F0020C00F0030800F0010800F0010800F00 -10800F0010000F0000000F0000000F0000000F0000000F0000000F0000000F0000000F0000000F -0000000F0000000F0000000F0000000F0000000F0000000F0000000F0000000F0000000F000000 -0F0000001F800007FFFE001C1F7E9E21>IIII91 -D<080410082010201040204020804080408040B85CFC7EFC7E7C3E381C0F0E7B9F17>II<081020204040808080B8FCFC7C38060E7D9F0D>96 -D<1FE000303000781800781C00300E00000E00000E00000E0000FE00078E001E0E00380E00780E -00F00E10F00E10F00E10F01E10781E103867200F83C014147E9317>I<0E0000FE00000E00000E -00000E00000E00000E00000E00000E00000E00000E00000E00000E3E000EC3800F01C00F00E00E -00E00E00700E00700E00780E00780E00780E00780E00780E00780E00700E00700E00E00F00E00D -01C00CC300083E0015207F9F19>I<03F80E0C1C1E381E380C70007000F000F000F000F000F000 -F00070007000380138011C020E0C03F010147E9314>I<000380003F8000038000038000038000 -038000038000038000038000038000038000038003E380061B801C078038038038038070038070 -0380F00380F00380F00380F00380F00380F003807003807003803803803807801C07800E1B8003 -E3F815207E9F19>I<03F0000E1C001C0E00380700380700700700700380F00380F00380FFFF80 -F00000F00000F000007000007000003800801800800C010007060001F80011147F9314>I<007C -00C6018F038F07060700070007000700070007000700FFF0070007000700070007000700070007 -0007000700070007000700070007000700070007007FF01020809F0E>I<0000E003E3300E3C30 -1C1C30380E00780F00780F00780F00780F00780F00380E001C1C001E380033E000200000200000 -3000003000003FFE001FFF800FFFC03001E0600070C00030C00030C00030C000306000603000C0 -1C038003FC00141F7F9417>I<0E0000FE00000E00000E00000E00000E00000E00000E00000E00 -000E00000E00000E00000E3E000E43000E81800F01C00F01C00E01C00E01C00E01C00E01C00E01 -C00E01C00E01C00E01C00E01C00E01C00E01C00E01C00E01C00E01C0FFE7FC16207F9F19>I<1C -003E003E003E001C000000000000000000000000000E007E000E000E000E000E000E000E000E00 -0E000E000E000E000E000E000E000E000E000E00FFC00A1F809E0C>I<00E001F001F001F000E0 -000000000000000000000000007007F000F0007000700070007000700070007000700070007000 -7000700070007000700070007000700070007000706070F060F0C061803F000C28829E0E>I<0E -0000FE00000E00000E00000E00000E00000E00000E00000E00000E00000E00000E00000E0FF00E -03C00E03000E02000E04000E08000E10000E30000E70000EF8000F38000E1C000E1E000E0E000E -07000E07800E03800E03C00E03E0FFCFF815207F9F18>I<0E00FE000E000E000E000E000E000E -000E000E000E000E000E000E000E000E000E000E000E000E000E000E000E000E000E000E000E00 -0E000E000E000E00FFE00B20809F0C>I<0E1F01F000FE618618000E81C81C000F00F00E000F00 -F00E000E00E00E000E00E00E000E00E00E000E00E00E000E00E00E000E00E00E000E00E00E000E -00E00E000E00E00E000E00E00E000E00E00E000E00E00E000E00E00E000E00E00E00FFE7FE7FE0 -23147F9326>I<0E3E00FE43000E81800F01C00F01C00E01C00E01C00E01C00E01C00E01C00E01 -C00E01C00E01C00E01C00E01C00E01C00E01C00E01C00E01C0FFE7FC16147F9319>I<01F80007 -0E001C03803801C03801C07000E07000E0F000F0F000F0F000F0F000F0F000F0F000F07000E070 -00E03801C03801C01C0380070E0001F80014147F9317>I<0E3E00FEC3800F01C00F00E00E00E0 -0E00F00E00700E00780E00780E00780E00780E00780E00780E00700E00F00E00E00F01E00F01C0 -0EC3000E3E000E00000E00000E00000E00000E00000E00000E00000E0000FFE000151D7F9319> -I<03E0800619801C05803C0780380380780380700380F00380F00380F00380F00380F00380F003 -807003807803803803803807801C0B800E138003E3800003800003800003800003800003800003 -80000380000380003FF8151D7E9318>I<0E78FE8C0F1E0F1E0F0C0E000E000E000E000E000E00 -0E000E000E000E000E000E000E000E00FFE00F147F9312>I<1F9030704030C010C010C010E000 -78007F803FE00FF00070803880188018C018C018E030D0608F800D147E9312>I<020002000200 -060006000E000E003E00FFF80E000E000E000E000E000E000E000E000E000E000E000E080E080E -080E080E080610031001E00D1C7F9B12>I<0E01C0FE1FC00E01C00E01C00E01C00E01C00E01C0 -0E01C00E01C00E01C00E01C00E01C00E01C00E01C00E01C00E01C00E03C00603C0030DC001F1FC -16147F9319>III<7FC3FC0F01E00701C007018003810001C20000E40000EC00007800003800003C0000 -7C00004E000087000107000303800201C00601E01E01E0FF07FE1714809318>II<3FFF380E200E201C40384078407000E001E001C00380078007010E011E -011C0338027006700EFFFE10147F9314>I E /Fp 13 122 df<0000001FFC0000C000000003FF -FFC001C00000001FFFFFF003C00000007FFFFFFC07C0000001FFFC00FE0FC0000007FFC0001F9F -C000000FFE000007FFC000003FF8000003FFC000007FF0000000FFC00000FFE00000007FC00001 -FFC00000007FC00001FF800000003FC00003FF000000001FC00007FE000000001FC0000FFE0000 -00000FC0000FFC000000000FC0001FFC0000000007C0001FFC0000000007C0003FF80000000007 -C0003FF80000000003C0003FF80000000003C0007FF80000000003C0007FF80000000003C0007F -F0000000000000007FF000000000000000FFF000000000000000FFF000000000000000FFF00000 -0000000000FFF000000000000000FFF000000000000000FFF000000000000000FFF00000000000 -0000FFF000000000000000FFF000000000000000FFF000000000000000FFF000001FFFFFFF807F -F000001FFFFFFF807FF000001FFFFFFF807FF800001FFFFFFF807FF800000001FFC0003FF80000 -0001FFC0003FF800000001FFC0003FF800000001FFC0001FFC00000001FFC0001FFC00000001FF -C0000FFE00000001FFC0000FFE00000001FFC00007FF00000001FFC00003FF00000001FFC00001 -FF80000001FFC00001FFC0000001FFC00000FFE0000001FFC000007FF0000003FFC000003FFC00 -0003FFC000000FFF000007FFC0000007FFC0001FBFC0000001FFFC00FF1FC00000007FFFFFFE0F -C00000001FFFFFF803C000000003FFFFE000C0000000001FFE00000000413D7BBB4C>71 -DI76 D78 D85 D<003FFE00000001FFFFE0000007FFFFF800000FE0 -07FC00000FF001FE00001FF800FF00001FF8007F80001FF8007FC0001FF8003FC0000FF0003FE0 -0007E0003FE00003C0003FE0000000003FE0000000003FE0000000003FE0000000003FE0000000 -FFFFE000001FFFFFE000007FF83FE00003FF803FE00007FC003FE0000FF0003FE0001FE0003FE0 -003FE0003FE0007FC0003FE0007FC0003FE000FF80003FE000FF80003FE000FF80003FE000FF80 -003FE000FF80007FE0007FC0007FE0007FC000DFE0003FE0039FF0001FF80F0FFFE007FFFE0FFF -E001FFF807FFE0003FE000FFE02B267DA52F>97 D<00FE00000000FFFE00000000FFFE00000000 -FFFE00000000FFFE0000000007FE0000000003FE0000000003FE0000000003FE0000000003FE00 -00000003FE0000000003FE0000000003FE0000000003FE0000000003FE0000000003FE00000000 -03FE0000000003FE0000000003FE0000000003FE0000000003FE0000000003FE0000000003FE01 -FF000003FE1FFFF00003FE7FFFFC0003FEFC03FE0003FFF000FF0003FFC0003F8003FF00001FC0 -03FE00001FE003FE00000FF003FE00000FF803FE00000FF803FE000007FC03FE000007FC03FE00 -0007FC03FE000007FE03FE000007FE03FE000007FE03FE000007FE03FE000007FE03FE000007FE -03FE000007FE03FE000007FE03FE000007FE03FE000007FC03FE000007FC03FE000007FC03FE00 -000FFC03FE00000FF803FE00000FF003FE00001FF003FF00001FE003FF80003FC003FFC0007F80 -03F9E000FF0003F0FC07FE0003F07FFFF80003E01FFFE00003C003FE00002F3C7DBB36>I<01E0 -0007F8000FFC000FFC001FFE001FFE001FFE001FFE000FFC000FFC0007F80001E0000000000000 -0000000000000000000000000000000000000000000000000000000000FE00FFFE00FFFE00FFFE -00FFFE0007FE0003FE0003FE0003FE0003FE0003FE0003FE0003FE0003FE0003FE0003FE0003FE -0003FE0003FE0003FE0003FE0003FE0003FE0003FE0003FE0003FE0003FE0003FE0003FE0003FE -0003FE0003FE0003FE0003FE00FFFFF0FFFFF0FFFFF0FFFFF0143D7DBC1A>105 -D<0001FFC00000000FFFF80000007FFFFF000000FF80FF800003FE003FE00007F8000FF0000FF0 -0007F8000FF00007F8001FE00003FC003FE00003FE003FE00003FE007FC00001FF007FC00001FF -007FC00001FF007FC00001FF00FFC00001FF80FFC00001FF80FFC00001FF80FFC00001FF80FFC0 -0001FF80FFC00001FF80FFC00001FF80FFC00001FF80FFC00001FF807FC00001FF007FC00001FF -007FC00001FF003FE00003FE003FE00003FE001FE00003FC001FF00007FC000FF00007F80007F8 -000FF00003FE003FE00000FF80FF8000007FFFFF0000000FFFF800000001FFC0000029267DA530 ->111 D<01FC03F000FFFC0FFC00FFFC1FFF00FFFC3C3F80FFFC707F8007FCE0FFC003FCC0FFC0 -03FD80FFC003FD80FFC003FF807F8003FF003F0003FF001E0003FF00000003FE00000003FE0000 -0003FE00000003FE00000003FE00000003FE00000003FE00000003FE00000003FE00000003FE00 -000003FE00000003FE00000003FE00000003FE00000003FE00000003FE00000003FE00000003FE -00000003FE00000003FE00000003FE000000FFFFFC0000FFFFFC0000FFFFFC0000FFFFFC000022 -267DA528>114 D<003FF07003FFFEF007FFFFF01FC01FF03F0003F03E0001F07C0001F07C0000 -F0FC0000F0FC0000F0FE0000F0FF000000FFC00000FFFC00007FFFF0003FFFFE003FFFFF801FFF -FFC00FFFFFE003FFFFF000FFFFF8001FFFFC00007FFC000007FE700001FEF00000FEF000007EF8 -00007EF800007EFC00007EFC00007CFE0000FCFF0000F8FF8001F0FFF00FE0F9FFFFC0F07FFF00 -C01FF8001F267DA526>I<000F0000000F0000000F0000000F0000000F0000001F0000001F0000 -001F0000001F0000003F0000003F0000007F0000007F000000FF000001FF000003FF000007FF00 -001FFFFFF0FFFFFFF0FFFFFFF0FFFFFFF001FF000001FF000001FF000001FF000001FF000001FF -000001FF000001FF000001FF000001FF000001FF000001FF000001FF000001FF000001FF000001 -FF000001FF000001FF000001FF000001FF003C01FF003C01FF003C01FF003C01FF003C01FF003C -01FF003C01FF003C00FF007800FF8078007F80F0003FC1E0001FFFC0000FFF800001FE001E377E -B626>I121 -D E end -%%EndProlog -%%BeginSetup -%%Feature: *Resolution 300dpi -TeXDict begin - -%%EndSetup -%%Page: 1 1 -0 bop 0 1152 a Fp(GNU)33 b(History)f(Library)p 0 1201 1950 -17 v 1035 1250 a Fo(Edition)16 b(2.0,)e(for)h Fn(History)f(Library)g -Fo(V)l(ersion)i(2.0.)1759 1304 y(July)g(1994)0 2443 y Fm(Brian)23 -b(F)-6 b(o)n(x,)23 b(F)-6 b(ree)23 b(Soft)n(w)n(are)f(F)-6 -b(oundation)0 2509 y(Chet)22 b(Ramey)-6 b(,)23 b(Case)e(W)-6 -b(estern)23 b(Reserv)n(e)f(Univ)n(ersit)n(y)p 0 2545 1950 9 -v eop -%%Page: 2 2 -1 bop 0 295 a Fo(This)16 b(do)q(cumen)o(t)g(describ)q(es)h(the)f(GNU)f -(History)g(library)l(,)h(a)g(programming)e(to)q(ol)i(that)f(pro)o(vides)h(a)f -(consisten)o(t)0 358 y(user)g(in)o(terface)h(for)e(recalling)j(lines)g(of)e -(previously)h(t)o(yp)q(ed)g(input.)0 495 y(Published)h(b)o(y)f(the)f(F)l(ree) -g(Soft)o(w)o(are)f(F)l(oundation)0 557 y(675)g(Massac)o(h)o(usetts)g(Av)o(en) -o(ue,)0 619 y(Cam)o(bridge,)h(MA)g(02139)f(USA)0 756 y(P)o(ermission)f(is)g -(gran)o(ted)f(to)f(mak)o(e)h(and)h(distribute)h(v)o(erbatim)e(copies)h(of)f -(this)h(man)o(ual)g(pro)o(vided)g(the)f(cop)o(yrigh)o(t)0 818 -y(notice)k(and)f(this)h(p)q(ermission)h(notice)e(are)g(preserv)o(ed)h(on)f -(all)h(copies.)0 955 y(P)o(ermission)f(is)f(gran)o(ted)f(to)h(cop)o(y)g(and)g -(distribute)h(mo)q(di\014ed)h(v)o(ersions)e(of)f(this)i(man)o(ual)f(under)h -(the)f(conditions)0 1018 y(for)e(v)o(erbatim)g(cop)o(ying,)h(pro)o(vided)h -(that)d(the)i(en)o(tire)g(resulting)h(deriv)o(ed)f(w)o(ork)f(is)h -(distributed)h(under)f(the)g(terms)0 1080 y(of)i(a)g(p)q(ermission)h(notice)g -(iden)o(tical)h(to)e(this)g(one.)0 1217 y(P)o(ermission)20 -b(is)g(gran)o(ted)f(to)g(cop)o(y)h(and)f(distribute)i(translations)f(of)f -(this)h(man)o(ual)f(in)o(to)h(another)f(language,)0 1279 y(under)c(the)f(ab)q -(o)o(v)o(e)g(conditions)h(for)e(mo)q(di\014ed)j(v)o(ersions,)e(except)g(that) -g(this)g(p)q(ermission)i(notice)e(ma)o(y)g(b)q(e)h(stated)0 -1341 y(in)h(a)f(translation)g(appro)o(v)o(ed)g(b)o(y)g(the)g(F)l(oundation.)0 -2636 y(Cop)o(yrigh)o(t)226 2635 y(c)214 2636 y Fl(\015)g Fo(1989,)f(1991)g(F) -l(ree)h(Soft)o(w)o(are)f(F)l(oundation,)h(Inc.)p eop -%%Page: 1 3 -2 bop 0 -83 a Fo(Chapter)15 b(1:)k(Using)d(History)f(In)o(teractiv)o(ely)1157 -b(1)0 158 y Fk(1)41 b(Using)14 b(History)h(In)n(teractiv)n(ely)62 -330 y Fo(This)i(c)o(hapter)e(describ)q(es)j(ho)o(w)d(to)h(use)g(the)g(GNU)g -(History)f(Library)i(in)o(teractiv)o(ely)l(,)g(from)e(a)g(user's)h(stand-)0 -392 y(p)q(oin)o(t.)23 b(It)16 b(should)h(b)q(e)f(considered)i(a)d(user's)h -(guide.)23 b(F)l(or)15 b(information)h(on)g(using)h(the)f(GNU)g(History)f -(Library)0 454 y(in)h(y)o(our)f(o)o(wn)f(programs,)g(see)i(Chapter)e(2)h -([Programming)f(with)i(GNU)f(History],)f(page)h(5.)0 663 y -Fm(1.1)33 b(History)15 b(In)n(teraction)62 800 y Fo(The)j(History)g(library)g -(pro)o(vides)h(a)e(history)h(expansion)h(feature)e(that)g(is)i(similar)g(to)e -(the)h(history)f(expan-)0 862 y(sion)k(pro)o(vided)h(b)o(y)f -Fn(csh)p Fo(.)36 b(The)22 b(follo)o(wing)f(text)g(describ)q(es)h(the)f(syn)o -(tax)f(used)i(to)e(manipulate)i(the)f(history)0 924 y(information.)62 -1061 y(History)11 b(expansion)i(tak)o(es)d(place)i(in)h(t)o(w)o(o)d(parts.)18 -b(The)11 b(\014rst)g(is)h(to)f(determine)h(whic)o(h)g(line)h(from)e(the)g -(previous)0 1124 y(history)h(should)h(b)q(e)f(used)h(during)f(substitution.) -20 b(The)12 b(second)g(is)h(to)e(select)h(p)q(ortions)g(of)g(that)f(line)i -(for)f(inclusion)0 1186 y(in)o(to)f(the)h(curren)o(t)f(one.)18 -b(The)12 b(line)h(selected)f(from)f(the)g(previous)h(history)g(is)f(called)i -(the)e Fj(ev)o(en)o(t)p Fo(,)h(and)f(the)h(p)q(ortions)0 1248 -y(of)h(that)g(line)i(that)e(are)g(acted)g(up)q(on)h(are)g(called)h -Fj(w)o(ords)p Fo(.)j(The)c(line)h(is)f(brok)o(en)f(in)o(to)h(w)o(ords)f(in)h -(the)f(same)h(fashion)0 1310 y(that)j(Bash)h(do)q(es,)h(so)e(that)g(sev)o -(eral)h(English)i(\(or)d(Unix\))h(w)o(ords)f(surrounded)i(b)o(y)f(quotes)f -(are)h(considered)h(as)0 1373 y(one)c(w)o(ord.)0 1565 y Fi(1.1.1)30 -b(Ev)n(en)n(t)16 b(Designators)62 1702 y Fo(An)g(ev)o(en)o(t)f(designator)g -(is)g(a)g(reference)h(to)f(a)g(command)g(line)i(en)o(try)d(in)i(the)g -(history)f(list.)0 1847 y Fn(!)216 b Fo(Start)14 b(a)g(history)h -(substitution,)g(except)h(when)f(follo)o(w)o(ed)g(b)o(y)g(a)f(space,)h(tab,)f -(the)h(end)g(of)g(the)g(line,)240 1909 y Fn(=)g Fo(or)g Fn(\()p -Fo(.)0 1989 y Fn(!!)192 b Fo(Refer)16 b(to)e(the)i(previous)f(command.)20 -b(This)c(is)g(a)f(synon)o(ym)g(for)f Fn(!-1)p Fo(.)0 2068 y -Fn(!n)192 b Fo(Refer)16 b(to)e(command)h(line)i Fj(n)p Fo(.)0 -2148 y Fn(!-n)168 b Fo(Refer)16 b(to)e(the)i(command)f Fj(n)g -Fo(lines)i(bac)o(k.)0 2227 y Fn(!string)72 b Fo(Refer)16 b(to)e(the)i(most)e -(recen)o(t)h(command)g(starting)g(with)g Fj(string)p Fo(.)0 -2298 y Fn(!?string)p Fo([)p Fn(?)p Fo(])240 2360 y(Refer)h(to)e(the)i(most)e -(recen)o(t)h(command)g(con)o(taining)h Fj(string)p Fo(.)0 2440 -y Fn(!#)192 b Fo(The)15 b(en)o(tire)h(command)f(line)i(t)o(yp)q(ed)f(so)e -(far.)0 2510 y Fn(^string1^string2^)240 2573 y Fo(Quic)o(k)j(Substitution.)22 -b(Rep)q(eat)16 b(the)g(last)f(command,)h(replacing)h Fj(string1)h -Fo(with)e Fj(string2)p Fo(.)21 b(Equiv-)240 2635 y(alen)o(t)15 -b(to)g Fn(!!:s/string1/string2/)p Fo(.)p eop -%%Page: 2 4 -3 bop 0 -83 a Fo(2)1497 b(GNU)15 b(History)g(Library)0 158 -y Fi(1.1.2)30 b(W)-5 b(ord)15 b(Designators)62 295 y Fo(A)i -Fn(:)g Fo(separates)f(the)h(ev)o(en)o(t)f(sp)q(eci\014cation)j(from)d(the)g -(w)o(ord)g(designator.)25 b(It)17 b(can)g(b)q(e)g(omitted)g(if)g(the)g(w)o -(ord)0 358 y(designator)d(b)q(egins)h(with)f(a)f Fn(^)p Fo(,)h -Fn($)p Fo(,)f Fn(*)h Fo(or)f Fn(\045)p Fo(.)20 b(W)l(ords)13 -b(are)h(n)o(um)o(b)q(ered)g(from)f(the)h(b)q(eginning)i(of)d(the)h(line,)i -(with)e(the)0 420 y(\014rst)h(w)o(ord)f(b)q(eing)j(denoted)f(b)o(y)f(a)g(0)f -(\(zero\).)0 569 y Fn(0)h(\(zero\))57 b Fo(The)15 b Fn(0)p -Fo(th)g(w)o(ord.)20 b(F)l(or)14 b(man)o(y)h(applications,)h(this)g(is)g(the)f -(command)g(w)o(ord.)0 656 y Fn(n)216 b Fo(The)15 b Fj(n)p Fo(th)h(w)o(ord.)0 -744 y Fn(^)216 b Fo(The)15 b(\014rst)g(argumen)o(t;)f(that)h(is,)g(w)o(ord)g -(1.)0 831 y Fn($)216 b Fo(The)15 b(last)h(argumen)o(t.)0 918 -y Fn(\045)216 b Fo(The)15 b(w)o(ord)g(matc)o(hed)g(b)o(y)g(the)g(most)g -(recen)o(t)g Fn(?string?)f Fo(searc)o(h.)0 1005 y Fn(x-y)168 -b Fo(A)15 b(range)g(of)g(w)o(ords;)f Fn(-)p Fj(y)19 b Fo(abbreviates)c -Fn(0-)p Fj(y)t Fo(.)0 1092 y Fn(*)216 b Fo(All)17 b(of)f(the)g(w)o(ords,)f -(except)i(the)f Fn(0)p Fo(th.)22 b(This)17 b(is)f(a)g(synon)o(ym)g(for)f -Fn(1-$)p Fo(.)22 b(It)17 b(is)f(not)g(an)g(error)f(to)h(use)240 -1155 y Fn(*)f Fo(if)h(there)f(is)h(just)f(one)g(w)o(ord)f(in)i(the)g(ev)o(en) -o(t;)e(the)i(empt)o(y)e(string)i(is)f(returned)h(in)g(that)e(case.)0 -1242 y Fn(x*)192 b Fo(Abbreviates)16 b Fn(x-$)0 1329 y(x-)192 -b Fo(Abbreviates)16 b Fn(x-$)f Fo(lik)o(e)h Fn(x*)p Fo(,)e(but)i(omits)f(the) -g(last)g(w)o(ord.)0 1537 y Fi(1.1.3)30 b(Mo)r(di\014ers)62 -1674 y Fo(After)20 b(the)f(optional)i(w)o(ord)e(designator,)h(y)o(ou)f(can)h -(add)g(a)g(sequence)h(of)e(one)h(or)f(more)g(of)g(the)h(follo)o(wing)0 -1736 y(mo)q(di\014ers,)c(eac)o(h)f(preceded)i(b)o(y)e(a)g Fn(:)p -Fo(.)0 1885 y Fn(h)216 b Fo(Remo)o(v)o(e)15 b(a)g(trailing)h(pathname)f(comp) -q(onen)o(t,)g(lea)o(ving)h(only)g(the)f(head.)0 1973 y Fn(r)216 -b Fo(Remo)o(v)o(e)15 b(a)g(trailing)h(su\016x)f(of)g(the)g(form)g(`)p -Fn(.)p Fo(')p Fj(su\016x)p Fo(,)f(lea)o(ving)i(the)f(basename.)0 -2060 y Fn(e)216 b Fo(Remo)o(v)o(e)15 b(all)h(but)g(the)f(trailing)h(su\016x.) -0 2147 y Fn(t)216 b Fo(Remo)o(v)o(e)15 b(all)h(leading)h(pathname)e(comp)q -(onen)o(ts,)g(lea)o(ving)h(the)f(tail.)0 2234 y Fn(p)216 b -Fo(Prin)o(t)15 b(the)g(new)h(command)f(but)g(do)g(not)g(execute)h(it.)0 -2309 y Fn(s/old/new/)240 2371 y Fo(Substitute)g Fj(new)k Fo(for)15 -b(the)h(\014rst)f(o)q(ccurrence)h(of)g Fj(old)h Fo(in)g(the)e(ev)o(en)o(t)h -(line.)22 b(An)o(y)16 b(delimiter)h(ma)o(y)e(b)q(e)240 2433 -y(used)e(in)f(place)h(of)f Fn(/)p Fo(.)19 b(The)12 b(delimiter)i(ma)o(y)d(b)q -(e)i(quoted)f(in)h Fj(old)h Fo(and)e Fj(new)17 b Fo(with)12 -b(a)g(single)h(bac)o(kslash.)240 2496 y(If)g Fn(&)h Fo(app)q(ears)f(in)h -Fj(new)p Fo(,)f(it)h(is)g(replaced)g(b)o(y)f Fj(old)p Fo(.)20 -b(A)13 b(single)i(bac)o(kslash)e(will)i(quote)e(the)h Fn(&)p -Fo(.)19 b(The)13 b(\014nal)240 2558 y(delimiter)k(is)f(optional)g(if)f(it)h -(is)f(the)h(last)f(c)o(haracter)f(on)h(the)h(input)g(line.)0 -2645 y Fn(&)216 b Fo(Rep)q(eat)16 b(the)f(previous)h(substitution.)p -eop -%%Page: 3 5 -4 bop 0 -83 a Fo(Chapter)15 b(1:)k(Using)d(History)f(In)o(teractiv)o(ely)1157 -b(3)0 158 y Fn(g)216 b Fo(Cause)15 b(c)o(hanges)g(to)f(b)q(e)i(applied)h(o)o -(v)o(er)d(the)h(en)o(tire)g(ev)o(en)o(t)g(line.)21 b(Used)16 -b(in)g(conjunction)g(with)f Fn(s)p Fo(,)f(as)240 221 y(in)i -Fn(gs/old/new/)p Fo(,)d(or)i(with)h Fn(&)p Fo(.)p eop -%%Page: 4 6 -5 bop 0 -83 a Fo(4)1497 b(GNU)15 b(History)g(Library)p eop -%%Page: 5 7 -6 bop 0 -83 a Fo(Chapter)15 b(2:)k(Programming)c(with)g(GNU)g(History)1039 -b(5)0 158 y Fk(2)41 b(Programming)16 b(with)f(GNU)h(History)62 -347 y Fo(This)e(c)o(hapter)f(describ)q(es)i(ho)o(w)d(to)h(in)o(terface)g -(programs)f(that)h(y)o(ou)g(write)g(with)g(the)h(GNU)f(History)g(Library)l(.) -0 409 y(It)j(should)g(b)q(e)g(considered)h(a)f(tec)o(hnical)h(guide.)22 -b(F)l(or)15 b(information)h(on)f(the)h(in)o(teractiv)o(e)g(use)g(of)f(GNU)g -(History)l(,)0 471 y(see)g(Chapter)g(1)g([Using)h(History)f(In)o(teractiv)o -(ely],)g(page)g(1.)0 698 y Fm(2.1)33 b(In)n(tro)r(duction)17 -b(to)e(History)62 835 y Fo(Man)o(y)j(programs)g(read)h(input)h(from)e(the)g -(user)h(a)g(line)h(at)f(a)f(time.)31 b(The)19 b(GNU)g(History)f(library)i(is) -f(able)0 897 y(to)e(k)o(eep)g(trac)o(k)f(of)h(those)g(lines,)i(asso)q(ciate)e -(arbitrary)g(data)g(with)g(eac)o(h)g(line,)j(and)d(utilize)i(information)f -(from)0 960 y(previous)e(lines)h(in)f(comp)q(osing)f(new)h(ones.)62 -1097 y(The)i(programmer)f(using)h(the)g(History)g(library)g(has)g(a)o(v)m -(ailable)h(functions)g(for)e(remem)o(b)q(ering)h(lines)i(on)d(a)0 -1159 y(history)f(list,)g(asso)q(ciating)g(arbitrary)g(data)f(with)h(a)f -(line,)j(remo)o(ving)d(lines)j(from)d(the)h(list,)g(searc)o(hing)g(through)0 -1221 y(the)h(list)h(for)e(a)h(line)h(con)o(taining)g(an)f(arbitrary)f(text)h -(string,)g(and)g(referencing)h(an)o(y)f(line)h(in)g(the)f(list)h(directly)l -(.)0 1284 y(In)d(addition,)h(a)e(history)h Fj(expansion)h Fo(function)g(is)f -(a)o(v)m(ailable)h(whic)o(h)g(pro)o(vides)f(for)f(a)h(consisten)o(t)g(user)g -(in)o(terface)0 1346 y(across)f(di\013eren)o(t)i(programs.)62 -1483 y(The)i(user)g(using)g(programs)f(written)g(with)h(the)g(History)f -(library)i(has)e(the)h(b)q(ene\014t)h(of)e(a)g(consisten)o(t)h(user)0 -1545 y(in)o(terface)d(with)g(a)f(set)h(of)f(w)o(ell-kno)o(wn)h(commands)g -(for)f(manipulating)i(the)f(text)f(of)g(previous)h(lines)h(and)f(using)0 -1608 y(that)g(text)g(in)i(new)e(commands.)22 b(The)15 b(basic)i(history)e -(manipulation)j(commands)d(are)g(similar)i(to)e(the)h(history)0 -1670 y(substitution)g(pro)o(vided)g(b)o(y)f Fn(csh)p Fo(.)62 -1807 y(If)g(the)g(programmer)e(desires,)i(he)g(can)g(use)g(the)f(Readline)j -(library)l(,)e(whic)o(h)h(includes)g(some)f(history)f(manip-)0 -1870 y(ulation)i(b)o(y)f(default,)h(and)f(has)g(the)g(added)h(adv)m(an)o -(tage)f(of)g(command)g(line)h(editing.)0 2096 y Fm(2.2)33 b(History)15 -b(Storage)62 2234 y Fo(The)h(history)f(list)h(is)g(an)f(arra)o(y)f(of)g -(history)i(en)o(tries.)k(A)15 b(history)g(en)o(try)g(is)h(declared)g(as)f -(follo)o(ws:)120 2358 y Fn(typedef)23 b(struct)g(_hist_entry)f({)168 -2408 y(char)h(*line;)168 2458 y(char)g(*data;)120 2508 y(})h(HIST_ENTRY;)62 -2645 y Fo(The)16 b(history)f(list)h(itself)g(migh)o(t)f(therefore)g(b)q(e)h -(declared)g(as)p eop -%%Page: 6 8 -7 bop 0 -83 a Fo(6)1497 b(GNU)15 b(History)g(Library)120 158 -y Fn(HIST_ENTRY)22 b(**the_history_list;)62 302 y Fo(The)16 -b(state)e(of)h(the)g(History)g(library)h(is)g(encapsulated)g(in)o(to)f(a)g -(single)i(structure:)120 434 y Fn(/*)24 b(A)f(structure)g(used)g(to)h(pass)f -(the)h(current)f(state)g(of)g(the)h(history)f(stuff)g(around.)g(*/)120 -484 y(typedef)g(struct)g(_hist_state)f({)168 534 y(HIST_ENTRY)g(**entries;) -214 b(/*)23 b(Pointer)g(to)h(the)f(entries)g(themselves.)f(*/)168 -584 y(int)h(offset;)453 b(/*)23 b(The)h(location)e(pointer)h(within)g(this)h -(array.)f(*/)168 633 y(int)g(length;)453 b(/*)23 b(Number)g(of)h(elements)f -(within)g(this)g(array.)g(*/)168 683 y(int)g(size;)501 b(/*)23 -b(Number)g(of)h(slots)f(allocated)g(to)g(this)h(array.)f(*/)168 -733 y(int)g(flags;)120 783 y(})h(HISTORY_STATE;)62 927 y Fo(If)16 -b(the)f(\015ags)g(mem)o(b)q(er)g(includes)j Fn(HS_STIFLED)p -Fo(,)13 b(the)i(history)h(has)f(b)q(een)h(sti\015ed.)0 1215 -y Fm(2.3)33 b(History)15 b(F)-6 b(unctions)62 1359 y Fo(This)16 -b(section)g(describ)q(es)h(the)e(calling)i(sequence)f(for)f(the)g(v)m(arious) -h(functions)g(presen)o(t)f(in)h(GNU)f(History)l(.)0 1631 y -Fi(2.3.1)30 b(Initializing)15 b(History)g(and)g(State)g(Managemen)n(t)62 -1775 y Fo(This)j(section)g(describ)q(es)h(functions)f(used)g(to)e(initialize) -21 b(and)c(manage)g(the)g(state)g(of)g(the)g(History)g(library)0 -1837 y(when)f(y)o(ou)f(w)o(an)o(t)f(to)g(use)i(the)f(history)g(functions)h -(in)g(y)o(our)f(program.)1725 2021 y(F)l(unction)-1899 b Fh(void)20 -b Fg(using)p 258 2021 18 3 v 20 w(history)j Ff(\(\))120 2083 -y Fo(Begin)g(a)f(session)g(in)h(whic)o(h)g(the)f(history)g(functions)g(migh)o -(t)g(b)q(e)h(used.)40 b(This)23 b(initializes)i(the)120 2145 -y(in)o(teractiv)o(e)16 b(v)m(ariables.)1725 2328 y(F)l(unction)-1899 -b Fh(HISTORY_STATE)21 b(*)e Fg(history)p 582 2328 V 21 w(get)p -680 2328 V 21 w(history)p 876 2328 V 21 w(state)j Ff(\(\))120 -2391 y Fo(Return)16 b(a)f(structure)g(describing)i(the)e(curren)o(t)g(state)f -(of)h(the)g(input)i(history)l(.)1725 2574 y(F)l(unction)-1899 -b Fh(void)20 b Fg(history)p 302 2574 V 20 w(set)p 393 2574 -V 21 w(history)p 589 2574 V 21 w(state)j Ff(\()p Fn(HISTORY_STATE)13 -b(*state)p Ff(\))120 2636 y Fo(Set)i(the)h(state)e(of)h(the)g(history)g(list) -h(according)g(to)e Fj(state)p Fo(.)p eop -%%Page: 7 9 -8 bop 0 -83 a Fo(Chapter)15 b(2:)k(Programming)c(with)g(GNU)g(History)1039 -b(7)0 158 y Fi(2.3.2)30 b(History)15 b(List)g(Managemen)n(t)62 -295 y Fo(These)i(functions)h(manage)e(individual)k(en)o(tries)d(on)f(the)h -(history)g(list,)g(or)f(set)h(parameters)e(managing)i(the)0 -358 y(list)f(itself.)1725 520 y(F)l(unction)-1899 b Fh(void)20 -b Fg(add)p 219 520 18 3 v 20 w(history)j Ff(\()p Fn(char)14 -b(*string)p Ff(\))120 582 y Fo(Place)j Fj(string)k Fo(at)16 -b(the)g(end)i(of)e(the)g(history)h(list.)25 b(The)17 b(asso)q(ciated)g(data)f -(\014eld)h(\(if)g(an)o(y\))f(is)h(set)g(to)120 644 y Fn(NULL)p -Fo(.)1725 806 y(F)l(unction)-1899 b Fh(HIST_ENTRY)21 b(*)e -Fg(remo)n(v)n(e)p 509 806 V 20 w(history)k Ff(\()p Fn(int)14 -b(which)p Ff(\))120 868 y Fo(Remo)o(v)o(e)d(history)g(en)o(try)g(at)g -(o\013set)f Fj(whic)o(h)i Fo(from)f(the)g(history)l(.)19 b(The)11 -b(remo)o(v)o(ed)g(elemen)o(t)h(is)g(returned)120 930 y(so)j(y)o(ou)g(can)g -(free)g(the)h(line,)g(data,)e(and)i(con)o(taining)g(structure.)1725 -1092 y(F)l(unction)-1899 b Fh(HIST_ENTRY)21 b(*)e Fg(replace)p -505 1092 V 22 w(history)p 702 1092 V 20 w(en)n(try)24 b Ff(\()p -Fn(int)14 b(which,)g(char)h(*line,)f(char)208 1155 y(*data)p -Ff(\))120 1217 y Fo(Mak)o(e)d(the)i(history)f(en)o(try)g(at)f(o\013set)h -Fj(whic)o(h)h Fo(ha)o(v)o(e)e Fj(line)17 b Fo(and)12 b Fj(data)p -Fo(.)19 b(This)12 b(returns)g(the)h(old)g(en)o(try)e(so)120 -1279 y(y)o(ou)i(can)g(disp)q(ose)h(of)e(the)h(data.)19 b(In)13 -b(the)g(case)g(of)f(an)h(in)o(v)m(alid)i Fj(whic)o(h)p Fo(,)f(a)f -Fn(NULL)f Fo(p)q(oin)o(ter)i(is)f(returned.)1725 1441 y(F)l(unction)-1899 -b Fh(void)20 b Fg(sti\015e)p 245 1441 V 21 w(history)j Ff(\()p -Fn(int)14 b(max)p Ff(\))120 1503 y Fo(Sti\015e)i(the)f(history)h(list,)f -(remem)o(b)q(ering)h(only)g(the)f(last)g Fj(max)j Fo(en)o(tries.)1725 -1665 y(F)l(unction)-1899 b Fh(int)20 b Fg(unsti\015e)p 283 -1665 V 21 w(history)i Ff(\(\))120 1728 y Fo(Stop)13 b(sti\015ing)h(the)f -(history)l(.)19 b(This)14 b(returns)f(the)g(previous)h(amoun)o(t)e(the)h -(history)g(w)o(as)g(sti\015ed.)20 b(The)120 1790 y(v)m(alue)c(is)g(p)q -(ositiv)o(e)g(if)g(the)f(history)g(w)o(as)g(sti\015ed,)h(negativ)o(e)f(if)g -(it)h(w)o(asn't.)1725 1952 y(F)l(unction)-1899 b Fh(int)20 -b Fg(history)p 276 1952 V 20 w(is)p 334 1952 V 21 w(sti\015ed)k -Ff(\(\))120 2014 y Fo(Returns)16 b(non-zero)f(if)h(the)f(history)g(is)h -(sti\015ed,)g(zero)f(if)g(it)h(is)g(not.)0 2222 y Fi(2.3.3)30 -b(Information)14 b(Ab)r(out)h(the)g(History)g(List)62 2359 -y Fo(These)h(functions)g(return)f(information)g(ab)q(out)g(the)h(en)o(tire)f -(history)g(list)h(or)f(individual)j(list)f(en)o(tries.)1725 -2521 y(F)l(unction)-1899 b Fh(HIST_ENTRY)21 b(**)e Fg(history)p -530 2521 V 21 w(list)24 b Ff(\(\))120 2583 y Fo(Return)e(a)e -Fn(NULL)h Fo(terminated)g(arra)o(y)f(of)g Fn(HIST_ENTRY)g Fo(whic)o(h)i(is)f -(the)g(curren)o(t)g(input)h(history)l(.)120 2645 y(Elemen)o(t)16 -b(0)f(of)f(this)i(list)g(is)g(the)f(b)q(eginning)i(of)e(time.)20 -b(If)c(there)f(is)h(no)f(history)l(,)g(return)g Fn(NULL)p Fo(.)p -eop -%%Page: 8 10 -9 bop 0 -83 a Fo(8)1497 b(GNU)15 b(History)g(Library)1725 158 -y(F)l(unction)-1899 b Fh(int)20 b Fg(where)p 250 158 18 3 v -20 w(history)j Ff(\(\))120 221 y Fo(Returns)16 b(the)f(o\013set)f(of)h(the)g -(curren)o(t)g(history)g(elemen)o(t.)1725 378 y(F)l(unction)-1899 -b Fh(HIST_ENTRY)21 b(*)e Fg(curren)n(t)p 512 378 V 21 w(history)k -Ff(\(\))120 440 y Fo(Return)14 b(the)g(history)g(en)o(try)f(at)h(the)g -(curren)o(t)f(p)q(osition,)i(as)e(determined)j(b)o(y)d Fn(where_history)h -(\(\))p Fo(.)120 502 y(If)h(there)h(is)f(no)h(en)o(try)e(there,)h(return)g(a) -g Fn(NULL)g Fo(p)q(oin)o(ter.)1725 660 y(F)l(unction)-1899 -b Fh(HIST_ENTRY)21 b(*)e Fg(history)p 504 660 V 21 w(get)j -Ff(\()p Fn(int)15 b(offset)p Ff(\))120 722 y Fo(Return)g(the)g(history)f(en)o -(try)g(at)g(p)q(osition)i Fj(o\013set)p Fo(,)d(starting)h(from)g -Fn(history_base)p Fo(.)k(If)c(there)h(is)g(no)120 784 y(en)o(try)g(there,)g -(or)f(if)i Fj(o\013set)f Fo(is)h(greater)e(than)h(the)h(history)f(length,)g -(return)g(a)g Fn(NULL)g Fo(p)q(oin)o(ter.)1725 942 y(F)l(unction)-1899 -b Fh(int)20 b Fg(history)p 276 942 V 20 w(total)p 412 942 V -22 w(b)n(ytes)j Ff(\(\))120 1004 y Fo(Return)17 b(the)f(n)o(um)o(b)q(er)g(of) -g(b)o(ytes)g(that)f(the)h(primary)g(history)g(en)o(tries)h(are)e(using.)23 -b(This)17 b(function)120 1066 y(returns)e(the)g(sum)h(of)e(the)i(lengths)f -(of)g(all)h(the)g(lines)g(in)g(the)g(history)l(.)0 1265 y Fi(2.3.4)30 -b(Mo)n(ving)15 b(Around)h(the)f(History)g(List)62 1402 y Fo(These)h -(functions)g(allo)o(w)f(the)g(curren)o(t)h(index)g(in)o(to)f(the)h(history)f -(list)h(to)e(b)q(e)i(set)f(or)g(c)o(hanged.)1725 1559 y(F)l(unction)-1899 -b Fh(int)20 b Fg(history)p 276 1559 V 20 w(set)p 367 1559 V -21 w(p)r(os)h Ff(\()p Fn(int)15 b(pos)p Ff(\))120 1621 y Fo(Set)g(the)h(p)q -(osition)g(in)g(the)f(history)g(list)h(to)f Fj(p)q(os)p Fo(,)g(an)g(absolute) -g(index)i(in)o(to)e(the)g(list.)1725 1779 y(F)l(unction)-1899 -b Fh(HIST_ENTRY)21 b(*)e Fg(previous)p 540 1779 V 20 w(history)k -Ff(\(\))120 1841 y Fo(Bac)o(k)16 b(up)h(the)g(curren)o(t)f(history)h -(o\013set)e(to)h(the)h(previous)g(history)g(en)o(try)l(,)f(and)h(return)f(a)g -(p)q(oin)o(ter)120 1903 y(to)f(that)f(en)o(try)l(.)20 b(If)15 -b(there)g(is)h(no)f(previous)h(en)o(try)l(,)f(return)g(a)g -Fn(NULL)g Fo(p)q(oin)o(ter.)1725 2061 y(F)l(unction)-1899 b -Fh(HIST_ENTRY)21 b(*)e Fg(next)p 439 2061 V 21 w(history)k -Ff(\(\))120 2123 y Fo(Mo)o(v)o(e)c(the)h(curren)o(t)g(history)f(o\013set)g -(forw)o(ard)g(to)g(the)h(next)g(history)g(en)o(try)l(,)g(and)g(return)g(the)g -(a)120 2185 y(p)q(oin)o(ter)c(to)e(that)h(en)o(try)l(.)k(If)d(there)f(is)h -(no)f(next)g(en)o(try)l(,)g(return)g(a)g Fn(NULL)g Fo(p)q(oin)o(ter.)0 -2384 y Fi(2.3.5)30 b(Searc)n(hing)15 b(the)h(History)f(List)62 -2521 y Fo(These)e(functions)g(allo)o(w)f(searc)o(hing)h(of)f(the)g(history)g -(list)h(for)f(en)o(tries)h(con)o(taining)g(a)f(sp)q(eci\014c)i(string.)19 -b(Searc)o(h-)0 2583 y(ing)e(ma)o(y)g(b)q(e)g(p)q(erformed)g(b)q(oth)g(forw)o -(ard)f(and)h(bac)o(kw)o(ard)f(from)g(the)h(curren)o(t)f(history)h(p)q -(osition.)26 b(The)17 b(searc)o(h)0 2645 y(ma)o(y)d(b)q(e)i -Fj(anc)o(hored)p Fo(,)f(meaning)h(that)f(the)g(string)g(m)o(ust)g(matc)o(h)f -(at)h(the)g(b)q(eginning)i(of)e(the)h(history)f(en)o(try)l(.)p -eop -%%Page: 9 11 -10 bop 0 -83 a Fo(Chapter)15 b(2:)k(Programming)c(with)g(GNU)g(History)1039 -b(9)1725 158 y(F)l(unction)-1899 b Fh(int)20 b Fg(history)p -276 158 18 3 v 20 w(searc)n(h)j Ff(\()p Fn(char)14 b(*string,)g(int)h -(direction)p Ff(\))120 221 y Fo(Searc)o(h)k(the)g(history)g(for)f -Fj(string)p Fo(,)i(starting)e(at)g(the)h(curren)o(t)g(history)g(o\013set.)30 -b(If)19 b Fj(direction)h Fn(<)f Fo(0,)120 283 y(then)14 b(the)f(searc)o(h)g -(is)h(through)e(previous)i(en)o(tries,)g(else)g(through)f(subsequen)o(t.)20 -b(If)13 b Fj(string)k Fo(is)d(found,)120 345 y(then)f(the)g(curren)o(t)g -(history)g(index)i(is)e(set)g(to)f(that)h(history)g(en)o(try)l(,)f(and)i(the) -f(v)m(alue)h(returned)f(is)h(the)120 407 y(o\013set)h(in)i(the)f(line)i(of)d -(the)h(en)o(try)g(where)g Fj(string)k Fo(w)o(as)c(found.)22 -b(Otherwise,)17 b(nothing)f(is)h(c)o(hanged,)120 470 y(and)e(a)g(-1)g(is)h -(returned.)1725 659 y(F)l(unction)-1899 b Fh(int)20 b Fg(history)p -276 659 V 20 w(searc)n(h)p 452 659 V 21 w(pre\014x)i Ff(\()p -Fn(char)15 b(*string,)f(int)g(direction)p Ff(\))120 721 y Fo(Searc)o(h)22 -b(the)h(history)f(for)f Fj(string)p Fo(,)j(starting)e(at)f(the)i(curren)o(t)f -(history)g(o\013set.)40 b(The)22 b(searc)o(h)g(is)120 783 y(anc)o(hored:)i -(matc)o(hing)18 b(lines)h(m)o(ust)d(b)q(egin)j(with)f Fj(string)p -Fo(.)26 b(If)17 b Fj(direction)i Fn(<)e Fo(0,)g(then)h(the)f(searc)o(h)g(is) -120 845 y(through)e(previous)h(en)o(tries,)f(else)i(through)d(subsequen)o(t.) -21 b(If)16 b Fj(string)j Fo(is)d(found,)f(then)h(the)f(curren)o(t)120 -908 y(history)20 b(index)i(is)e(set)g(to)g(that)f(en)o(try)l(,)i(and)f(the)g -(return)h(v)m(alue)g(is)g(0.)34 b(Otherwise,)22 b(nothing)e(is)120 -970 y(c)o(hanged,)15 b(and)h(a)e(-1)h(is)h(returned.)1725 1159 -y(F)l(unction)-1899 b Fh(int)20 b Fg(history)p 276 1159 V 20 -w(searc)n(h)p 452 1159 V 21 w(p)r(os)h Ff(\()p Fn(char)15 b(*string,)f(int)g -(direction,)g(int)h(pos)p Ff(\))120 1221 y Fo(Searc)o(h)d(for)f -Fj(string)k Fo(in)d(the)g(history)f(list,)i(starting)e(at)g -Fj(p)q(os)p Fo(,)h(an)f(absolute)h(index)h(in)o(to)e(the)h(list.)19 -b(If)12 b Fj(di-)120 1283 y(rection)g Fo(is)h(negativ)o(e,)f(the)g(searc)o(h) -g(pro)q(ceeds)h(bac)o(kw)o(ard)e(from)g Fj(p)q(os)p Fo(,)i(otherwise)f(forw)o -(ard.)17 b(Returns)120 1345 y(the)e(absolute)h(index)g(of)f(the)g(history)h -(elemen)o(t)f(where)h Fj(string)j Fo(w)o(as)14 b(found,)h(or)g(-1)g -(otherwise.)0 1634 y Fi(2.3.6)30 b(Managing)14 b(the)i(History)f(File)62 -1780 y Fo(The)f(History)g(library)h(can)f(read)g(the)g(history)g(from)f(and)i -(write)f(it)g(to)f(a)h(\014le.)20 b(This)15 b(section)g(do)q(cumen)o(ts)f -(the)0 1842 y(functions)i(for)f(managing)g(a)f(history)i(\014le.)1725 -2031 y(F)l(unction)-1899 b Fh(int)20 b Fg(read)p 211 2031 V -20 w(history)i Ff(\()p Fn(char)15 b(*filename)p Ff(\))120 2093 -y Fo(Add)i(the)f(con)o(ten)o(ts)g(of)g Fj(\014lename)k Fo(to)c(the)h(history) -f(list,)h(a)f(line)i(at)e(a)g(time.)24 b(If)17 b Fj(\014lename)j -Fo(is)d Fn(NULL)p Fo(,)120 2155 y(then)f(read)f(from)f(`)p -Fn(~/.history)p Fo('.)k(Returns)e(0)e(if)i(successful,)g(or)f(errno)g(if)h -(not.)1725 2344 y(F)l(unction)-1899 b Fh(int)20 b Fg(read)p -211 2344 V 20 w(history)p 406 2344 V 20 w(range)i Ff(\()p Fn(char)15 -b(*filename,)e(int)i(from,)g(int)f(to)p Ff(\))120 2407 y Fo(Read)j(a)e(range) -h(of)f(lines)j(from)d Fj(\014lename)p Fo(,)i(adding)f(them)g(to)f(the)h -(history)g(list.)23 b(Start)15 b(reading)i(at)120 2469 y(line)f -Fj(from)f Fo(and)g(end)g(at)f Fj(to)p Fo(.)19 b(If)d Fj(from)e -Fo(is)h(zero,)f(start)g(at)g(the)h(b)q(eginning.)22 b(If)15 -b Fj(to)i Fo(is)e(less)g(than)g Fj(from)p Fo(,)120 2531 y(then)i(read)g(un)o -(til)h(the)f(end)g(of)g(the)g(\014le.)25 b(If)17 b Fj(\014lename)k -Fo(is)c Fn(NULL)p Fo(,)f(then)i(read)e(from)g(`)p Fn(~/.history)p -Fo('.)120 2593 y(Returns)g(0)f(if)g(successful,)h(or)f Fn(errno)g -Fo(if)g(not.)p eop -%%Page: 10 12 -11 bop 0 -83 a Fo(10)1474 b(GNU)15 b(History)g(Library)1725 -158 y(F)l(unction)-1899 b Fh(int)20 b Fg(write)p 229 158 18 -3 v 22 w(history)i Ff(\()p Fn(char)15 b(*filename)p Ff(\))120 -221 y Fo(W)l(rite)20 b(the)g(curren)o(t)f(history)h(to)f Fj(\014lename)p -Fo(,)i(o)o(v)o(erwriting)f Fj(\014lename)j Fo(if)d(necessary)l(.)34 -b(If)20 b Fj(\014lename)120 283 y Fo(is)d Fn(NULL)p Fo(,)g(then)g(write)g -(the)g(history)g(list)h(to)e(`)p Fn(~/.history)p Fo('.)23 b(V)l(alues)18 -b(returned)g(are)e(as)h(in)h Fn(read_)120 345 y(history)c(\(\))p -Fo(.)1725 504 y(F)l(unction)-1899 b Fh(int)20 b Fg(app)r(end)p -285 504 V 19 w(history)j Ff(\()p Fn(int)14 b(nelements,)g(char)h(*filename)p -Ff(\))120 566 y Fo(App)q(end)i(the)e(last)g Fj(nelemen)o(ts)j -Fo(of)d(the)g(history)g(list)h(to)f Fj(\014lename)p Fo(.)1725 -724 y(F)l(unction)-1899 b Fh(int)20 b Fg(history)p 276 724 -V 20 w(truncate)p 507 724 V 21 w(\014le)k Ff(\()p Fn(char)14 -b(*filename,)g(int)h(nlines)p Ff(\))120 787 y Fo(T)l(runcate)g(the)h(history) -f(\014le)h Fj(\014lename)p Fo(,)g(lea)o(ving)g(only)g(the)f(last)g -Fj(nlines)k Fo(lines.)0 988 y Fi(2.3.7)30 b(History)15 b(Expansion)62 -1125 y Fo(These)h(functions)g(implemen)o(t)g Fn(csh)p Fo(-lik)o(e)g(history)g -(expansion.)1725 1283 y(F)l(unction)-1899 b Fh(int)20 b Fg(history)p -276 1283 V 20 w(expand)j Ff(\()p Fn(char)14 b(*string,)g(char)h(**output)p -Ff(\))120 1345 y Fo(Expand)20 b Fj(string)p Fo(,)f(placing)i(the)e(result)h -(in)o(to)f Fj(output)p Fo(,)h(a)f(p)q(oin)o(ter)h(to)e(a)h(string)h(\(see)f -(Section)h(1.1)120 1408 y([History)15 b(In)o(teraction],)f(page)h(1\).)20 -b(Returns:)120 1555 y Fn(0)216 b Fo(If)21 b(no)g(expansions)h(to)q(ok)e -(place)h(\(or,)g(if)h(the)f(only)g(c)o(hange)g(in)h(the)f(text)f(w)o(as)g -(the)360 1618 y(de-slashifying)d(of)e(the)g(history)h(expansion)g(c)o -(haracter\);)120 1701 y Fn(1)216 b Fo(if)16 b(expansions)g(did)g(tak)o(e)e -(place;)120 1785 y Fn(-1)192 b Fo(if)16 b(there)f(w)o(as)f(an)h(error)g(in)h -(expansion;)120 1869 y Fn(2)216 b Fo(if)14 b(the)f(returned)h(line)h(should)f -(only)g(b)q(e)f(displa)o(y)o(ed,)i(but)e(not)g(executed,)h(as)f(with)h(the) -360 1931 y Fn(:p)h Fo(mo)q(di\014er)h(\(see)f(Section)h(1.1.3)e([Mo)q -(di\014ers],)h(page)g(2\).)120 2079 y(If)g(an)h(error)e(o)q(curred)i(in)g -(expansion,)f(then)h Fj(output)g Fo(con)o(tains)f(a)g(descriptiv)o(e)i(error) -d(message.)1725 2238 y(F)l(unction)-1899 b Fh(char)20 b(*)f -Fg(history)p 347 2238 V 21 w(arg)p 449 2238 V 19 w(extract)24 -b Ff(\()p Fn(int)14 b(first,)h(int)g(last,)f(char)h(*string)p -Ff(\))120 2300 y Fo(Extract)10 b(a)h(string)g(segmen)o(t)g(consisting)h(of)f -(the)g Fj(\014rst)h Fo(through)f Fj(last)h Fo(argumen)o(ts)e(presen)o(t)h(in) -h Fj(string)p Fo(.)120 2362 y(Argumen)o(ts)j(are)g(brok)o(en)g(up)g(as)g(in)h -(Bash.)1725 2521 y(F)l(unction)-1899 b Fh(char)20 b(*)f Fg(get)p -249 2521 V 21 w(history)p 445 2521 V 20 w(ev)n(en)n(t)25 b -Ff(\()p Fn(char)14 b(*string,)g(int)h(*cindex,)f(int)h(qchar)p -Ff(\))120 2583 y Fo(Returns)e(the)f(text)f(of)h(the)g(history)g(ev)o(en)o(t)f -(b)q(eginning)k(at)c Fj(string)16 b Fn(+)c Fj(*cindex)p Fo(.)20 -b Fj(*cindex)c Fo(is)d(mo)q(di\014ed)120 2645 y(to)h(p)q(oin)o(t)h(to)f -(after)h(the)f(ev)o(en)o(t)h(sp)q(eci\014er.)21 b(A)o(t)15 -b(function)g(en)o(try)l(,)f Fj(cindex)20 b Fo(p)q(oin)o(ts)15 -b(to)f(the)h(index)h(in)o(to)p eop -%%Page: 11 13 -12 bop 0 -83 a Fo(Chapter)15 b(2:)k(Programming)c(with)g(GNU)g(History)1017 -b(11)120 158 y Fj(string)17 b Fo(where)d(the)f(history)h(ev)o(en)o(t)f(sp)q -(eci\014cation)i(b)q(egins.)20 b Fj(qc)o(har)d Fo(is)c(a)g(c)o(haracter)g -(that)g(is)h(allo)o(w)o(ed)120 221 y(to)h(end)g(the)h(ev)o(en)o(t)f(sp)q -(eci\014cation)i(in)f(addition)g(to)f(the)g(\\normal")g(terminating)g(c)o -(haracters.)1725 394 y(F)l(unction)-1899 b Fh(char)20 b(**)f -Fg(history)p 373 394 18 3 v 21 w(tok)n(enize)25 b Ff(\()p Fn(char)14 -b(*string)p Ff(\))120 456 y Fo(Return)k(an)f(arra)o(y)f(of)h(tok)o(ens)f -(parsed)i(out)e(of)h Fj(string)p Fo(,)g(m)o(uc)o(h)h(as)e(the)i(shell)g(migh) -o(t.)26 b(The)17 b(tok)o(ens)120 519 y(are)c(split)h(on)f(white)g(space)h -(and)f(on)g(the)g(c)o(haracters)f Fn(\(\)<>;&|$)p Fo(,)g(and)h(shell)i -(quoting)e(con)o(v)o(en)o(tions)120 581 y(are)i(ob)q(ey)o(ed.)0 -840 y Fm(2.4)33 b(History)15 b(V)-6 b(ariables)62 981 y Fo(This)16 -b(section)g(describ)q(es)h(the)e(externally)h(visible)i(v)m(ariables)e(exp)q -(orted)g(b)o(y)f(the)g(GNU)g(History)g(Library)l(.)1736 1155 -y(V)l(ariable)-1899 b Fh(int)20 b Fg(history)p 276 1155 V 20 -w(base)120 1217 y Fo(The)15 b(logical)i(o\013set)d(of)h(the)g(\014rst)g(en)o -(try)g(in)h(the)f(history)g(list.)1736 1390 y(V)l(ariable)-1899 -b Fh(int)20 b Fg(history)p 276 1390 V 20 w(length)120 1453 -y Fo(The)15 b(n)o(um)o(b)q(er)h(of)f(en)o(tries)g(curren)o(tly)h(stored)f(in) -h(the)f(history)g(list.)1736 1626 y(V)l(ariable)-1899 b Fh(int)20 -b Fg(max)p 208 1626 V 19 w(input)p 360 1626 V 21 w(history)120 -1689 y Fo(The)12 b(maxim)o(um)g(n)o(um)o(b)q(er)g(of)f(history)h(en)o(tries.) -19 b(This)12 b(m)o(ust)f(b)q(e)h(c)o(hanged)g(using)h Fn(stifle_history)120 -1751 y(\(\))p Fo(.)1736 1924 y(V)l(ariable)-1899 b Fh(char)20 -b Fg(history)p 302 1924 V 20 w(expansion)p 569 1924 V 21 w(c)n(har)120 -1987 y Fo(The)15 b(c)o(haracter)g(that)f(starts)g(a)h(history)g(ev)o(en)o(t.) -20 b(The)15 b(default)h(is)g(`)p Fn(!)p Fo('.)1736 2160 y(V)l(ariable)-1899 -b Fh(char)20 b Fg(history)p 302 2160 V 20 w(subst)p 454 2160 -V 20 w(c)n(har)120 2222 y Fo(The)13 b(c)o(haracter)e(that)h(in)o(v)o(ok)o(es) -g(w)o(ord)g(substitution)h(if)g(found)g(at)e(the)i(start)e(of)h(a)g(line.)21 -b(The)12 b(default)120 2285 y(is)k(`)p Fn(^)p Fo('.)1736 2458 -y(V)l(ariable)-1899 b Fh(char)20 b Fg(history)p 302 2458 V -20 w(commen)n(t)p 552 2458 V 19 w(c)n(har)120 2521 y Fo(During)12 -b(tok)o(enization,)h(if)f(this)h(c)o(haracter)e(is)i(seen)f(as)g(the)g -(\014rst)f(c)o(haracter)g(of)h(a)g(w)o(ord,)f(then)i(it)f(and)120 -2583 y(all)19 b(subsequen)o(t)g(c)o(haracters)e(up)h(to)g(a)f(newline)j(are)e -(ignored,)h(suppressing)g(history)f(expansion)120 2645 y(for)d(the)g -(remainder)h(of)f(the)g(line.)21 b(This)16 b(is)g(disabled)h(b)o(y)e -(default.)p eop -%%Page: 12 14 -13 bop 0 -83 a Fo(12)1474 b(GNU)15 b(History)g(Library)1736 -158 y(V)l(ariable)-1899 b Fh(char)20 b(*)f Fg(history)p 347 -158 18 3 v 21 w(no)p 429 158 V 20 w(expand)p 629 158 V 20 w(c)n(hars)120 -221 y Fo(The)f(list)g(of)g(c)o(haracters)e(whic)o(h)j(inhibit)h(history)d -(expansion)i(if)f(found)g(immediately)h(follo)o(wing)120 283 -y Fj(history)p 261 283 14 2 v 16 w(expansion)p 472 283 V 18 -w(c)o(har)p Fo(.)g(The)d(default)f(is)h(whitespace)g(and)g(`)p -Fn(=)p Fo('.)0 575 y Fm(2.5)33 b(History)15 b(Programming)h(Example)62 -720 y Fo(The)g(follo)o(wing)g(program)e(demonstrates)g(simple)j(use)e(of)g -(the)g(GNU)g(History)g(Library)l(.)120 852 y Fn(main)23 b(\(\))120 -902 y({)168 951 y(char)g(line[1024],)f(*t;)168 1001 y(int)h(len,)g(done)h(=)g -(0;)168 1101 y(line[0])f(=)g(0;)168 1201 y(using_history)f(\(\);)168 -1250 y(while)h(\(!done\))215 1300 y({)263 1350 y(printf)g(\("history$)g("\);) -263 1400 y(fflush)g(\(stdout\);)263 1450 y(t)h(=)g(fgets)f(\(line,)g(sizeof)g -(\(line\))g(-)h(1,)f(stdin\);)263 1499 y(if)h(\(t)f(&&)h(*t\))311 -1549 y({)359 1599 y(len)f(=)h(strlen)f(\(t\);)359 1649 y(if)g(\(t[len)g(-)h -(1])g(==)f('\\n'\))406 1699 y(t[len)h(-)f(1])h(=)g('\\0';)311 -1748 y(})263 1848 y(if)g(\(!t\))311 1898 y(strcpy)f(\(line,)g("quit"\);)263 -1998 y(if)h(\(line[0]\))311 2047 y({)359 2097 y(char)f(*expansion;)359 -2147 y(int)g(result;)359 2247 y(result)g(=)g(history_expand)f(\(line,)h -(&expansion\);)359 2296 y(if)g(\(result\))406 2346 y(fprintf)g(\(stderr,)g -("\045s\\n",)g(expansion\);)359 2446 y(if)g(\(result)g(<)h(0)g(||)f(result)g -(==)h(2\))406 2496 y({)454 2545 y(free)f(\(expansion\);)454 -2595 y(continue;)406 2645 y(})p eop -%%Page: 13 15 -14 bop 0 -83 a Fo(Chapter)15 b(2:)k(Programming)c(with)g(GNU)g(History)1017 -b(13)359 208 y Fn(add_history)22 b(\(expansion\);)359 258 y(strncpy)h -(\(line,)g(expansion,)f(sizeof)h(\(line\))g(-)h(1\);)359 308 -y(free)f(\(expansion\);)311 358 y(})263 457 y(if)h(\(strcmp)f(\(line,)g -("quit"\))g(==)g(0\))311 507 y(done)g(=)h(1;)263 557 y(else)f(if)h(\(strcmp)f -(\(line,)g("save"\))g(==)h(0\))311 607 y(write_history)e(\("history_file"\);) -263 656 y(else)h(if)h(\(strcmp)f(\(line,)g("read"\))g(==)h(0\))311 -706 y(read_history)e(\("history_file"\);)263 756 y(else)h(if)h(\(strcmp)f -(\(line,)g("list"\))g(==)h(0\))311 806 y({)359 856 y(register)e(HIST_ENTRY)h -(**the_list;)359 906 y(register)f(int)i(i;)359 1005 y(the_list)e(=)i -(history_list)e(\(\);)359 1055 y(if)h(\(the_list\))406 1105 -y(for)h(\(i)f(=)h(0;)g(the_list[i];)e(i++\))454 1155 y(printf)h(\("\045d:)g -(\045s\\n",)g(i)h(+)g(history_base,)e(the_list[i]->line\);)311 -1204 y(})263 1254 y(else)h(if)h(\(strncmp)f(\(line,)g("delete",)g(6\))g(==)h -(0\))311 1304 y({)359 1354 y(int)f(which;)359 1404 y(if)g(\(\(sscanf)g -(\(line)g(+)h(6,)f("\045d",)h(&which\)\))e(==)i(1\))406 1453 -y({)454 1503 y(HIST_ENTRY)f(*entry)g(=)g(remove_history)f(\(which\);)454 -1553 y(if)i(\(!entry\))502 1603 y(fprintf)f(\(stderr,)f("No)i(such)f(entry)g -(\045d\\n",)g(which\);)454 1653 y(else)502 1703 y({)550 1752 -y(free)g(\(entry->line\);)550 1802 y(free)g(\(entry\);)502 -1852 y(})406 1902 y(})359 1952 y(else)406 2001 y({)454 2051 -y(fprintf)g(\(stderr,)g("non-numeric)f(arg)h(given)h(to)f(`delete'\\n"\);)406 -2101 y(})311 2151 y(})215 2201 y(})120 2250 y(})p eop -%%Page: 14 16 -15 bop 0 -83 a Fo(14)1474 b(GNU)15 b(History)g(Library)p eop -%%Page: 15 17 -16 bop 0 -83 a Fo(App)q(endix)17 b(A:)e(Concept)g(Index)1346 -b(15)0 158 y Fk(App)r(endix)13 b(A)41 b(Concept)15 b(Index)0 -405 y Fm(A)0 471 y Fe(anc)o(hored)f(searc)o(h)5 b Fd(:)i(:)f(:)g(:)g(:)g(:)g -(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g -(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)18 b Fe(8)0 -579 y Fm(E)0 646 y Fe(ev)o(en)o(t)13 b(designators)g Fd(:)6 -b(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g -(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)23 -b Fe(1)1015 405 y(expansion)5 b Fd(:)k(:)d(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:) -g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f -(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)18 b Fe(1)1015 -521 y Fm(H)1015 587 y Fe(history)d(ev)o(en)o(ts)5 b Fd(:)i(:)f(:)g(:)g(:)g(:) -g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g -(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)18 b -Fe(1)1015 646 y(History)c(Searc)o(hing)7 b Fd(:)h(:)e(:)g(:)g(:)g(:)g(:)h(:)f -(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g -(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)20 b Fe(8)p eop -%%Page: 16 18 -17 bop 0 -83 a Fo(16)1474 b(GNU)15 b(History)g(Library)p eop -%%Page: 17 19 -18 bop 0 -83 a Fo(App)q(endix)17 b(B:)e(F)l(unction)h(and)g(V)l(ariable)g -(Index)1069 b(17)0 158 y Fk(App)r(endix)13 b(B)41 b(F)-7 b(unction)15 -b(and)g(V)-7 b(ariable)14 b(Index)0 405 y Fm(A)0 471 y Fc(add)p -62 471 12 2 v 13 w(history)8 b Fd(:)s(:)e(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g -(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g -(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)20 b Fe(7)0 529 y Fc(append)p -122 529 V 12 w(history)9 b Fd(:)d(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g -(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f -(:)g(:)g(:)g(:)24 b Fe(10)0 654 y Fm(C)0 720 y Fc(current)p -142 720 V 11 w(history)9 b Fd(:)d(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g -(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g -(:)g(:)g(:)g(:)24 b Fe(8)0 845 y Fm(G)0 911 y Fc(get)p 62 911 -V 13 w(history)p 215 911 V 11 w(event)9 b Fd(:)d(:)g(:)g(:)g(:)g(:)g(:)g(:)g -(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f -(:)g(:)g(:)g(:)g(:)23 b Fe(10)0 1036 y Fm(H)0 1102 y Fc(history)p -142 1102 V 11 w(arg)p 213 1102 V 13 w(extract)8 b Fd(:)t(:)e(:)g(:)g(:)g(:)g -(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g -(:)g(:)g(:)g(:)g(:)21 b Fe(10)0 1160 y Fc(history)p 142 1160 -V 11 w(base)e Fd(:)6 b(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:) -g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h -(:)f(:)g(:)20 b Fe(11)0 1218 y Fc(history)p 142 1218 V 11 w(comment)p -293 1218 V 12 w(char)g Fd(:)6 b(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f -(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)21 -b Fe(11)0 1276 y Fc(history)p 142 1276 V 11 w(expand)10 b Fd(:)c(:)g(:)g(:)g -(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g -(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)24 b Fe(10)0 -1335 y Fc(history)p 142 1335 V 11 w(expansion)p 333 1335 V -11 w(char)17 b Fd(:)7 b(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g -(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)19 b Fe(11)0 -1393 y Fc(history)p 142 1393 V 11 w(get)8 b Fd(:)d(:)h(:)g(:)g(:)g(:)g(:)h(:) -f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g -(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)20 b Fe(8)0 -1451 y Fc(history)p 142 1451 V 11 w(get)p 213 1451 V 13 w(history)p -366 1451 V 12 w(state)t Fd(:)t(:)6 b(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g -(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)17 b Fe(6)0 -1509 y Fc(history)p 142 1509 V 11 w(is)p 193 1509 V 14 w(stifled)7 -b Fd(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g -(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)23 b -Fe(7)0 1567 y Fc(history)p 142 1567 V 11 w(length)16 b Fd(:)6 -b(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g -(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)18 -b Fe(11)0 1625 y Fc(history)p 142 1625 V 11 w(list)7 b Fd(:)t(:)g(:)f(:)g(:)g -(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g -(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)19 -b Fe(7)0 1683 y Fc(history)p 142 1683 V 11 w(no)p 193 1683 -V 14 w(expand)p 327 1683 V 12 w(chars)f Fd(:)6 b(:)g(:)g(:)g(:)g(:)g(:)h(:)f -(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)20 -b Fe(12)0 1741 y Fc(history)p 142 1741 V 11 w(search)t Fd(:)t(:)6 -b(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g -(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)17 -b Fe(9)0 1800 y Fc(history)p 142 1800 V 11 w(search)p 273 1800 -V 12 w(pos)9 b Fd(:)d(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g -(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)23 -b Fe(9)0 1858 y Fc(history)p 142 1858 V 11 w(search)p 273 1858 -V 12 w(prefix)6 b Fd(:)t(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g -(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)19 -b Fe(9)0 1916 y Fc(history)p 142 1916 V 11 w(set)p 213 1916 -V 13 w(history)p 366 1916 V 12 w(state)t Fd(:)t(:)6 b(:)g(:)g(:)g(:)g(:)g(:)g -(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)17 -b Fe(6)0 1974 y Fc(history)p 142 1974 V 11 w(set)p 213 1974 -V 13 w(pos)5 b Fd(:)h(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g -(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g -(:)g(:)18 b Fe(8)0 2032 y Fc(history)p 142 2032 V 11 w(subst)p -253 2032 V 13 w(char)k Fd(:)6 b(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g -(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)24 -b Fe(11)1015 405 y Fc(history)p 1157 405 V 12 w(tokenize)9 -b Fd(:)s(:)d(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g -(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)22 -b Fe(11)1015 463 y Fc(history)p 1157 463 V 12 w(total)p 1269 -463 V 12 w(bytes)9 b Fd(:)t(:)d(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g -(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)22 -b Fe(8)1015 521 y Fc(history)p 1157 521 V 12 w(truncate)p 1329 -521 V 11 w(file)5 b Fd(:)g(:)h(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:) -f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)19 -b Fe(10)1015 629 y Fm(M)1015 695 y Fc(max)p 1077 695 V 13 w(input)p -1190 695 V 13 w(history)14 b Fd(:)6 b(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g -(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g -(:)g(:)17 b Fe(11)1015 803 y Fm(N)1015 870 y Fc(next)p 1097 -870 V 13 w(history)7 b Fd(:)s(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g -(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g -(:)g(:)g(:)g(:)g(:)g(:)g(:)20 b Fe(8)1015 978 y Fm(P)1015 1044 -y Fc(previous)p 1177 1044 V 12 w(history)7 b Fd(:)f(:)g(:)g(:)g(:)g(:)g(:)g -(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h -(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)23 b Fe(8)1015 1152 y Fm(R)1015 -1218 y Fc(read)p 1097 1218 V 13 w(history)7 b Fd(:)s(:)f(:)g(:)g(:)g(:)g(:)g -(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f -(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)20 b Fe(9)1015 -1276 y Fc(read)p 1097 1276 V 13 w(history)p 1250 1276 V 11 -w(range)9 b Fd(:)d(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:) -g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)23 -b Fe(9)1015 1335 y Fc(remove)p 1137 1335 V 12 w(history)t Fd(:)t(:)6 -b(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g -(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)17 -b Fe(7)1015 1393 y Fc(replace)p 1157 1393 V 12 w(history)p -1309 1393 V 11 w(entry)6 b Fd(:)f(:)h(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h -(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)19 -b Fe(7)1015 1501 y Fm(S)1015 1567 y Fc(stifle)p 1137 1567 V -12 w(history)t Fd(:)t(:)6 b(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h -(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g -(:)g(:)g(:)g(:)17 b Fe(7)1015 1675 y Fm(U)1015 1741 y Fc(unstifle)p -1177 1741 V 12 w(history)7 b Fd(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h -(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g -(:)g(:)g(:)g(:)23 b Fe(7)1015 1800 y Fc(using)p 1117 1800 V -13 w(history)5 b Fd(:)s(:)h(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g -(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g -(:)g(:)h(:)f(:)g(:)18 b Fe(6)1015 1907 y Fm(W)1015 1974 y Fc(where)p -1117 1974 V 13 w(history)5 b Fd(:)s(:)h(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g -(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g -(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)18 b Fe(8)1015 2032 y Fc(write)p -1117 2032 V 13 w(history)5 b Fd(:)s(:)h(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g -(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g -(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)18 b Fe(9)p eop -%%Page: 18 20 -19 bop 0 -83 a Fo(18)1474 b(GNU)15 b(History)g(Library)p eop -%%Page: -1 21 -20 bop 1937 -83 a Fo(i)0 158 y Fk(T)-7 b(able)15 b(of)g(Con)n(ten)n(ts)0 -333 y Fm(1)67 b(Using)22 b(History)h(In)n(teractiv)n(ely)9 -b Fb(:)k(:)d(:)g(:)g(:)h(:)f(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g -(:)h(:)f(:)g(:)g(:)h(:)f(:)g(:)31 b Fm(1)149 411 y Fo(1.1)45 -b(History)15 b(In)o(teraction)9 b Fa(:)f(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g -(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g -(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)23 -b Fo(1)299 473 y(1.1.1)44 b(Ev)o(en)o(t)14 b(Designators)6 -b Fa(:)h(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g -(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f -(:)g(:)g(:)20 b Fo(1)299 535 y(1.1.2)44 b(W)l(ord)15 b(Designators)9 -b Fa(:)d(:)h(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h -(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g -(:)h(:)f(:)23 b Fo(2)299 597 y(1.1.3)44 b(Mo)q(di\014ers)14 -b Fa(:)8 b(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:) -g(:)g(:)g(:)h(:)f(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g -(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)28 b Fo(2)0 722 -y Fm(2)67 b(Programming)23 b(with)g(GNU)f(History)13 b Fb(:)e(:)f(:)g(:)g(:)h -(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)36 b -Fm(5)149 800 y Fo(2.1)45 b(In)o(tro)q(duction)16 b(to)f(History)6 -b Fa(:)h(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g -(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f -(:)g(:)g(:)g(:)h(:)f(:)g(:)20 b Fo(5)149 862 y(2.2)45 b(History)15 -b(Storage)d Fa(:)7 b(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g -(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f -(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)27 -b Fo(5)149 924 y(2.3)45 b(History)15 b(F)l(unctions)c Fa(:)d(:)f(:)h(:)f(:)g -(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f -(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h -(:)f(:)g(:)g(:)g(:)h(:)25 b Fo(6)299 986 y(2.3.1)44 b(Initializing)18 -b(History)d(and)h(State)e(Managemen)o(t)f Fa(:)7 b(:)g(:)g(:)h(:)f(:)g(:)g(:) -g(:)h(:)f(:)g(:)g(:)g(:)h(:)27 b Fo(6)299 1049 y(2.3.2)44 b(History)15 -b(List)h(Managemen)o(t)c Fa(:)7 b(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h -(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g -(:)28 b Fo(7)299 1111 y(2.3.3)44 b(Information)15 b(Ab)q(out)g(the)h(History) -f(List)5 b Fa(:)i(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g -(:)g(:)g(:)h(:)f(:)g(:)g(:)19 b Fo(7)299 1173 y(2.3.4)44 b(Mo)o(ving)15 -b(Around)g(the)g(History)g(List)6 b Fa(:)i(:)f(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:) -g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)20 -b Fo(8)299 1236 y(2.3.5)44 b(Searc)o(hing)16 b(the)f(History)g(List)7 -b Fa(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f -(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)21 b -Fo(8)299 1298 y(2.3.6)44 b(Managing)15 b(the)g(History)g(File)5 -b Fa(:)j(:)f(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g -(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)19 b -Fo(9)299 1360 y(2.3.7)44 b(History)15 b(Expansion)d Fa(:)7 -b(:)g(:)h(:)f(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g -(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)26 -b Fo(10)149 1422 y(2.4)45 b(History)15 b(V)l(ariables)5 b Fa(:)k(:)e(:)g(:)g -(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g -(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f -(:)g(:)g(:)g(:)h(:)f(:)g(:)20 b Fo(11)149 1485 y(2.5)45 b(History)15 -b(Programming)f(Example)8 b Fa(:)g(:)f(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:) -g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f -(:)g(:)g(:)g(:)23 b Fo(12)0 1609 y Fm(App)r(endix)h(A)67 b(Concept)22 -b(Index)15 b Fb(:)c(:)f(:)h(:)f(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g -(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)h(:)37 b Fm(15)0 1749 -y(App)r(endix)24 b(B)67 b(F)-6 b(unction)25 b(and)e(V)-6 b(ariable)24 -b(Index)8 b Fb(:)j(:)f(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)31 -b Fm(17)p eop -%%Page: -2 22 -21 bop 0 -83 a Fo(ii)1496 b(GNU)15 b(History)g(Library)p eop -%%Trailer -end -userdict /end-hook known{end-hook}if -%%EOF diff --git a/lib/readline/doc/hstech.texinfo b/lib/readline/doc/hstech.texinfo index 5f0f600..be41318 100644 --- a/lib/readline/doc/hstech.texinfo +++ b/lib/readline/doc/hstech.texinfo @@ -1,7 +1,7 @@ @ignore This file documents the user interface to the GNU History library. -Copyright (C) 1988, 1991 Free Software Foundation, Inc. +Copyright (C) 1988, 1991, 1994, 1996 Free Software Foundation, Inc. Authored by Brian Fox and Chet Ramey. Permission is granted to make and distribute verbatim copies of this manual @@ -168,6 +168,10 @@ This returns the old entry so you can dispose of the data. In the case of an invalid @var{which}, a @code{NULL} pointer is returned. @end deftypefun +@deftypefun void clear_history () +Clear the history list by deleting all the entries. +@end deftypefun + @deftypefun void stifle_history (int max) Stifle the history list, remembering only the last @var{max} entries. @end deftypefun @@ -400,6 +404,17 @@ following @var{history_expansion_char}. The default is whitespace and @samp{=}. @end deftypevar +@deftypevar {char *} history_search_delimiter_chars +The list of additional characters which can delimit a history search +string, in addition to whitespace, @samp{:} and @samp{?} in the case of +a substring search. The default is empty. +@end deftypevar + +@deftypevar int history_quotes_inhibit_expansion +If non-zero, single-quoted words are not scanned for the history expansion +character. The default value is 0. +@end deftypevar + @node History Programming Example @section History Programming Example diff --git a/lib/readline/doc/hsuser.texinfo b/lib/readline/doc/hsuser.texinfo index 51327a3..6e95649 100644 --- a/lib/readline/doc/hsuser.texinfo +++ b/lib/readline/doc/hsuser.texinfo @@ -1,7 +1,7 @@ @ignore This file documents the user interface to the GNU History library. -Copyright (C) 1988, 1991 Free Software Foundation, Inc. +Copyright (C) 1988, 1991, 1996 Free Software Foundation, Inc. Authored by Brian Fox and Chet Ramey. Permission is granted to make and distribute verbatim copies of this manual @@ -39,26 +39,124 @@ information on using the GNU History Library in your own programs, @pxref{Programming with GNU History}. @end ifclear +@ifset BashFeatures @menu +* Bash History Facilities:: How Bash lets you manipulate your command + history. * History Interaction:: What it feels like using History as a user. @end menu +@end ifset +@ifclear BashFeatures +@menu +* History Interaction:: What it feels like using History as a user. +@end menu +@end ifclear + +@ifset BashFeatures +@node Bash History Facilities +@section Bash History Facilities +@cindex command history +@cindex history list + +When the @samp{-o history} option to the @code{set} builtin +is enabled (@pxref{The Set Builtin}), +the shell provides access to the @var{command history}, +the list of commands previously typed. The text of the last +@code{HISTSIZE} +commands (default 500) is saved in a history list. The shell +stores each command in the history list prior to parameter and +variable expansion +but after history expansion is performed, subject to the +values of the shell variables +@code{HISTIGNORE} and @code{HISTCONTROL}. +When the shell starts up, the history is initialized from the +file named by the @code{HISTFILE} variable (default @file{~/.bash_history}). +@code{HISTFILE} is truncated, if necessary, to contain no more than +the number of lines specified by the value of the @code{HISTFILESIZE} +variable. When an interactive shell exits, the last +@code{HISTSIZE} lines are copied from the history list to @code{HISTFILE}. +If the @code{histappend} shell option is set (@pxref{Bash Builtins}), +the lines are appended to the history file, +otherwise the history file is overwritten. +If @code{HISTFILE} +is unset, or if the history file is unwritable, the history is +not saved. After saving the history, the history file is truncated +to contain no more than @code{$HISTFILESIZE} +lines. If @code{HISTFILESIZE} is not set, no truncation is performed. + +The builtin command @code{fc} (@pxref{Korn Shell Builtins}) +may be used to list or edit and re-execute a portion of +the history list. The @code{history} builtin (@pxref{C Shell Builtins}) +can be used to display or modify the history list and +manipulate the history file. +When using the command-line editing, search commands +are available in each editing mode that provide access to the +history list. + +The shell allows control over which commands are saved on the history +list. The @code{HISTCONTROL} and @code{HISTIGNORE} +variables may be set to cause the shell to save only a subset of the +commands entered. +The @code{cmdhist} +shell option, if enabled, causes the shell to attempt to save each +line of a multi-line command in the same history entry, adding +semicolons where necessary to preserve syntactic correctness. +The @code{lithist} +shell option causes the shell to save the command with embedded newlines +instead of semicolons. +@xref{Bash Builtins} for a description of @code{shopt}. +@end ifset @node History Interaction -@section History Interaction -@cindex expansion +@section Interactive History Expansion +@cindex history expansion The History library provides a history expansion feature that is similar -to the history expansion provided by @code{csh}. The following text +to the history expansion provided by @code{csh}. This section describes the syntax used to manipulate the history information. +History expansions introduce words from the history list into +the input stream, making it easy to repeat commands, insert the +arguments to a previous command into the current input line, or +fix errors in previous commands quickly. + History expansion takes place in two parts. The first is to determine which line from the previous history should be used during substitution. The second is to select portions of that line for inclusion into the current one. The line selected from the previous history is called the @dfn{event}, and the portions of that line that are acted upon are -called @dfn{words}. The line is broken into words in the same fashion +called @dfn{words}. Various @dfn{modifiers} are available to manipulate +the selected words. The line is broken into words in the same fashion that Bash does, so that several English (or Unix) words surrounded by quotes are considered as one word. +History expansions are introduced by the appearance of the +history expansion character, which is @samp{!} by default. +@ifset BashFeatures +Only @samp{\} and @samp{'} may be used to escape the history expansion +character. +@end ifset + +@ifset BashFeatures +Several shell options settable with the @code{shopt} +builtin (@pxref{Bash Builtins}) may be used to tailor +the behavior of history expansion. If the +@code{histverify} shell option is enabled, and Readline +is being used, history substitutions are not immediately passed to +the shell parser. +Instead, the expanded line is reloaded into the Readline +editing buffer for further modification. +If Readline is being used, and the @code{histreedit} +shell option is enabled, a failed history expansion will be +reloaded into the Readline editing buffer for correction. +The @samp{-p} option to the @code{history} builtin command +may be used to see what a history expansion will do before using it. +The @samp{-s} option to the @code{history} builtin may be used to +add commands to the end of the history list without actually executing +them, so that they are available for subsequent recall. + +The shell allows control of the various characters used by the +history expansion mechanism with the @code{histchars} variable. +@end ifset @menu * Event Designators:: How to specify which history line to use. @@ -80,92 +178,100 @@ history list. Start a history substitution, except when followed by a space, tab, the end of the line, @key{=} or @key{(}. -@item @code{!!} -Refer to the previous command. This is a synonym for @code{!-1}. - -@item @code{!n} +@item @code{!@var{n}} Refer to command line @var{n}. -@item @code{!-n} +@item @code{!-@var{n}} Refer to the command @var{n} lines back. -@item @code{!string} +@item @code{!!} +Refer to the previous command. This is a synonym for @samp{!-1}. + +@item @code{!@var{string}} Refer to the most recent command starting with @var{string}. -@item @code{!?string}[@code{?}] -Refer to the most recent command containing @var{string}. +@item @code{!?@var{string}[?]} +Refer to the most recent command containing @var{string}. The trailing +@samp{?} may be omitted if the @var{string} is followed immediately by +a newline. -@item @code{!#} -The entire command line typed so far. - -@item @code{^string1^string2^} +@item @code{^@var{string1}^@var{string2}^} Quick Substitution. Repeat the last command, replacing @var{string1} with @var{string2}. Equivalent to -@code{!!:s/string1/string2/}. +@code{!!:s/@var{string1}/@var{string2}/}. + +@item @code{!#} +The entire command line typed so far. @end table @node Word Designators @subsection Word Designators -A @key{:} separates the event specification from the word designator. It -can be omitted if the word designator begins with a @key{^}, @key{$}, -@key{*} or @key{%}. Words are numbered from the beginning of the line, -with the first word being denoted by a 0 (zero). +Word designators are used to select desired words from the event. +A @samp{:} separates the event specification from the word designator. It +can be omitted if the word designator begins with a @samp{^}, @samp{$}, +@samp{*}, @samp{-}, or @samp{%}. Words are numbered from the beginning +of the line, with the first word being denoted by 0 (zero). Words are +inserted into the current line separated by single spaces. @table @code @item 0 (zero) The @code{0}th word. For many applications, this is the command word. -@item n +@item @var{n} The @var{n}th word. @item ^ -The first argument; that is, word 1. +The first argument; that is, word 1. @item $ The last argument. @item % -The word matched by the most recent @code{?string?} search. +The word matched by the most recent @samp{?@var{string}?} search. -@item x-y -A range of words; @code{-@var{y}} abbreviates @code{0-@var{y}}. +@item @var{x}-@var{y} +A range of words; @samp{-@var{y}} abbreviates @samp{0-@var{y}}. @item * -All of the words, except the @code{0}th. This is a synonym for @code{1-$}. -It is not an error to use @key{*} if there is just one word in the event; +All of the words, except the @code{0}th. This is a synonym for @samp{1-$}. +It is not an error to use @samp{*} if there is just one word in the event; the empty string is returned in that case. -@item x* -Abbreviates @code{x-$} +@item @var{x}* +Abbreviates @samp{@var{x}-$} -@item x- -Abbreviates @code{x-$} like @code{x*}, but omits the last word. +@item @var{x}- +Abbreviates @samp{@var{x}-$} like @samp{@var{x}*}, but omits the last word. @end table +If a word designator is supplied without an event specification, the +previous command is used as the event. + @node Modifiers @subsection Modifiers After the optional word designator, you can add a sequence of one or more -of the following modifiers, each preceded by a @key{:}. +of the following modifiers, each preceded by a @samp{:}. @table @code @item h Remove a trailing pathname component, leaving only the head. +@item t +Remove all leading pathname components, leaving the tail. + @item r -Remove a trailing suffix of the form @samp{.}@var{suffix}, leaving the basename. +Remove a trailing suffix of the form @samp{.@var{suffix}}, leaving +the basename. @item e Remove all but the trailing suffix. -@item t -Remove all leading pathname components, leaving the tail. - @item p Print the new command but do not execute it. @@ -174,17 +280,17 @@ Print the new command but do not execute it. Quote the substituted words, escaping further substitutions. @item x -Quote the substituted words as with @code{q}, +Quote the substituted words as with @samp{q}, but break into words at spaces, tabs, and newlines. @end ifset -@item s/old/new/ +@item s/@var{old}/@var{new}/ Substitute @var{new} for the first occurrence of @var{old} in the -event line. Any delimiter may be used in place of @key{/}. +event line. Any delimiter may be used in place of @samp{/}. The delimiter may be quoted in @var{old} and @var{new} -with a single backslash. If @key{&} appears in @var{new}, +with a single backslash. If @samp{&} appears in @var{new}, it is replaced by @var{old}. A single backslash will quote -the @key{&}. The final delimiter is optional if it is the last +the @samp{&}. The final delimiter is optional if it is the last character on the input line. @item & @@ -192,7 +298,7 @@ Repeat the previous substitution. @item g Cause changes to be applied over the entire event line. Used in -conjunction with @code{s}, as in @code{gs/old/new/}, or with -@code{&}. +conjunction with @samp{s}, as in @code{gs/@var{old}/@var{new}/}, +or with @samp{&}. @end table diff --git a/lib/readline/doc/readline.dvi b/lib/readline/doc/readline.dvi deleted file mode 100644 index aea321a..0000000 Binary files a/lib/readline/doc/readline.dvi and /dev/null differ diff --git a/lib/readline/doc/readline.info b/lib/readline/doc/readline.info deleted file mode 100644 index 6df0bd9..0000000 --- a/lib/readline/doc/readline.info +++ /dev/null @@ -1,744 +0,0 @@ -This is Info file history.info, produced by Makeinfo-1.55 from the -input file hist.texinfo. - - This document describes the GNU History library, a programming tool -that provides a consistent user interface for recalling lines of -previously typed input. - - Copyright (C) 1988, 1991 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. - - 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. - - -File: history.info, Node: Top, Next: Using History Interactively, Prev: (DIR), Up: (DIR) - -GNU History Library -******************* - - This document describes the GNU History library, a programming tool -that provides a consistent user interface for recalling lines of -previously typed input. - -* Menu: - -* Using History Interactively:: GNU History User's Manual. -* Programming with GNU History:: GNU History Programmer's Manual. -* Concept Index:: Index of concepts described in this manual. -* Function and Variable Index:: Index of externally visible functions - and variables. - - -File: history.info, Node: Using History Interactively, Next: Programming with GNU History, Prev: Top, Up: Top - -Using History Interactively -*************************** - - This chapter describes how to use the GNU History Library -interactively, from a user's standpoint. It should be considered a -user's guide. For information on using the GNU History Library in your -own programs, *note Programming with GNU History::.. - -* Menu: - -* History Interaction:: What it feels like using History as a user. - - -File: history.info, Node: History Interaction, Up: Using History Interactively - -History Interaction -=================== - - The History library provides a history expansion feature that is -similar to the history expansion provided by `csh'. The following text -describes the syntax used to manipulate the history information. - - History expansion takes place in two parts. The first is to -determine which line from the previous history should be used during -substitution. The second is to select portions of that line for -inclusion into the current one. The line selected from the previous -history is called the "event", and the portions of that line that are -acted upon are called "words". The line is broken into words in the -same fashion that Bash does, so that several English (or Unix) words -surrounded by quotes are considered as one word. - -* Menu: - -* Event Designators:: How to specify which history line to use. -* Word Designators:: Specifying which words are of interest. -* Modifiers:: Modifying the results of substitution. - - -File: history.info, Node: Event Designators, Next: Word Designators, Up: History Interaction - -Event Designators ------------------ - - An event designator is a reference to a command line entry in the -history list. - -`!' - Start a history substitution, except when followed by a space, tab, - the end of the line, = or (. - -`!!' - Refer to the previous command. This is a synonym for `!-1'. - -`!n' - Refer to command line N. - -`!-n' - Refer to the command N lines back. - -`!string' - Refer to the most recent command starting with STRING. - -`!?string'[`?'] - Refer to the most recent command containing STRING. - -`!#' - The entire command line typed so far. - -`^string1^string2^' - Quick Substitution. Repeat the last command, replacing STRING1 - with STRING2. Equivalent to `!!:s/string1/string2/'. - - -File: history.info, Node: Word Designators, Next: Modifiers, Prev: Event Designators, Up: History Interaction - -Word Designators ----------------- - - A : separates the event specification from the word designator. It -can be omitted if the word designator begins with a ^, $, * or %. -Words are numbered from the beginning of the line, with the first word -being denoted by a 0 (zero). - -`0 (zero)' - The `0'th word. For many applications, this is the command word. - -`n' - The Nth word. - -`^' - The first argument; that is, word 1. - -`$' - The last argument. - -`%' - The word matched by the most recent `?string?' search. - -`x-y' - A range of words; `-Y' abbreviates `0-Y'. - -`*' - All of the words, except the `0'th. This is a synonym for `1-$'. - It is not an error to use * if there is just one word in the event; - the empty string is returned in that case. - -`x*' - Abbreviates `x-$' - -`x-' - Abbreviates `x-$' like `x*', but omits the last word. - - -File: history.info, Node: Modifiers, Prev: Word Designators, Up: History Interaction - -Modifiers ---------- - - After the optional word designator, you can add a sequence of one or -more of the following modifiers, each preceded by a :. - -`h' - Remove a trailing pathname component, leaving only the head. - -`r' - Remove a trailing suffix of the form `.'SUFFIX, leaving the - basename. - -`e' - Remove all but the trailing suffix. - -`t' - Remove all leading pathname components, leaving the tail. - -`p' - Print the new command but do not execute it. - -`s/old/new/' - Substitute NEW for the first occurrence of OLD in the event line. - Any delimiter may be used in place of /. The delimiter may be - quoted in OLD and NEW with a single backslash. If & appears in - NEW, it is replaced by OLD. A single backslash will quote the &. - The final delimiter is optional if it is the last character on the - input line. - -`&' - Repeat the previous substitution. - -`g' - Cause changes to be applied over the entire event line. Used in - conjunction with `s', as in `gs/old/new/', or with `&'. - - -File: history.info, Node: Programming with GNU History, Next: Concept Index, Prev: Using History Interactively, Up: Top - -Programming with GNU History -**************************** - - This chapter describes how to interface programs that you write with -the GNU History Library. It should be considered a technical guide. -For information on the interactive use of GNU History, *note Using -History Interactively::.. - -* Menu: - -* Introduction to History:: What is the GNU History library for? -* History Storage:: How information is stored. -* History Functions:: Functions that you can use. -* History Variables:: Variables that control behaviour. -* History Programming Example:: Example of using the GNU History Library. - - -File: history.info, Node: Introduction to History, Next: History Storage, Up: Programming with GNU History - -Introduction to History -======================= - - Many programs read input from the user a line at a time. The GNU -History library is able to keep track of those lines, associate -arbitrary data with each line, and utilize information from previous -lines in composing new ones. - - The programmer using the History library has available functions for -remembering lines on a history list, associating arbitrary data with a -line, removing lines from the list, searching through the list for a -line containing an arbitrary text string, and referencing any line in -the list directly. In addition, a history "expansion" function is -available which provides for a consistent user interface across -different programs. - - The user using programs written with the History library has the -benefit of a consistent user interface with a set of well-known -commands for manipulating the text of previous lines and using that text -in new commands. The basic history manipulation commands are similar to -the history substitution provided by `csh'. - - If the programmer desires, he can use the Readline library, which -includes some history manipulation by default, and has the added -advantage of command line editing. - - -File: history.info, Node: History Storage, Next: History Functions, Prev: Introduction to History, Up: Programming with GNU History - -History Storage -=============== - - The history list is an array of history entries. A history entry is -declared as follows: - - typedef struct _hist_entry { - char *line; - char *data; - } HIST_ENTRY; - - The history list itself might therefore be declared as - - HIST_ENTRY **the_history_list; - - The state of the History library is encapsulated into a single -structure: - - /* A structure used to pass the current state of the history stuff around. */ - typedef struct _hist_state { - HIST_ENTRY **entries; /* Pointer to the entries themselves. */ - int offset; /* The location pointer within this array. */ - int length; /* Number of elements within this array. */ - int size; /* Number of slots allocated to this array. */ - int flags; - } HISTORY_STATE; - - If the flags member includes `HS_STIFLED', the history has been -stifled. - - -File: history.info, Node: History Functions, Next: History Variables, Prev: History Storage, Up: Programming with GNU History - -History Functions -================= - - This section describes the calling sequence for the various functions -present in GNU History. - -* Menu: - -* Initializing History and State Management:: Functions to call when you - want to use history in a - program. -* History List Management:: Functions used to manage the list - of history entries. -* Information About the History List:: Functions returning information about - the history list. -* Moving Around the History List:: Functions used to change the position - in the history list. -* Searching the History List:: Functions to search the history list - for entries containing a string. -* Managing the History File:: Functions that read and write a file - containing the history list. -* History Expansion:: Functions to perform csh-like history - expansion. - - -File: history.info, Node: Initializing History and State Management, Next: History List Management, Up: History Functions - -Initializing History and State Management ------------------------------------------ - - This section describes functions used to initialize and manage the -state of the History library when you want to use the history functions -in your program. - - - Function: void using_history () - Begin a session in which the history functions might be used. This - initializes the interactive variables. - - - Function: HISTORY_STATE * history_get_history_state () - Return a structure describing the current state of the input - history. - - - Function: void history_set_history_state (HISTORY_STATE *state) - Set the state of the history list according to STATE. - - -File: history.info, Node: History List Management, Next: Information About the History List, Prev: Initializing History and State Management, Up: History Functions - -History List Management ------------------------ - - These functions manage individual entries on the history list, or set -parameters managing the list itself. - - - Function: void add_history (char *string) - Place STRING at the end of the history list. The associated data - field (if any) is set to `NULL'. - - - Function: HIST_ENTRY * remove_history (int which) - Remove history entry at offset WHICH from the history. The - removed element is returned so you can free the line, data, and - containing structure. - - - Function: HIST_ENTRY * replace_history_entry (int which, char *line, - char *data) - Make the history entry at offset WHICH have LINE and DATA. This - returns the old entry so you can dispose of the data. In the case - of an invalid WHICH, a `NULL' pointer is returned. - - - Function: void stifle_history (int max) - Stifle the history list, remembering only the last MAX entries. - - - Function: int unstifle_history () - Stop stifling the history. This returns the previous amount the - history was stifled. The value is positive if the history was - stifled, negative if it wasn't. - - - Function: int history_is_stifled () - Returns non-zero if the history is stifled, zero if it is not. - - -File: history.info, Node: Information About the History List, Next: Moving Around the History List, Prev: History List Management, Up: History Functions - -Information About the History List ----------------------------------- - - These functions return information about the entire history list or -individual list entries. - - - Function: HIST_ENTRY ** history_list () - Return a `NULL' terminated array of `HIST_ENTRY' which is the - current input history. Element 0 of this list is the beginning of - time. If there is no history, return `NULL'. - - - Function: int where_history () - Returns the offset of the current history element. - - - Function: HIST_ENTRY * current_history () - Return the history entry at the current position, as determined by - `where_history ()'. If there is no entry there, return a `NULL' - pointer. - - - Function: HIST_ENTRY * history_get (int offset) - Return the history entry at position OFFSET, starting from - `history_base'. If there is no entry there, or if OFFSET is - greater than the history length, return a `NULL' pointer. - - - Function: int history_total_bytes () - Return the number of bytes that the primary history entries are - using. This function returns the sum of the lengths of all the - lines in the history. - - -File: history.info, Node: Moving Around the History List, Next: Searching the History List, Prev: Information About the History List, Up: History Functions - -Moving Around the History List ------------------------------- - - These functions allow the current index into the history list to be -set or changed. - - - Function: int history_set_pos (int pos) - Set the position in the history list to POS, an absolute index - into the list. - - - Function: HIST_ENTRY * previous_history () - Back up the current history offset to the previous history entry, - and return a pointer to that entry. If there is no previous - entry, return a `NULL' pointer. - - - Function: HIST_ENTRY * next_history () - Move the current history offset forward to the next history entry, - and return the a pointer to that entry. If there is no next - entry, return a `NULL' pointer. - - -File: history.info, Node: Searching the History List, Next: Managing the History File, Prev: Moving Around the History List, Up: History Functions - -Searching the History List --------------------------- - - These functions allow searching of the history list for entries -containing a specific string. Searching may be performed both forward -and backward from the current history position. The search may be -"anchored", meaning that the string must match at the beginning of the -history entry. - - - Function: int history_search (char *string, int direction) - Search the history for STRING, starting at the current history - offset. If DIRECTION < 0, then the search is through previous - entries, else through subsequent. If STRING is found, then the - current history index is set to that history entry, and the value - returned is the offset in the line of the entry where STRING was - found. Otherwise, nothing is changed, and a -1 is returned. - - - Function: int history_search_prefix (char *string, int direction) - Search the history for STRING, starting at the current history - offset. The search is anchored: matching lines must begin with - STRING. If DIRECTION < 0, then the search is through previous - entries, else through subsequent. If STRING is found, then the - current history index is set to that entry, and the return value - is 0. Otherwise, nothing is changed, and a -1 is returned. - - - Function: int history_search_pos (char *string, int direction, int - pos) - Search for STRING in the history list, starting at POS, an - absolute index into the list. If DIRECTION is negative, the search - proceeds backward from POS, otherwise forward. Returns the - absolute index of the history element where STRING was found, or - -1 otherwise. - - -File: history.info, Node: Managing the History File, Next: History Expansion, Prev: Searching the History List, Up: History Functions - -Managing the History File -------------------------- - - The History library can read the history from and write it to a file. -This section documents the functions for managing a history file. - - - Function: int read_history (char *filename) - Add the contents of FILENAME to the history list, a line at a - time. If FILENAME is `NULL', then read from `~/.history'. - Returns 0 if successful, or errno if not. - - - Function: int read_history_range (char *filename, int from, int to) - Read a range of lines from FILENAME, adding them to the history - list. Start reading at line FROM and end at TO. If FROM is zero, - start at the beginning. If TO is less than FROM, then read until - the end of the file. If FILENAME is `NULL', then read from - `~/.history'. Returns 0 if successful, or `errno' if not. - - - Function: int write_history (char *filename) - Write the current history to FILENAME, overwriting FILENAME if - necessary. If FILENAME is `NULL', then write the history list to - `~/.history'. Values returned are as in `read_history ()'. - - - Function: int append_history (int nelements, char *filename) - Append the last NELEMENTS of the history list to FILENAME. - - - Function: int history_truncate_file (char *filename, int nlines) - Truncate the history file FILENAME, leaving only the last NLINES - lines. - - -File: history.info, Node: History Expansion, Prev: Managing the History File, Up: History Functions - -History Expansion ------------------ - - These functions implement `csh'-like history expansion. - - - Function: int history_expand (char *string, char **output) - Expand STRING, placing the result into OUTPUT, a pointer to a - string (*note History Interaction::.). Returns: - `0' - If no expansions took place (or, if the only change in the - text was the de-slashifying of the history expansion - character); - - `1' - if expansions did take place; - - `-1' - if there was an error in expansion; - - `2' - if the returned line should only be displayed, but not - executed, as with the `:p' modifier (*note Modifiers::.). - - If an error ocurred in expansion, then OUTPUT contains a - descriptive error message. - - - Function: char * history_arg_extract (int first, int last, char - *string) - Extract a string segment consisting of the FIRST through LAST - arguments present in STRING. Arguments are broken up as in Bash. - - - Function: char * get_history_event (char *string, int *cindex, int - qchar) - Returns the text of the history event beginning at STRING + - *CINDEX. *CINDEX is modified to point to after the event - specifier. At function entry, CINDEX points to the index into - STRING where the history event specification begins. QCHAR is a - character that is allowed to end the event specification in - addition to the "normal" terminating characters. - - - Function: char ** history_tokenize (char *string) - Return an array of tokens parsed out of STRING, much as the shell - might. The tokens are split on white space and on the characters - `()<>;&|$', and shell quoting conventions are obeyed. - - -File: history.info, Node: History Variables, Next: History Programming Example, Prev: History Functions, Up: Programming with GNU History - -History Variables -================= - - This section describes the externally visible variables exported by -the GNU History Library. - - - Variable: int history_base - The logical offset of the first entry in the history list. - - - Variable: int history_length - The number of entries currently stored in the history list. - - - Variable: int max_input_history - The maximum number of history entries. This must be changed using - `stifle_history ()'. - - - Variable: char history_expansion_char - The character that starts a history event. The default is `!'. - - - Variable: char history_subst_char - The character that invokes word substitution if found at the start - of a line. The default is `^'. - - - Variable: char history_comment_char - During tokenization, if this character is seen as the first - character of a word, then it and all subsequent characters up to a - newline are ignored, suppressing history expansion for the - remainder of the line. This is disabled by default. - - - Variable: char * history_no_expand_chars - The list of characters which inhibit history expansion if found - immediately following HISTORY_EXPANSION_CHAR. The default is - whitespace and `='. - - -File: history.info, Node: History Programming Example, Prev: History Variables, Up: Programming with GNU History - -History Programming Example -=========================== - - The following program demonstrates simple use of the GNU History -Library. - - main () - { - char line[1024], *t; - int len, done = 0; - - line[0] = 0; - - using_history (); - while (!done) - { - printf ("history$ "); - fflush (stdout); - t = fgets (line, sizeof (line) - 1, stdin); - if (t && *t) - { - len = strlen (t); - if (t[len - 1] == '\n') - t[len - 1] = '\0'; - } - - if (!t) - strcpy (line, "quit"); - - if (line[0]) - { - char *expansion; - int result; - - result = history_expand (line, &expansion); - if (result) - fprintf (stderr, "%s\n", expansion); - - if (result < 0 || result == 2) - { - free (expansion); - continue; - } - - add_history (expansion); - strncpy (line, expansion, sizeof (line) - 1); - free (expansion); - } - - if (strcmp (line, "quit") == 0) - done = 1; - else if (strcmp (line, "save") == 0) - write_history ("history_file"); - else if (strcmp (line, "read") == 0) - read_history ("history_file"); - else if (strcmp (line, "list") == 0) - { - register HIST_ENTRY **the_list; - register int i; - - the_list = history_list (); - if (the_list) - for (i = 0; the_list[i]; i++) - printf ("%d: %s\n", i + history_base, the_list[i]->line); - } - else if (strncmp (line, "delete", 6) == 0) - { - int which; - if ((sscanf (line + 6, "%d", &which)) == 1) - { - HIST_ENTRY *entry = remove_history (which); - if (!entry) - fprintf (stderr, "No such entry %d\n", which); - else - { - free (entry->line); - free (entry); - } - } - else - { - fprintf (stderr, "non-numeric arg given to `delete'\n"); - } - } - } - } - - -File: history.info, Node: Concept Index, Next: Function and Variable Index, Prev: Programming with GNU History, Up: Top - -Concept Index -************* - -* Menu: - -* anchored search: Searching the History List. -* event designators: Event Designators. -* expansion: History Interaction. -* history events: Event Designators. -* History Searching: Searching the History List. - - -File: history.info, Node: Function and Variable Index, Prev: Concept Index, Up: Top - -Function and Variable Index -*************************** - -* Menu: - -* add_history: History List Management. -* append_history: Managing the History File. -* current_history: Information About the History List. -* get_history_event: History Expansion. -* history_arg_extract: History Expansion. -* history_base: History Variables. -* history_comment_char: History Variables. -* history_expand: History Expansion. -* history_expansion_char: History Variables. -* history_get: Information About the History List. -* history_get_history_state: Initializing History and State Management. -* history_is_stifled: History List Management. -* history_length: History Variables. -* history_list: Information About the History List. -* history_no_expand_chars: History Variables. -* history_search: Searching the History List. -* history_search_pos: Searching the History List. -* history_search_prefix: Searching the History List. -* history_set_history_state: Initializing History and State Management. -* history_set_pos: Moving Around the History List. -* history_subst_char: History Variables. -* history_tokenize: History Expansion. -* history_total_bytes: Information About the History List. -* history_truncate_file: Managing the History File. -* max_input_history: History Variables. -* next_history: Moving Around the History List. -* previous_history: Moving Around the History List. -* read_history: Managing the History File. -* read_history_range: Managing the History File. -* remove_history: History List Management. -* replace_history_entry: History List Management. -* stifle_history: History List Management. -* unstifle_history: History List Management. -* using_history: Initializing History and State Management. -* where_history: Information About the History List. -* write_history: Managing the History File. - - - -Tag Table: -Node: Top975 -Node: Using History Interactively1569 -Node: History Interaction2077 -Node: Event Designators3122 -Node: Word Designators3952 -Node: Modifiers4936 -Node: Programming with GNU History6065 -Node: Introduction to History6791 -Node: History Storage8112 -Node: History Functions9205 -Node: Initializing History and State Management10176 -Node: History List Management10968 -Node: Information About the History List12396 -Node: Moving Around the History List13702 -Node: Searching the History List14587 -Node: Managing the History File16419 -Node: History Expansion17925 -Node: History Variables19769 -Node: History Programming Example21138 -Node: Concept Index23742 -Node: Function and Variable Index24223 - -End Tag Table diff --git a/lib/readline/doc/readline.ps b/lib/readline/doc/readline.ps deleted file mode 100644 index 839598f..0000000 --- a/lib/readline/doc/readline.ps +++ /dev/null @@ -1,2037 +0,0 @@ -%!PS-Adobe-2.0 -%%Creator: dvipsk 5.490s Copyright 1986, 1992 Radical Eye Software -%%Title: history.dvi -%%Pages: 22 1 -%%BoundingBox: 0 0 612 792 -%%EndComments -%DVIPSCommandLine: dvips -D 300 -o history.ps history.dvi -%%BeginProcSet: tex.pro -%! -/TeXDict 250 dict def TeXDict begin /N{def}def /B{bind def}N /S{exch}N /X{S N} -B /TR{translate}N /isls false N /vsize 11 72 mul N /@rigin{isls{[0 -1 1 0 0 0] -concat}if 72 Resolution div 72 VResolution div neg scale isls{Resolution hsize --72 div mul 0 TR}if Resolution VResolution vsize -72 div 1 add mul TR matrix -currentmatrix dup dup 4 get round 4 exch put dup dup 5 get round 5 exch put -setmatrix}N /@landscape{/isls true N}B /@manualfeed{statusdict /manualfeed -true put}B /@copies{/#copies X}B /FMat[1 0 0 -1 0 0]N /FBB[0 0 0 0]N /nn 0 N -/IE 0 N /ctr 0 N /df-tail{/nn 8 dict N nn begin /FontType 3 N /FontMatrix -fntrx N /FontBBox FBB N string /base X array /BitMaps X /BuildChar{ -CharBuilder}N /Encoding IE N end dup{/foo setfont}2 array copy cvx N load 0 nn -put /ctr 0 N[}B /df{/sf 1 N /fntrx FMat N df-tail}B /dfs{div /sf X /fntrx[sf 0 -0 sf neg 0 0]N df-tail}B /E{pop nn dup definefont setfont}B /ch-width{ch-data -dup length 5 sub get}B /ch-height{ch-data dup length 4 sub get}B /ch-xoff{128 -ch-data dup length 3 sub get sub}B /ch-yoff{ch-data dup length 2 sub get 127 -sub}B /ch-dx{ch-data dup length 1 sub get}B /ch-image{ch-data dup type -/stringtype ne{ctr get /ctr ctr 1 add N}if}B /id 0 N /rw 0 N /rc 0 N /gp 0 N -/cp 0 N /G 0 N /sf 0 N /CharBuilder{save 3 1 roll S dup /base get 2 index get -S /BitMaps get S get /ch-data X pop /ctr 0 N ch-dx 0 ch-xoff ch-yoff ch-height -sub ch-xoff ch-width add ch-yoff setcachedevice ch-width ch-height true[1 0 0 --1 -.1 ch-xoff sub ch-yoff .1 add]{ch-image}imagemask restore}B /D{/cc X dup -type /stringtype ne{]}if nn /base get cc ctr put nn /BitMaps get S ctr S sf 1 -ne{dup dup length 1 sub dup 2 index S get sf div put}if put /ctr ctr 1 add N} -B /I{cc 1 add D}B /bop{userdict /bop-hook known{bop-hook}if /SI save N @rigin -0 0 moveto /V matrix currentmatrix dup 1 get dup mul exch 0 get dup mul add -.99 lt{/FV}{/RV}ifelse load def pop}N /eop{SI restore showpage userdict -/eop-hook known{eop-hook}if}N /@start{userdict /start-hook known{start-hook} -if /VResolution X /Resolution X 1000 div /DVImag X /IE 256 array N 0 1 255{IE -S 1 string dup 0 3 index put cvn put}for 65781.76 div /vsize X 65781.76 div -/hsize X}N /p{show}N /RMat[1 0 0 -1 0 0]N /BDot 260 string N /rulex 0 N /ruley -0 N /v{/ruley X /rulex X V}B /V{}B /RV statusdict begin /product where{pop -product dup length 7 ge{0 7 getinterval dup(Display)eq exch 0 4 getinterval -(NeXT)eq or}{pop false}ifelse}{false}ifelse end{{gsave TR -.1 -.1 TR 1 1 scale -rulex ruley false RMat{BDot}imagemask grestore}}{{gsave TR -.1 -.1 TR rulex -ruley scale 1 1 false RMat{BDot}imagemask grestore}}ifelse B /FV{gsave -transform round exch round exch itransform moveto rulex 0 rlineto 0 ruley neg -rlineto rulex neg 0 rlineto fill grestore}B /a{moveto}B /delta 0 N /tail{dup -/delta X 0 rmoveto}B /M{S p delta add tail}B /b{S p tail}B /c{-4 M}B /d{-3 M} -B /e{-2 M}B /f{-1 M}B /g{0 M}B /h{1 M}B /i{2 M}B /j{3 M}B /k{4 M}B /w{0 -rmoveto}B /l{p -4 w}B /m{p -3 w}B /n{p -2 w}B /o{p -1 w}B /q{p 1 w}B /r{p 2 w} -B /s{p 3 w}B /t{p 4 w}B /x{0 S rmoveto}B /y{3 2 roll p a}B /bos{/SS save N}B -/eos{SS restore}B end -%%EndProcSet -TeXDict begin 40258431 52099146 1000 300 300 @start /Fa 1 59 -df<70F8F8F87005057C840D>58 D E /Fb 1 59 df<78FCFCFCFC7806067B8510>58 -D E /Fc 24 123 df<1FC0007FF000707800201800001C00001C0007FC001FFC003C1C00701C00 -E01C00E01C00E01C00707C003FFF800F8F8011107E8F14>97 DI<03F80FFC1C1C380870006000E000E0 -00E000E00060007000380E1C1E0FFC03F00F107E8F14>I<007E00007E00000E00000E00000E00 -000E00000E0007CE000FFE001C3E00301E00700E00E00E00E00E00E00E00E00E00E00E00E00E00 -700E00301E00383E001FEFC007CFC012177F9614>I<07E00FF01C38301C700CE00EE00EFFFEFF -FEE00060007000380E1C1E0FFC03F00F107E8F14>I<007C00FE01CE03840380038003807FFEFF -FE0380038003800380038003800380038003800380038003807FFC7FFC0F177F9614>I<07CF00 -1FFF80383B80301800701C00701C00701C003018003838003FF00037C0007000007000003FF800 -1FFC003FFE00700F00E00380E00380E00380E003807007003C1E001FFC0007F00011197F8F14> -II<03 -0007800780030000000000000000007F807F800380038003800380038003800380038003800380 -03800380FFFCFFFC0E187D9714>I107 DIII<07C01FF03C78701C701CE00EE00EE00EE0 -0EE00EE00E701C783C3C781FF007C00F107E8F14>II -114 D<0FD83FF86038C038C038F0007F803FF007F8001C6006E006F006F81CFFF8CFE00F107E8F -14>I<030007000700070007007FFCFFFC07000700070007000700070007000700070E070E070E -070C03FC00F00F157F9414>IIII<7E3F007E3F001E38000E780007700007E0 -0003E00001C00003C00003E0000770000E78000E38001C1C00FE3F80FE3F8011107F8F14>II< -3FFF7FFF700E701C7038007000E001C0038007000E001C0738077007FFFFFFFF10107F8F14>I -E /Fd 1 59 df<60F0F06004047D830B>58 D E /Fe 25 122 df<078018603030303060186018 -E01CE01CE01CE01CE01CE01CE01CE01CE01CE01CE01CE01C6018601870383030186007800E187E -9713>48 D<03000700FF0007000700070007000700070007000700070007000700070007000700 -070007000700070007000700FFF00C187D9713>I<0F80106020304038803CC01CE01C401C003C -003800380070006000C001800100020004040804100430083FF87FF8FFF80E187E9713>I<01E0 -06100C1818383038300070006000E000E7C0E860F030F018E018E01CE01CE01C601C601C701830 -183030186007C00E187E9713>54 D<40007FFE7FFC7FFC40088010801080200040004000800180 -01800100030003000300030007000700070007000700070002000F197E9813>I<078018603030 -201860186018601870103C303E600F8007C019F030F86038401CC00CC00CC00CC00C6008201018 -600FC00E187E9713>I<07801860303070306018E018E018E01CE01CE01C601C603C303C185C0F -9C001C00180018003870307060604021801F000E187E9713>I72 -D<0FC21836200E6006C006C002C002C002E00070007E003FE01FF807FC003E000E000700038003 -80038003C002C006E004D81887E0101A7E9915>83 D<3F8070C070E020700070007007F01C7030 -707070E070E071E071E0F171FB1E3C10107E8F13>97 D<07F80C1C381C30087000E000E000E000 -E000E000E0007000300438080C1807E00E107F8F11>99 D<007E00000E00000E00000E00000E00 -000E00000E00000E00000E00000E0003CE000C3E00380E00300E00700E00E00E00E00E00E00E00 -E00E00E00E00E00E00600E00700E00381E001C2E0007CFC0121A7F9915>I<07C01C3030187018 -600CE00CFFFCE000E000E000E0006000300438080C1807E00E107F8F11>I<0FCE187330307038 -703870387038303018602FC02000600070003FF03FFC1FFE600FC003C003C003C0036006381C07 -E010187F8F13>103 DI<18003C003C001800000000000000000000000000FC00 -1C001C001C001C001C001C001C001C001C001C001C001C001C001C00FF80091A80990A>I110 D<07E01C38300C700E6006E007E007E007E007E007E00760 -06700E381C1C3807E010107F8F13>II114 D<1F2060E04020C020C020F0007F003FC01FE000F0807080 -30C030C020F0408F800C107F8F0F>I<0400040004000C000C001C003C00FFC01C001C001C001C -001C001C001C001C001C201C201C201C201C200E4003800B177F960F>I118 D120 DI E /Ff 2 42 -df<007000E001C00380078007000E001E001E003C003C003C0078007800780078007000F000F0 -00F000F000F000F000F000F000F000F000F000F000700078007800780078003C003C003C001E00 -1E000E0007000780038001C000E000700C2E7EA112>40 DI E /Fg 25 123 df<0007F800007FFC0001FC0E0003F01F0007E03F000FC03F000F -C03F000FC03F000FC01E000FC00C000FC000000FC000000FC0FF80FFFFFF80FFFFFF800FC01F80 -0FC01F800FC01F800FC01F800FC01F800FC01F800FC01F800FC01F800FC01F800FC01F800FC01F -800FC01F800FC01F800FC01F800FC01F800FC01F800FC01F800FC01F807FF8FFF07FF8FFF01C23 -7FA220>12 D<000FFF80007FFF8001FC1F8003F03F8007E03F800FC03F800FC01F800FC01F800F -C01F800FC01F800FC01F800FC01F800FC01F80FFFFFF80FFFFFF800FC01F800FC01F800FC01F80 -0FC01F800FC01F800FC01F800FC01F800FC01F800FC01F800FC01F800FC01F800FC01F800FC01F -800FC01F800FC01F800FC01F800FC01F800FC01F807FF8FFF07FF8FFF01C237FA220>I<07FE00 -001FFF80003F07E0003F03F0003F01F0003F01F8001E01F8000001F8000001F800003FF80003FD -F8001F81F8003E01F8007C01F800F801F800F801F800F801F800F801F8007C02F8007E0CF8001F -F87F8007E03F8019167E951C>97 DI<00FF8007FFE00F83F01F03F03E03F07E03F07C01E07C0000FC0000FC0000FC0000 -FC0000FC0000FC00007C00007E00007E00003F00301F00600FC0E007FF8000FE0014167E9519> -I<0001FF000001FF0000003F0000003F0000003F0000003F0000003F0000003F0000003F000000 -3F0000003F0000003F0000003F0000FE3F0007FFBF000FC1FF001F007F003E003F007E003F007C -003F007C003F00FC003F00FC003F00FC003F00FC003F00FC003F00FC003F00FC003F007C003F00 -7E003F003E003F001F007F000F81FF0007FF3FE001FC3FE01B237EA220>I<00FE0007FF800F83 -C01F01E03E00F07E00F07C00F87C0078FC0078FFFFF8FFFFF8FC0000FC0000FC00007C00007C00 -003E00183E00181F00300F80E003FFC000FF0015167E951A>I<00FE0F8003FF9FC00F83E3C01F -01F3C01E00F0003E00F8003E00F8003E00F8003E00F8003E00F8001E00F0001F01F0000F83E000 -0BFF800008FE000018000000180000001C0000001FFFE0001FFFFC000FFFFF0007FFFF001FFFFF -807C001FC078000FC0F80007C0F80007C0F80007C07C000F803E001F001F807E000FFFFC0001FF -E0001A217F951D>103 DI<1E003F007F807F807F807F803F001E00000000000000000000000000FF80FF801F801F801F -801F801F801F801F801F801F801F801F801F801F801F801F801F801F801F80FFF0FFF00C247EA3 -0F>I107 -DI< -FF03F803F800FF0FFE0FFE001F183F183F001F201F201F001F401FC01F801F401FC01F801F801F -801F801F801F801F801F801F801F801F801F801F801F801F801F801F801F801F801F801F801F80 -1F801F801F801F801F801F801F801F801F801F801F801F801F801F801F801F801F801F801F801F -801F80FFF0FFF0FFF0FFF0FFF0FFF02C167D9531>II< -00FF0007FFE00F81F01F00F83E007C7C003E7C003E7C003EFC003FFC003FFC003FFC003FFC003F -FC003FFC003F7C003E7E007E3E007C1F00F80F81F007FFE000FF0018167E951D>II114 D<07F9801FFF80380780700380F00180F00180F80000FF0000FFF8007FFE -003FFF001FFF8007FF80003FC0C007C0C003C0E003C0E003C0F00380FC0F00EFFE00C3F8001216 -7E9517>I<00C00000C00000C00000C00001C00001C00003C00007C0000FC0001FC000FFFF00FF -FF000FC0000FC0000FC0000FC0000FC0000FC0000FC0000FC0000FC0000FC0000FC0000FC1800F -C1800FC1800FC1800FC18007C18007E30003FE0000FC0011207F9F16>IIIIII<7FFFE07FFFE0780FC0701FC0601F80E03F00 -C07F00C07E00C0FC0001FC0001F80003F00007F03007E0300FC0301FC0701F80703F00607F00E0 -7E03E0FFFFE0FFFFE014167E9519>I E /Fh 22 119 df<00E00000E00000E00000E00040E040 -F0E1E0F8E3E07EEFC01FFF0007FC0003F80007FC001FFF007EEFC0F8E3E0F0E1E040E04000E000 -00E00000E00000E00013157D991A>42 D<003800007C00007C00006C0000EE0000EE0000EE0000 -EE0000C60001C70001C70001C70001C7000383800383800383800383800783C00701C007FFC007 -FFC007FFC00E00E00E00E00E00E00E00E01C00707F83FCFF83FE7F83FC171E7F9D1A>65 -D<7FFFFCFFFFFC7FFFFC0E001C0E001C0E001C0E001C0E001C0E00000E00000E07000E07000E07 -000FFF000FFF000FFF000E07000E07000E07000E00000E00000E00000E000E0E000E0E000E0E00 -0E0E000E7FFFFEFFFFFE7FFFFE171E7F9D1A>69 D -72 DI78 D<0FFE003FFF807FFFC07C07C07001C0F001E0E000E0E000E0E000E0E000E0E000E0E000E0 -E000E0E000E0E000E0E000E0E000E0E000E0E000E0E000E0E000E0E000E0E000E0F001E0F001E0 -7001C07C07C07FFFC03FFF800FFE00131E7D9D1A>I82 D<03F1C00FFDC03FFFC07C0FC07003C0E003C0E001C0E001C0E001C0E00000700000780000 -3F00001FF00007FE0000FF00000F800003C00001C00000E00000E06000E0E000E0E000E0E001C0 -F001C0FC0780FFFF80EFFE00E3F800131E7D9D1A>I<7FFFFEFFFFFEFFFFFEE0380EE0380EE038 -0EE0380EE0380E0038000038000038000038000038000038000038000038000038000038000038 -0000380000380000380000380000380000380000380000380003FF8007FFC003FF80171E7F9D1A ->I89 D<7FFFC0FFFFE0FFFFE07FFFC013047D7E1A ->95 D<1FF0003FFC007FFE00780F00300700000380000380007F8007FF801FFF803F8380780380 -700380E00380E00380E00380700780780F803FFFFC1FFDFC07F0FC16157D941A>97 -D<00FF8003FFC00FFFE01F01E03C00C0780000700000700000E00000E00000E00000E00000E000 -007000007000007800703C00701F01F00FFFE003FFC000FE0014157D941A>99 -D<001FC0001FC0001FC00001C00001C00001C00001C00001C00001C001F1C007FDC00FFFC01E0F -C03C07C07803C07001C0E001C0E001C0E001C0E001C0E001C0E001C0E001C07003C07003C03807 -C03E0FC01FFFFC07FDFC01F1FC161E7E9D1A>I -104 D<01C00003E00003E00003E00001C0000000000000000000000000000000007FE000FFE000 -7FE00000E00000E00000E00000E00000E00000E00000E00000E00000E00000E00000E00000E000 -00E00000E00000E000FFFFC0FFFFC0FFFFC0121F7C9E1A>I110 D<01F00007FC001FFF003E0F803C07807803C07001 -C0E000E0E000E0E000E0E000E0E000E0E000E0F001E07001C07803C03C07803E0F801FFF0007FC -0001F00013157D941A>I114 D<00C00001C00001C00001C00001C00001C00001C0007FFFE0FFFFE0FFFFE001C00001 -C00001C00001C00001C00001C00001C00001C00001C00001C00001C07001C07001C07001C07000 -E0E000FFE0007FC0001F00141C7F9B1A>116 D<7FC7FCFFC7FE7FC7FC0E00E00E00E00F01E007 -01C00701C00783C003838003838003838001C70001C70001C70000EE0000EE0000EE00007C0000 -7C0000380017157F941A>118 D E /Fi 41 123 df<0003FC00003FFE00007E070001F80F8003 -F01F8003E01F8007E01F8007E01F8007E01F8007E0060007E0000007E0000007E0000007E0FFC0 -FFFFFFC0FFFFFFC007E00FC007E00FC007E00FC007E00FC007E00FC007E00FC007E00FC007E00F -C007E00FC007E00FC007E00FC007E00FC007E00FC007E00FC007E00FC007E00FC007E00FC007E0 -0FC007E00FC007E00FC07FFC7FFC7FFC7FFC1E267FA522>12 D<3C7EFFFFFFFF7E3C08087C8711 ->46 D<001C00003C0000FC00FFFC00FFFC0000FC0000FC0000FC0000FC0000FC0000FC0000FC00 -00FC0000FC0000FC0000FC0000FC0000FC0000FC0000FC0000FC0000FC0000FC0000FC0000FC00 -00FC0000FC0000FC0000FC0000FC0000FC0000FC0000FC007FFFFC7FFFFC16237CA21F>49 -D<01FF0007FFC01E07F03803F86001FC7C00FEFE00FEFE00FFFE007FFE007F7C007F3800FF0000 -FF0000FE0000FE0001FC0001F80003F00007E0000780000F00001E00003C0000700000E00301C0 -030380070700060600060FFFFE1FFFFE3FFFFE7FFFFCFFFFFCFFFFFC18237DA21F>I<01FF0007 -FFE01E03F03801F83C01FC7E00FE7E00FE7E00FE3E00FE1C01FE0001FC0001FC0003F80007F000 -0FC001FF0001FF000007E00001F00001F80000FC0000FE0000FF0000FF1000FF7C00FFFE00FFFE -00FFFE00FEFE00FE7C01FC7001F83E07F00FFFC001FF0018237DA21F>I<000038000000780000 -0078000000F8000001F8000003F8000007F8000006F800000CF800001CF8000038F8000030F800 -0060F80000E0F80001C0F8000180F8000300F8000700F8000E00F8001C00F8001800F8003000F8 -007000F800E000F800FFFFFFC0FFFFFFC00001F8000001F8000001F8000001F8000001F8000001 -F8000001F800007FFFC0007FFFC01A237EA21F>I<18000C1F007C1FFFF81FFFF01FFFE01FFFC0 -1FFF801FFE0018000018000018000018000018000018FF001BFFE01F01F01C00F80800FC00007E -00007E00007E00007F00007F78007FFC007FFC007FFC007FFC007EF8007E6000FC7000FC3801F8 -1E07E007FFC001FE0018237DA21F>I<001FC0007FF001F83803E00C07803E0F807E1F007E3F00 -7E3F007E7E003C7E00007E00007E0000FE3FC0FE7FF0FE80F8FF80FCFF007CFF007EFE007EFE00 -7FFE007FFE007FFE007F7E007F7E007F7E007F7E007F3E007E3F007E1F007C0F80F807C1F003FF -C0007F0018237DA21F>I<300000003C0000003FFFFFC03FFFFFC03FFFFF807FFFFF007FFFFE00 -7FFFFC006000180060001800E0003000C0006000C000C000000180000001800000030000000700 -0000060000000E0000001E0000001E0000001E0000003C0000003C0000007C0000007C0000007C -0000007C000000FC000000FC000000FC000000FC000000FC000000FC000000FC00000078000000 -3000001A257DA41F>I<00001C00000000001C00000000003E00000000003E00000000003E0000 -0000007F00000000007F0000000000FF8000000000FF8000000000FF80000000019FC000000001 -9FC0000000031FE0000000030FE0000000030FE00000000607F00000000607F00000000C07F800 -00000C03F80000001C03FC0000001801FC0000001801FC0000003001FE0000003000FE0000007F -FFFF0000007FFFFF00000060007F000000C0007F800000C0003F800001C0003FC0000180001FC0 -000180001FC0000300000FE0000300000FE0000780000FF000FFF801FFFF80FFF801FFFF802925 -7EA42E>65 D -68 DI< -FFFFFFFE00FFFFFFFE0003F800FE0003F8001F0003F8000F0003F800070003F800070003F80003 -0003F800030003F800030003F800018003F806018003F806018003F806000003F806000003F80E -000003F81E000003FFFE000003FFFE000003F81E000003F80E000003F806000003F806000003F8 -06000003F806000003F800000003F800000003F800000003F800000003F800000003F800000003 -F800000003F800000003F800000003F8000000FFFFF00000FFFFF0000021257EA427>I72 -DI -76 DI<00FF0080 -07FFE3800F80F7801E001F803C000F807800078078000380F8000380F8000180F8000180FC0001 -80FC000000FF0000007FE000007FFF00003FFFE0003FFFF8001FFFFE0007FFFF0003FFFF80007F -FF800003FFC000003FC000000FE0000007E0000007E0C00003E0C00003E0C00003E0C00003C0E0 -0003C0F00007C0F8000780FC000F00FFC03E00E3FFF800803FE0001B257DA422>83 -D87 -D<07FF00001FFFC0003E03E0003F01F0003F01F8003F00FC001E00FC000000FC000000FC000000 -FC00003FFC0003FCFC000FC0FC003F00FC007E00FC007E00FC00FC00FC00FC00FC00FC00FC00FC -017C007E017C003F067C001FFC3FE007F01FE01B187E971E>97 DI<007FE003FFF807C07C -1F80FC1F00FC3F00FC7E00787E0000FE0000FE0000FE0000FE0000FE0000FE0000FE0000FE0000 -7E00007F00003F000C1F800C1FC01807E07003FFE0007F0016187E971B>I<0001FF800001FF80 -00001F8000001F8000001F8000001F8000001F8000001F8000001F8000001F8000001F8000001F -8000001F8000001F80007F1F8003FFDF8007E0FF801F803F803F001F803F001F807E001F807E00 -1F80FE001F80FE001F80FE001F80FE001F80FE001F80FE001F80FE001F80FE001F807E001F807E -001F803F001F803F003F801F807F800FC0FF8003FF9FF800FE1FF81D267EA522>I<007F0003FF -C007C1F00F80F81F00F83F007C7E007C7E007EFE007EFE007EFFFFFEFFFFFEFE0000FE0000FE00 -007E00007E00007E00063F00061F000C0F801807E07003FFE0007F8017187E971C>I<000FC000 -7FF000F8F001F1F803F1F803E1F807E0F007E00007E00007E00007E00007E00007E00007E000FF -FF00FFFF0007E00007E00007E00007E00007E00007E00007E00007E00007E00007E00007E00007 -E00007E00007E00007E00007E00007E00007E00007E00007E0007FFF007FFF0015267EA513>I< -01FF07C007FFDFE00F83F1E01F01F1E03E00F8007E00FC007E00FC007E00FC007E00FC007E00FC -007E00FC003E00F8001F01F0000F83E0000FFFC00011FF00003000000030000000380000003C00 -00003FFFE0001FFFFC001FFFFE000FFFFF001FFFFF803C003F8078000FC0F80007C0F80007C0F8 -0007C0F80007C07C000F803E001F001F807E0007FFF80000FFC0001B247E971F>II<0F00 -1F803FC03FC03FC03FC01F800F000000000000000000000000000000FFC0FFC00FC00FC00FC00F -C00FC00FC00FC00FC00FC00FC00FC00FC00FC00FC00FC00FC00FC00FC00FC00FC0FFF8FFF80D27 -7EA611>I108 DII<007F800003FFF0 -0007C0F8001F807E003F003F003F003F007E001F807E001F80FE001FC0FE001FC0FE001FC0FE00 -1FC0FE001FC0FE001FC0FE001FC0FE001FC07E001F807E001F803F003F003F003F001F807E000F -C0FC0003FFF000007F80001A187E971F>II114 D<07F9801FFF803C0F80700380F00180F00180F00180FC0000FF8000 -7FFC007FFE003FFF800FFFC003FFC0001FE00003E0C001E0C001E0E001E0E001C0F003C0FC0780 -EFFF00C3FC0013187E9718>I<00600000600000600000600000E00000E00001E00001E00003E0 -0007E0001FE000FFFFC0FFFFC007E00007E00007E00007E00007E00007E00007E00007E00007E0 -0007E00007E00007E00007E06007E06007E06007E06007E06007E06003E0C003F0C001FF80007E -0013237FA218>III120 DI<3FFF -F83FFFF83E03F03807F0300FE0700FC0701F80603F80603F00607E0000FE0000FC0001F80003F8 -1803F01807E0180FE0180FC0381F80303F80707F00707E01F0FFFFF0FFFFF015187E971B>I -E /Fj 29 122 df<0003F07C001E0DC600380F0F00701E0F00E01E0E00E00C0001C01C0001C01C -0001C01C0001C01C0001C01C00038038007FFFFFC0038038000380380003803800038038000700 -700007007000070070000700700007007000070070000E00E0000E00E0000E00E0000E00E0000E -00E0000E00E0001C01C0001E01E000FF8FFE0020207E9F1B>11 D<0003E0001C1800381800703C -00E03C00E03801C00001C00001C00001C00001C0000380007FFFF0038070038070038070038070 -0700E00700E00700E00700E00700E00700E00E01C00E01C00E01C00E01C00E01C00E01C01C0380 -1E03C0FF0FF816207E9F19>I<0003F03F00001E09E08000380F80C000701F01E000E03E01E000 -E01E01C001C01C000001C01C000001C01C000001C01C000001C01C000003803800007FFFFFFF80 -038038038003803803800380380380038038038007007007000700700700070070070007007007 -00070070070007007007000E00E00E000E00E00E000E00E00E000E00E00E000E00E00E000E00E0 -0E001C01C01C001E01E01E00FF8FF8FFC023207E9F26>14 D<0020000060000060000060000060 -007061C03843800E4E0007580001E00001E00006B8001C9C00708700E083800180000180000180 -0001800001000012147AA117>42 D45 D<000C001C00FC0F3800380038 -00380038003800700070007000700070007000E000E000E000E000E000E001C001C001C001C001 -C001C0038003C0FFFE0F1E7C9D17>49 D<003F8000C1E00100F00200780400780400780F007C0F -807C0F807C0F00780600780000F80000F00001E00001C0000380000700000E00001C0000380000 -600000C0000180000300200600200800401000403FFFC07FFF80FFFF80161E7E9D17>I<07F800 -0C0C001E06001E07001C070000070000070000070000FF0007C7001E07003C0E00780E00F00E10 -F00E10F00E10F01E10F02E20784F401F878014147D9317>97 D<01FC07060E0F1C0F380E780070 -00F000F000F000F000E000E000E000E000F0027004300818300FC010147C9314>99 -D<0000700003F00000F00000700000700000E00000E00000E00000E00000E00000E00001C000F9 -C00305C00E03C01C03C03801C0780380700380F00380F00380F00380F00380E00700E00700E007 -00E00700E00700700F00301E00186F000F8FE014207C9F19>I<00F800070E000E07001C070038 -0380780380700380F00380F00380FFFF80F00000E00000E00000E00000E00000F0010070020030 -04001C180007E00011147D9314>I<0007800018C00031E00061E000E1C000C00001C00001C000 -01C00001C00001C0000380007FF800038000038000038000038000070000070000070000070000 -0700000700000E00000E00000E00000E00000E00000E00001C00001E0000FFE00013207E9F0E> -I<00000E003E1100E1A301C1C20381E00780E00701E00F01E00F01E00F01E00703C00703800787 -0004FC000800000800001800001C00000FFF000FFFC007FFE01800F0300030600030C00030C000 -30C000306000603000C01C070007FC00181F809417>I<00E00007E00001E00000E00000E00001 -C00001C00001C00001C00001C00001C000038000038F800390E003A0E003C0600380600780E007 -00E00700E00700E00700E00700E00E01C00E01C00E01C00E01C00E01C00E01C01C03801E03C0FF -CFF815207E9F19>I<01C003E003E003C0018000000000000000000000000003801F8007800380 -03800700070007000700070007000E000E000E000E000E000E001C001E00FF800B1F7F9E0C>I< -00E007E001E000E000E001C001C001C001C001C001C00380038003800380038003800700070007 -000700070007000E000E000E000E000E000E001C001E00FFC00B207F9F0C>108 -D<0387C07C001F9861860007A072070003C0340300038038030007807807000700700700070070 -07000700700700070070070007007007000E00E00E000E00E00E000E00E00E000E00E00E000E00 -E00E000E00E00E001C01C01C001E01E01E00FFCFFCFFC022147E9326>I<038F801F90E007A0E0 -03C0600380600780E00700E00700E00700E00700E00700E00E01C00E01C00E01C00E01C00E01C0 -0E01C01C03801E03C0FFCFF815147E9319>I<00FC000387000E01801C00C03800E03800E07000 -F0F000F0F000F0F000F0F000F0E001E0E001E0E001C0E003C0F00380700700380E001C1C0007E0 -0014147D9317>I<00E3E007EC3800F01C00E01E00E00E01C00E01C00F01C00F01C00F01C00F01 -C00F03801E03801E03801C03803C0380380380700740E00721C0071F000700000700000700000E -00000E00000E00000E00001E0000FFC000181D809319>I<00F040038CC00E04C01C03C03C03C0 -780380780380F00380F00380F00380F00380E00700E00700E00700F00700F00F00700F00301E00 -186E000F8E00000E00000E00000E00001C00001C00001C00001C00003C0001FF80121D7C9318> -I<038E001FB38007C78003C7800383000780000700000700000700000700000700000E00000E00 -000E00000E00000E00000E00001C00001E0000FFE00011147E9312>I<01F2060E080618061802 -380438001E001FE00FF003F8003C401C400C400C600C6018E010D0608FC00F147E9312>I<0080 -010001000100030007000F001E00FFF80E000E000E000E001C001C001C001C001C001C00380038 -203820382038203840384018800F000D1C7C9B12>I<1C0380FC1F803C07801C03801C03803807 -00380700380700380700380700380700700E00700E00700E00700E00701E00701E00703C00305E -001F9FC012147B9319>II< -FF9FE1FC3E0780701C0300601C0300401C0380401C0380800E0780800E0581000E0981000E09C2 -000E11C2000731C4000721C4000760C8000740C8000780F0000780F0000300E000030060000200 -40001E147C9321>I<1FF0FF03C07801C06001C04000E08000E180007300007600003C00003C00 -001C00002E00004E000087000107000203800603800C01C03E03E0FF07FC18147F9318>I<0FF8 -3F8001E00E0001C00C0001C0080000E0180000E0100000E0200000E0200000F040000070400000 -708000007080000071000000390000003A0000003E0000003C0000003800000018000000100000 -0010000000200000002000000040000070C00000F0800000F1000000E20000007C000000191D80 -9318>I E /Fk 36 122 df<0001C0000003C000000FC000007FC0001FFFC000FFFFC000FFBFC0 -00E03FC000003FC000003FC000003FC000003FC000003FC000003FC000003FC000003FC000003F -C000003FC000003FC000003FC000003FC000003FC000003FC000003FC000003FC000003FC00000 -3FC000003FC000003FC000003FC000003FC000003FC000003FC000003FC000003FC000003FC000 -003FC000003FC000003FC000003FC000003FC000003FC000003FC0007FFFFFE07FFFFFE07FFFFF -E01B2E7AAD28>49 D<003FE00001FFFE0007FFFF800F80FFC01E003FE038001FF07C000FF87E00 -07FCFF0007FCFF8007FEFF8007FEFF8003FEFF8003FE7F0003FE3E0007FE000007FE000007FC00 -0007FC00000FF800000FF800000FF000001FE000001FC000003F8000007F0000007E000000F800 -0001F0000003E0000007C000000F0000001E000E003C000E0038000E0070001E00E0001C01C000 -1C0300003C07FFFFFC0FFFFFFC1FFFFFFC3FFFFFFC7FFFFFF8FFFFFFF8FFFFFFF8FFFFFFF81F2E -7CAD28>I<0000007800000000000078000000000000FC000000000000FC000000000000FC0000 -00000001FE000000000001FE000000000003FF000000000003FF000000000007FF800000000007 -FF800000000007FF80000000000FFFC0000000000E7FC0000000001E7FE0000000001C3FE00000 -00001C3FE000000000383FF000000000381FF000000000781FF800000000700FF800000000700F -F800000000E00FFC00000000E007FC00000001E007FE00000001C003FE00000001C003FE000000 -038003FF000000038001FF000000078001FF800000070000FF800000070000FF8000000FFFFFFF -C000000FFFFFFFC000001FFFFFFFE000001C00003FE000003C00003FF000003800001FF0000038 -00001FF000007000001FF800007000000FF80000F000000FFC0000E0000007FC0000E0000007FC -0001C0000007FE0003E0000003FE00FFFF8001FFFFFCFFFF8001FFFFFCFFFF8001FFFFFC36317D -B03D>65 DI<000003FF80018000003FFFF003800001FFFFFC07800007FF003F0F80001FF800079F80 -003FC00001FF8000FF800000FF8001FE0000007F8003FC0000003F8007FC0000001F8007F80000 -000F800FF00000000F801FF000000007801FF000000007803FE000000007803FE000000003807F -E000000003807FE000000003807FC000000000007FC00000000000FFC00000000000FFC0000000 -0000FFC00000000000FFC00000000000FFC00000000000FFC00000000000FFC00000000000FFC0 -0000000000FFC000000000007FC000000000007FC000000000007FE000000000007FE000000003 -803FE000000003803FE000000003801FF000000003801FF000000007800FF0000000070007F800 -0000070007FC0000000E0003FC0000001E0001FE0000001C0000FF8000007800003FC00000F000 -001FF80003E0000007FF003F80000001FFFFFE000000003FFFF80000000003FF80000031317CB0 -3A>I70 -D<000003FF00030000007FFFF007000001FFFFFC0F000007FF007E1F00001FF0000FBF00007FC0 -0003FF0000FF800001FF0001FE0000007F0003FC0000007F0007FC0000003F000FF80000001F00 -0FF00000001F001FF00000000F001FF00000000F003FE000000007003FE000000007007FE00000 -0007007FE000000007007FC00000000000FFC00000000000FFC00000000000FFC00000000000FF -C00000000000FFC00000000000FFC00000000000FFC00000000000FFC00000000000FFC0000000 -0000FFC00000000000FFC00007FFFFFC7FC00007FFFFFC7FE00007FFFFFC7FE0000001FF003FE0 -000001FF003FE0000001FF001FF0000001FF001FF0000001FF000FF0000001FF000FF8000001FF -0007FC000001FF0003FC000001FF0001FE000001FF0000FF800001FF00007FC00003FF00001FF8 -00077F000007FF003E3F000001FFFFFC1F0000007FFFF00F00000003FF80030036317CB03F>I< -FFFFFF807FFFFFC0FFFFFF807FFFFFC0FFFFFF807FFFFFC000FF8000007FC00000FF8000007FC0 -0000FF8000007FC00000FF8000007FC00000FF8000007FC00000FF8000007FC00000FF8000007F -C00000FF8000007FC00000FF8000007FC00000FF8000007FC00000FF8000007FC00000FF800000 -7FC00000FF8000007FC00000FF8000007FC00000FF8000007FC00000FF8000007FC00000FF8000 -007FC00000FF8000007FC00000FF8000007FC00000FFFFFFFFFFC00000FFFFFFFFFFC00000FFFF -FFFFFFC00000FF8000007FC00000FF8000007FC00000FF8000007FC00000FF8000007FC00000FF -8000007FC00000FF8000007FC00000FF8000007FC00000FF8000007FC00000FF8000007FC00000 -FF8000007FC00000FF8000007FC00000FF8000007FC00000FF8000007FC00000FF8000007FC000 -00FF8000007FC00000FF8000007FC00000FF8000007FC00000FF8000007FC00000FF8000007FC0 -0000FF8000007FC00000FF8000007FC000FFFFFF807FFFFFC0FFFFFF807FFFFFC0FFFFFF807FFF -FFC03A317EB03F>II78 D80 D<7FFFFFFFFFFF007FFFFFFFFFFF007FFFFFFFFFFF007F -C00FF801FF007E000FF8003F007C000FF8001F0078000FF8000F0078000FF8000F0070000FF800 -0700F0000FF8000780F0000FF8000780F0000FF8000780E0000FF8000380E0000FF8000380E000 -0FF8000380E0000FF8000380E0000FF800038000000FF800000000000FF800000000000FF80000 -0000000FF800000000000FF800000000000FF800000000000FF800000000000FF800000000000F -F800000000000FF800000000000FF800000000000FF800000000000FF800000000000FF8000000 -00000FF800000000000FF800000000000FF800000000000FF800000000000FF800000000000FF8 -00000000000FF800000000000FF800000000000FF800000000000FF800000000000FF800000000 -000FF800000000000FF800000000000FF8000000007FFFFFFF0000007FFFFFFF0000007FFFFFFF -000031307DAF38>84 DII<00FFF0000003FFFE00000F803F80000FC00FE0001F -E007F0001FE007F0001FE003F8000FC003FC00078003FC00000003FC00000003FC00000003FC00 -000003FC000000FFFC00001FFFFC0000FFE3FC0003FC03FC000FF003FC001FC003FC003FC003FC -007F8003FC007F8003FC00FF0003FC00FF0003FC00FF0003FC00FF0007FC00FF0007FC007F800D -FC003FC019FE001FE070FFF007FFE07FF000FF803FF024207E9F27>97 D<01F8000000FFF80000 -00FFF8000000FFF80000000FF800000007F800000007F800000007F800000007F800000007F800 -000007F800000007F800000007F800000007F800000007F800000007F800000007F800000007F8 -00000007F83FE00007F8FFFC0007FBE07F0007FF001F8007FE000FC007FC000FE007F80007F007 -F80007F807F80007F807F80003FC07F80003FC07F80003FC07F80003FE07F80003FE07F80003FE -07F80003FE07F80003FE07F80003FE07F80003FE07F80003FE07F80003FC07F80003FC07F80003 -FC07F80007F807F80007F807F80007F007FC000FE007FE000FC007E7003F8007C3C0FE000780FF -F80007003FC00027327EB12D>I<000FFF00007FFFC001FC01F003F003F007E007F80FE007F81F -C007F83FC003F03FC001E07F8000007F8000007F800000FF800000FF800000FF800000FF800000 -FF800000FF800000FF800000FF8000007F8000007F8000007F8000003FC0001C3FC0001C1FC000 -380FE0003807E0007003F001E001FC07C0007FFF00000FF8001E207D9F24>I<0000000FC00000 -07FFC0000007FFC0000007FFC00000007FC00000003FC00000003FC00000003FC00000003FC000 -00003FC00000003FC00000003FC00000003FC00000003FC00000003FC00000003FC00000003FC0 -0000003FC00007F83FC0003FFF3FC000FE07BFC003F801FFC007E0007FC00FE0007FC01FC0003F -C03FC0003FC03FC0003FC07F80003FC07F80003FC07F80003FC0FF80003FC0FF80003FC0FF8000 -3FC0FF80003FC0FF80003FC0FF80003FC0FF80003FC0FF80003FC07F80003FC07F80003FC07F80 -003FC03FC0003FC03FC0003FC01FC0003FC00FE0007FC007E000FFC003F003FFE001FC0F3FFE00 -7FFE3FFE000FF03FFE27327DB12D>I<000FFC00007FFF8001FC0FC003F003E007E001F00FE001 -F81FC000FC3FC000FE3FC000FE7F80007E7F80007F7F80007FFF80007FFF80007FFFFFFFFFFFFF -FFFFFF800000FF800000FF800000FF8000007F8000007F8000007F8000003FC000071FC000071F -C0000E0FE0000E07F0001C03F8007800FE03E0003FFFC00007FE0020207E9F25>I<0001FE0000 -0FFF80001FC3C0007F07E000FE0FF001FE0FF001FC0FF003FC0FF003FC07E003FC018003FC0000 -03FC000003FC000003FC000003FC000003FC000003FC000003FC0000FFFFFC00FFFFFC00FFFFFC -0003FC000003FC000003FC000003FC000003FC000003FC000003FC000003FC000003FC000003FC -000003FC000003FC000003FC000003FC000003FC000003FC000003FC000003FC000003FC000003 -FC000003FC000003FC000003FC000003FC000003FC000003FC00007FFFF0007FFFF0007FFFF000 -1C327EB119>I<001FF007C000FFFE3FE001F83F79F007E00FC3F00FE00FE1F00FC007E0E01FC0 -07F0001FC007F0003FC007F8003FC007F8003FC007F8003FC007F8003FC007F8001FC007F0001F -C007F0000FC007E0000FE00FE00007E00FC00003F83F000006FFFE00000E1FF000000E00000000 -1E000000001E000000001F000000001F800000001FFFFF80000FFFFFF0000FFFFFFC0007FFFFFE -0003FFFFFF0003FFFFFF800FFFFFFFC01F00007FC07E00001FE07C00000FE0FC000007E0FC0000 -07E0FC000007E0FC000007E07E00000FC03E00000F803F00001F800FC0007E0007F803FC0001FF -FFF000001FFF0000242F7E9F28>I<01F8000000FFF8000000FFF8000000FFF80000000FF80000 -0007F800000007F800000007F800000007F800000007F800000007F800000007F800000007F800 -000007F800000007F800000007F800000007F800000007F800000007F807F80007F83FFE0007F8 -783F0007F8C03F8007F9801FC007FB001FC007FE001FE007FC001FE007FC001FE007FC001FE007 -F8001FE007F8001FE007F8001FE007F8001FE007F8001FE007F8001FE007F8001FE007F8001FE0 -07F8001FE007F8001FE007F8001FE007F8001FE007F8001FE007F8001FE007F8001FE007F8001F -E007F8001FE007F8001FE007F8001FE0FFFFC3FFFFFFFFC3FFFFFFFFC3FFFF28327DB12D>I<03 -C00007E0000FF0001FF8001FF8001FF8001FF8000FF00007E00003C00000000000000000000000 -000000000000000000000000000000000001F800FFF800FFF800FFF8000FF80007F80007F80007 -F80007F80007F80007F80007F80007F80007F80007F80007F80007F80007F80007F80007F80007 -F80007F80007F80007F80007F80007F80007F80007F80007F800FFFF80FFFF80FFFF8011337DB2 -17>I<01F800FFF800FFF800FFF8000FF80007F80007F80007F80007F80007F80007F80007F800 -07F80007F80007F80007F80007F80007F80007F80007F80007F80007F80007F80007F80007F800 -07F80007F80007F80007F80007F80007F80007F80007F80007F80007F80007F80007F80007F800 -07F80007F80007F80007F80007F80007F80007F80007F80007F800FFFFC0FFFFC0FFFFC012327D -B117>108 D<03F007F8001FE000FFF03FFE00FFF800FFF0783F01E0FC00FFF0C03F8300FE000F -F1801FC6007F0007F3001FCC007F0007F6001FF8007F8007FC001FF0007F8007FC001FF0007F80 -07FC001FF0007F8007F8001FE0007F8007F8001FE0007F8007F8001FE0007F8007F8001FE0007F -8007F8001FE0007F8007F8001FE0007F8007F8001FE0007F8007F8001FE0007F8007F8001FE000 -7F8007F8001FE0007F8007F8001FE0007F8007F8001FE0007F8007F8001FE0007F8007F8001FE0 -007F8007F8001FE0007F8007F8001FE0007F8007F8001FE0007F8007F8001FE0007F8007F8001F -E0007F80FFFFC3FFFF0FFFFCFFFFC3FFFF0FFFFCFFFFC3FFFF0FFFFC3E207D9F43>I<03F007F8 -00FFF03FFE00FFF0783F00FFF0C03F800FF1801FC007F3001FC007F6001FE007FC001FE007FC00 -1FE007FC001FE007F8001FE007F8001FE007F8001FE007F8001FE007F8001FE007F8001FE007F8 -001FE007F8001FE007F8001FE007F8001FE007F8001FE007F8001FE007F8001FE007F8001FE007 -F8001FE007F8001FE007F8001FE007F8001FE007F8001FE0FFFFC3FFFFFFFFC3FFFFFFFFC3FFFF -28207D9F2D>I<0007FC0000007FFFC00001FC07F00003F001F80007E000FC000FC0007E001FC0 -007F003FC0007F803F80003F807F80003FC07F80003FC07F80003FC0FF80003FE0FF80003FE0FF -80003FE0FF80003FE0FF80003FE0FF80003FE0FF80003FE0FF80003FE07F80003FC07F80003FC0 -7F80003FC03FC0007F803FC0007F801FC0007F000FE000FE0007E000FC0003F803F80001FE0FF0 -00007FFFC0000007FC000023207E9F28>I<01F83FE000FFF8FFFC00FFFBE07F00FFFF003F8007 -FE001FC007FC000FE007F8000FF007F80007F807F80007F807F80007FC07F80003FC07F80003FC -07F80003FE07F80003FE07F80003FE07F80003FE07F80003FE07F80003FE07F80003FE07F80003 -FE07F80003FC07F80007FC07F80007FC07F80007F807F80007F807F8000FF007FC000FE007FE00 -1FC007FF003F8007FBC0FE0007F8FFF80007F83FC00007F800000007F800000007F800000007F8 -00000007F800000007F800000007F800000007F800000007F800000007F800000007F8000000FF -FFC00000FFFFC00000FFFFC00000272E7E9F2D>I<03F03F00FFF07FC0FFF1C3E0FFF187E00FF3 -0FF007F60FF007F60FF007FC07E007FC03C007FC000007FC000007F8000007F8000007F8000007 -F8000007F8000007F8000007F8000007F8000007F8000007F8000007F8000007F8000007F80000 -07F8000007F8000007F8000007F8000007F80000FFFFE000FFFFE000FFFFE0001C207E9F21> -114 D<01FF860007FFFE001F00FE003C003E0078001E0078000E00F8000E00F8000E00F8000E00 -FC000000FF800000FFFC00007FFFC0007FFFF0003FFFF8001FFFFC0007FFFE0001FFFF00003FFF -000000FF8000003F8060001F80E0000F80E0000F80F0000F80F0000F00F8000F00FC001E00FE00 -1C00FF807800F3FFF000C07F800019207D9F20>I<001C0000001C0000001C0000001C0000001C -0000003C0000003C0000003C0000007C0000007C000000FC000001FC000003FC000007FC00001F -FFFE00FFFFFE00FFFFFE0003FC000003FC000003FC000003FC000003FC000003FC000003FC0000 -03FC000003FC000003FC000003FC000003FC000003FC000003FC000003FC000003FC000003FC03 -8003FC038003FC038003FC038003FC038003FC038003FC038001FC038001FC070000FE0700007F -0E00003FFC000007F000192E7FAD1F>I<01F80007E0FFF803FFE0FFF803FFE0FFF803FFE00FF8 -003FE007F8001FE007F8001FE007F8001FE007F8001FE007F8001FE007F8001FE007F8001FE007 -F8001FE007F8001FE007F8001FE007F8001FE007F8001FE007F8001FE007F8001FE007F8001FE0 -07F8001FE007F8001FE007F8001FE007F8001FE007F8003FE007F8003FE003F8007FE003F8007F -E001FC00DFF000FE039FFF007FFF1FFF000FFC1FFF28207D9F2D>II< -FFFF1FFFE07FF8FFFF1FFFE07FF8FFFF1FFFE07FF80FF000FE0007800FF800FE00078007F800FE -00070007F8007F00070003FC007F000E0003FC00FF800E0003FE00FF801E0001FE00FF801C0001 -FE01DFC01C0001FF01DFC03C0000FF03DFE0380000FF838FE07800007F838FE07000007F8707F0 -7000007FC707F0F000003FCF07F8E000003FCE03F8E000001FEE03F9C000001FFC01FDC000001F -FC01FFC000000FFC01FF8000000FF800FF80000007F800FF00000007F0007F00000007F0007F00 -000003F0007E00000003E0003E00000001E0003C00000001C0001C000035207E9F3A>I<7FFF80 -7FFC7FFF807FFC7FFF807FFC03FE000F0001FE001E0000FF003C0000FF807800007FC07800003F -E0F000001FE1E000000FF3C000000FFF80000007FF00000003FE00000001FE00000000FF000000 -00FF80000000FFC0000001FFC0000003DFE00000078FF00000078FF800000F07FC00001E03FC00 -003C01FE00007800FF0000F000FF8000E0007FC001E0003FC0FFFC01FFFFFFFC01FFFFFFFC01FF -FF28207F9F2B>II E /Fl 1 14 df<0001FE00000007FF8000001E01E000007800780000 -E0001C000180000600030000030006000001800C000000C00C000000C018000000603000000030 -30000000303000000030600000001860000000186000000018C00000000CC00000000CC0000000 -0CC00000000CC00000000CC00000000CC00000000CC00000000CC00000000C6000000018600000 -0018600000001830000000303000000030300000003018000000600C000000C00C000000C00600 -0001800300000300018000060000E0001C000078007800001E01E0000007FF80000001FE000026 -2B7DA02D>13 D E /Fm 46 122 df<3C007F00FF80FF80FFC0FFC0FFC07FC03EC000C000C00180 -018001800300030006000E001C00380030000A157B8813>44 D<1C007F007F00FF80FF80FF807F -007F001C0009097B8813>46 D<000E00001E00007E0007FE00FFFE00FFFE00F8FE0000FE0000FE -0000FE0000FE0000FE0000FE0000FE0000FE0000FE0000FE0000FE0000FE0000FE0000FE0000FE -0000FE0000FE0000FE0000FE0000FE0000FE0000FE0000FE0000FE0000FE0000FE0000FE0000FE -0000FE007FFFFE7FFFFE7FFFFE17277BA622>49 D<00FF800007FFF0000FFFFC001E03FE003800 -FF807C003F80FE003FC0FF001FC0FF001FE0FF000FE0FF000FE07E000FE03C001FE000001FE000 -001FC000001FC000003F8000003F0000007E000000FC000000F8000001F0000003E00000078000 -000F0000001E0000003C00E0007000E000E000E001C001C0038001C0060001C00FFFFFC01FFFFF -C03FFFFFC07FFFFFC0FFFFFF80FFFFFF80FFFFFF801B277DA622>I<007F800003FFF00007FFFC -000F80FE001F007F003F807F003F803F803F803F803F803F801F803F801F003F8000007F000000 -7F0000007E000000FC000001F8000007F00000FFC00000FFC0000001F80000007E0000003F0000 -003F8000001FC000001FC000001FE000001FE03C001FE07E001FE0FF001FE0FF001FE0FF001FC0 -FF003FC0FE003F807C007F003F00FE001FFFFC0007FFF00000FF80001B277DA622>I<00000E00 -00001E0000003E0000007E000000FE000000FE000001FE000003FE0000077E00000E7E00000E7E -00001C7E0000387E0000707E0000E07E0000E07E0001C07E0003807E0007007E000E007E000E00 -7E001C007E0038007E0070007E00E0007E00FFFFFFF8FFFFFFF8FFFFFFF80000FE000000FE0000 -00FE000000FE000000FE000000FE000000FE000000FE00007FFFF8007FFFF8007FFFF81D277EA6 -22>I<180003001F801F001FFFFE001FFFFC001FFFF8001FFFF0001FFFC0001FFF00001C000000 -1C0000001C0000001C0000001C0000001C0000001C0000001C7FC0001DFFF8001F80FC001E003F -0008003F0000001F8000001FC000001FC000001FE000001FE018001FE07C001FE0FE001FE0FE00 -1FE0FE001FE0FE001FC0FC001FC078003F8078003F803C007F001F01FE000FFFFC0003FFF00000 -FF80001B277DA622>I<380000003E0000003FFFFFF03FFFFFF03FFFFFF07FFFFFE07FFFFFC07F -FFFF807FFFFF0070000E0070000E0070001C00E0003800E0007000E000E0000001E0000001C000 -000380000007800000070000000F0000001F0000001E0000003E0000003E0000007E0000007C00 -00007C000000FC000000FC000000FC000000FC000001FC000001FC000001FC000001FC000001FC -000001FC000001FC000000F80000007000001C297CA822>55 D<00000780000000000780000000 -000FC0000000000FC0000000000FC0000000001FE0000000001FE0000000003FF0000000003FF0 -000000003FF00000000077F80000000077F800000000F7FC00000000E3FC00000000E3FC000000 -01C1FE00000001C1FE00000003C1FF0000000380FF0000000380FF00000007007F80000007007F -8000000F007FC000000E003FC000000E003FC000001C001FE000001C001FE000003FFFFFF00000 -3FFFFFF000003FFFFFF00000700007F80000700007F80000F00007FC0000E00003FC0000E00003 -FC0001C00001FE0001C00001FE0003C00001FF00FFFE003FFFFCFFFE003FFFFCFFFE003FFFFC2E -297EA833>65 DI<00007FE0030007FFFC07001FFFFF0F -007FF00F9F00FF0001FF01FC0000FF03F800007F07F000003F0FE000001F1FC000001F1FC00000 -0F3F8000000F3F800000077F800000077F800000077F00000000FF00000000FF00000000FF0000 -0000FF00000000FF00000000FF00000000FF00000000FF00000000FF000000007F000000007F80 -0000007F800000073F800000073F800000071FC00000071FC000000E0FE000000E07F000001C03 -F800003C01FC00007800FF0001F0007FF007C0001FFFFF800007FFFE0000007FF00028297CA831 ->I69 DI<0000 -7FE003000007FFFC0700001FFFFF0F00007FF00F9F0000FF0001FF0001FC0000FF0003F800007F -0007F000003F000FE000001F001FC000001F001FC000000F003F8000000F003F80000007007F80 -000007007F80000007007F0000000000FF0000000000FF0000000000FF0000000000FF00000000 -00FF0000000000FF0000000000FF0000000000FF0000000000FF0000FFFFF87F0000FFFFF87F80 -00FFFFF87F800000FF003F800000FF003F800000FF001FC00000FF001FC00000FF000FE00000FF -0007F00000FF0003F80000FF0001FC0000FF0000FF0001FF00007FF007FF00001FFFFF9F000007 -FFFE0F0000007FF003002D297CA835>III77 -DI80 -D82 D<00FF00C003FFE1C00FFFF9C01F80FFC03F00 -3FC03E000FC07C0007C07C0007C0FC0003C0FC0003C0FC0001C0FE0001C0FE0001C0FF000000FF -C000007FFC00007FFFE0003FFFF8001FFFFE001FFFFF0007FFFF8003FFFFC000FFFFC0000FFFE0 -00007FE000001FF000000FF0000007F0E00003F0E00003F0E00003F0E00003F0F00003E0F00003 -E0F80007E0FC0007C0FF000F80FFE01F80E3FFFF00E1FFFC00C01FF0001C297CA825>I85 DII<03FF80000FFFF0001F01FC003F80FE003F -807F003F803F003F803F801F003F8000003F8000003F8000003F8000003F80003FFF8001FC3F80 -0FE03F801F803F803F003F807E003F80FC003F80FC003F80FC003F80FC003F80FC005F807E00DF -803F839FFC1FFE0FFC03F803FC1E1B7E9A21>97 D -I<003FF00001FFFC0003F03E000FC07F001F807F003F007F003F007F007F003E007E0000007E00 -0000FE000000FE000000FE000000FE000000FE000000FE000000FE0000007E0000007E0000007F -0000003F0003803F8003801F8007000FE00E0003F83C0001FFF800003FC000191B7E9A1E>I<00 -007FF000007FF000007FF0000007F0000007F0000007F0000007F0000007F0000007F0000007F0 -000007F0000007F0000007F0000007F0000007F0003F87F001FFF7F007F03FF00FC00FF01F8007 -F03F0007F03F0007F07E0007F07E0007F07E0007F0FE0007F0FE0007F0FE0007F0FE0007F0FE00 -07F0FE0007F0FE0007F0FE0007F07E0007F07E0007F03F0007F03F0007F01F800FF00FC01FF007 -E07FFF01FFE7FF007F87FF202A7EA925>I<003FC00001FFF00003E07C000F803E001F801F001F -001F003F000F807E000F807E000FC07E000FC0FE0007C0FE0007C0FFFFFFC0FFFFFFC0FE000000 -FE000000FE0000007E0000007E0000007F0000003F0001C01F0001C00F80038007C0070003F01E -0000FFFC00003FE0001A1B7E9A1F>I<0007F8003FFC007E3E01FC7F03F87F03F07F07F07F07F0 -3E07F00007F00007F00007F00007F00007F00007F000FFFFC0FFFFC0FFFFC007F00007F00007F0 -0007F00007F00007F00007F00007F00007F00007F00007F00007F00007F00007F00007F00007F0 -0007F00007F00007F00007F00007F0007FFF807FFF807FFF80182A7EA915>I<007F80F001FFE3 -F807C0FE1C0F807C7C1F003E7C1F003E103F003F003F003F003F003F003F003F003F003F003F00 -3F001F003E001F003E000F807C0007C0F80005FFE0000C7F8000180000001C0000001C0000001E -0000001FFFF8001FFFFF000FFFFFC007FFFFE003FFFFF00FFFFFF03E0007F07C0001F8F80000F8 -F80000F8F80000F8F80000F87C0001F07C0001F03F0007E00FC01F8007FFFF00007FF0001E287E -9A22>II<07000F801FC03FE03FE03FE01FC00F80 -07000000000000000000000000000000FFE0FFE0FFE00FE00FE00FE00FE00FE00FE00FE00FE00F -E00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE0FFFEFFFEFFFE0F2B7EAA12>I108 DII<003FE00001FFFC0003F07E000FC01F801F800FC03F0007E03F00 -07E07E0003F07E0003F07E0003F0FE0003F8FE0003F8FE0003F8FE0003F8FE0003F8FE0003F8FE -0003F8FE0003F87E0003F07E0003F03F0007E03F0007E01F800FC00FC01F8007F07F0001FFFC00 -003FE0001D1B7E9A22>II114 D<03FE300FFFF03E03F0 -7800F07000F0F00070F00070F80070FE0000FFE0007FFF007FFFC03FFFE01FFFF007FFF800FFF8 -0007FC0000FCE0007CE0003CF0003CF00038F80038FC0070FF01E0E7FFC0C1FF00161B7E9A1B> -I<00700000700000700000700000F00000F00000F00001F00003F00003F00007F0001FFFE0FFFF -E0FFFFE007F00007F00007F00007F00007F00007F00007F00007F00007F00007F00007F00007F0 -0007F00007F07007F07007F07007F07007F07007F07007F07003F0E001F8C000FFC0003F001426 -7FA51A>II -IIII E /Fn 75 127 df<70F8F8F8F8F8F8F8F8F8F8F8 -F8F8F8F8F870000000000070F8F8F870051C779B18>33 D<4010E038F078E038E038E038E038E0 -38E038E038E038E038E03860300D0E7B9C18>I<030600078F00078F00078F00078F00078F0007 -8F007FFFC0FFFFE0FFFFE07FFFC00F1E000F1E000F1E000F1E000F1E000F1E007FFFC0FFFFE0FF -FFE07FFFC01E3C001E3C001E3C001E3C001E3C001E3C000C1800131C7E9B18>I<00C00001C000 -01C00001C00003F0000FFC003FFE007DCF0071C700E1C380E1C780E1C780E1C780F1C00079C000 -3DC0001FE0000FF80003FC0001DE0001CF0001C70061C380F1C380F1C380E1C380E1C70071C700 -79DE003FFE001FF80007E00001C00001C00001C00000C00011247D9F18>I<3803007C07807C07 -80EE0F80EE0F00EE0F00EE1F00EE1E00EE1E00EE3E007C3C007C3C00387C0000780000780000F8 -0000F00001F00001E00001E00003E00003C00003C00007C0000783800787C00F87C00F0EE00F0E -E01F0EE01E0EE01E0EE03E0EE03C07C03C07C018038013247E9F18>I<01C00007E0000FF0000E -70001C38001C38001C38001C38001C73F01C73F01CE3F00FE3800FC7000F87000F07001F0E003F -0E007B8E0073DC00E1DC00E0F800E0F800E07070E0787070FC707FFFE03FCFE00F03C0141C7F9B -18>I<387C7C7E3E0E0E0E1C1C38F8F0C0070E789B18>I<007000F001E003C007800F001E001C00 -380038007000700070007000E000E000E000E000E000E000E000E0007000700070007000380038 -001C001E000F00078003C001F000F000700C24799F18>I<6000F00078003C001E000F00078003 -8001C001C000E000E000E000E00070007000700070007000700070007000E000E000E000E001C0 -01C0038007800F001E003C007800F00060000C247C9F18>I<01C00001C00001C00001C000C1C1 -80F1C780F9CF807FFF001FFC0007F00007F0001FFC007FFF00F9CF80F1C780C1C18001C00001C0 -0001C00001C00011147D9718>I<00600000F00000F00000F00000F00000F00000F00000F0007F -FFC0FFFFE0FFFFE07FFFC000F00000F00000F00000F00000F00000F00000F00000600013147E97 -18>I<1C3E7E7F3F1F070E1E7CF860080C788518>I<7FFF00FFFF80FFFF807FFF0011047D8F18> -I<3078FCFC78300606778518>I<000300000780000780000F80000F00001F00001E00001E0000 -3E00003C00007C0000780000780000F80000F00001F00001E00003E00003C00003C00007C00007 -80000F80000F00000F00001F00001E00003E00003C00003C00007C0000780000F80000F00000F0 -000060000011247D9F18>I<01F00007FC000FFE001F1F001C07003803807803C07001C07001C0 -E000E0E000E0E000E0E000E0E000E0E000E0E000E0E000E0E000E0F001E07001C07001C07803C0 -3803801C07001F1F000FFE0007FC0001F000131C7E9B18>I<01800380038007800F803F80FF80 -FB80438003800380038003800380038003800380038003800380038003800380038003807FFCFF -FE7FFC0F1C7B9B18>I<03F0000FFE003FFF007C0F807003C0E001C0F000E0F000E06000E00000 -E00000E00001C00001C00003C0000780000F00001E00003C0000780000F00001E00007C0000F80 -001E00E03C00E07FFFE0FFFFE07FFFE0131C7E9B18>I<001F00003F0000770000770000E70001 -E70001C7000387000787000707000E07001E07003C0700380700780700F00700FFFFF8FFFFF8FF -FFF8000700000700000700000700000700000700007FF000FFF8007FF0151C7F9B18>52 -D<007E0001FF0007FF800F83C01E03C01C03C0380180380000700000700000E1F800E7FE00FFFF -00FE0780F803C0F001C0F000E0E000E0F000E07000E07000E07000E03801C03C03C01E07800FFF -0007FE0001F800131C7E9B18>54 D<3078FCFC783000000000000000003078FCFC783006147793 -18>58 D<183C7E7E3C180000000000000000183C7E7E3E1E0E1C3C78F060071A789318>I<0003 -00000780001F80003F00007E0001FC0003F00007E0001FC0003F00007E0000FC0000FC00007E00 -003F00001FC00007E00003F00001FC00007E00003F00001F8000078000030011187D9918>I<7F -FFC0FFFFE0FFFFE0FFFFE0000000000000000000000000FFFFE0FFFFE0FFFFE07FFFC0130C7E93 -18>I<600000F00000FC00007E00003F00001FC00007E00003F00001FC00007E00003F00001F80 -001F80003F00007E0001FC0003F00007E0001FC0003F00007E0000FC0000F0000060000011187D -9918>I<0FF0003FFC007FFF00700F00F00380F00380600780000F00003E00007C0001F00001E0 -0003C00003C00003C00003C00003C00003800000000000000000000000000000000003800007C0 -0007C00007C000038000111C7D9B18>I<00700000F80000F80000D80000D80001DC0001DC0001 -DC00018C00038E00038E00038E00038E000306000707000707000707000707000FFF800FFF800F -FF800E03800E03801C01C01C01C07F07F0FF8FF87F07F0151C7F9B18>65 -D<7FF800FFFE007FFF001C0F801C03C01C03C01C01E01C00E01C00E01C00F01C00701C00701C00 -701C00701C00701C00701C00701C00701C00F01C00E01C00E01C01E01C01C01C03C01C0F807FFF -00FFFE007FF800141C7F9B18>68 DII<7F07F0FF8FF87F07F01C01C01C01C01C01C01C01C01C01C01C01C01C01C01C01C01C01C01F -FFC01FFFC01FFFC01C01C01C01C01C01C01C01C01C01C01C01C01C01C01C01C01C01C01C01C07F -07F0FF8FF87F07F0151C7F9B18>72 D<7FFF00FFFF807FFF0001C00001C00001C00001C00001C0 -0001C00001C00001C00001C00001C00001C00001C00001C00001C00001C00001C00001C00001C0 -0001C00001C00001C00001C0007FFF00FFFF807FFF00111C7D9B18>I<7FE000FFE0007FE0000E -00000E00000E00000E00000E00000E00000E00000E00000E00000E00000E00000E00000E00000E -00000E00000E00000E00000E00700E00700E00700E00700E00707FFFF0FFFFF07FFFF0141C7F9B -18>76 D<7E07F0FF0FF87F07F01D81C01D81C01D81C01DC1C01CC1C01CC1C01CE1C01CE1C01CE1 -C01C61C01C71C01C71C01C31C01C39C01C39C01C39C01C19C01C19C01C1DC01C0DC01C0DC01C0D -C07F07C0FF87C07F03C0151C7F9B18>78 D<0FF8003FFE007FFF00780F00700700F00780E00380 -E00380E00380E00380E00380E00380E00380E00380E00380E00380E00380E00380E00380E00380 -E00380E00380F00780700700780F007FFF003FFE000FF800111C7D9B18>II<7FF800FFFE007FFF001C0F801C03801C03C01C01C01C01C01C01C01C03C01C03801C -0F801FFF001FFE001FFE001C0F001C07001C03801C03801C03801C03801C03801C039C1C039C1C -039C7F01F8FF81F87F00F0161C7F9B18>82 D<03F3801FFF803FFF807C0F80700780E00380E003 -80E00380E000007000007800003F00001FF00007FE0000FF00000F800003C00001C00000E00000 -E06000E0E000E0E001E0F001C0F80780FFFF80FFFE00E7F800131C7E9B18>I<7FFFF8FFFFF8FF -FFF8E07038E07038E07038E0703800700000700000700000700000700000700000700000700000 -700000700000700000700000700000700000700000700000700000700007FF0007FF0007FF0015 -1C7F9B18>II89 -D91 D<600000F00000F00000F800007800007C00003C00003C00003E00001E00001F00000F0000 -0F00000F800007800007C00003C00003C00003E00001E00001F00000F00000F800007800007800 -007C00003C00003E00001E00001E00001F00000F00000F8000078000078000030011247D9F18> -II<018007C01FF07EFCF83EE00E0F067C9B18>I<7FFF00FFFF80FFFF807FFF0011047D7F18>I< -061E3E387070E0E0E0F8FC7C7C38070E789E18>I<1FE0003FF8007FFC00781E00300E00000700 -00070000FF0007FF001FFF007F0700780700E00700E00700E00700F00F00781F003FFFF01FFBF0 -07E1F014147D9318>I<7E0000FE00007E00000E00000E00000E00000E00000E00000E3E000EFF -800FFFC00FC1E00F80E00F00700E00700E00380E00380E00380E00380E00380E00380F00700F00 -700F80E00FC1E00FFFC00EFF80063E00151C809B18>I<01FE0007FF001FFF803E078038030070 -0000700000E00000E00000E00000E00000E00000E000007000007001C03801C03E03C01FFF8007 -FF0001FC0012147D9318>I<001F80003F80001F8000038000038000038000038000038003E380 -0FFB801FFF803C1F80380F80700780700380E00380E00380E00380E00380E00380E00380700780 -700780380F803C1F801FFFF00FFBF803E3F0151C7E9B18>I<01F00007FC001FFE003E0F003807 -80700380700380E001C0E001C0FFFFC0FFFFC0FFFFC0E000007000007001C03801C03E03C01FFF -8007FF0001FC0012147D9318>I<001F80007FC000FFE000E1E001C0C001C00001C00001C0007F -FFC0FFFFC0FFFFC001C00001C00001C00001C00001C00001C00001C00001C00001C00001C00001 -C00001C00001C00001C0007FFF007FFF007FFF00131C7F9B18>I<01E1F007FFF80FFFF81E1E30 -1C0E003807003807003807003807003807001C0E001E1E001FFC001FF80039E0003800001C0000 -1FFE001FFFC03FFFE07801F0700070E00038E00038E00038E000387800F07E03F01FFFC00FFF80 -01FC00151F7F9318>I<7E0000FE00007E00000E00000E00000E00000E00000E00000E3E000EFF -800FFFC00FC1C00F80E00F00E00E00E00E00E00E00E00E00E00E00E00E00E00E00E00E00E00E00 -E00E00E00E00E07FC3FCFFE7FE7FC3FC171C809B18>I<03800007C00007C00007C00003800000 -00000000000000000000007FC000FFC0007FC00001C00001C00001C00001C00001C00001C00001 -C00001C00001C00001C00001C00001C00001C00001C000FFFF00FFFF80FFFF00111D7C9C18>I< -7FE000FFE0007FE00000E00000E00000E00000E00000E00000E00000E00000E00000E00000E000 -00E00000E00000E00000E00000E00000E00000E00000E00000E00000E00000E00000E0007FFFC0 -FFFFE07FFFC0131C7E9B18>108 D<7CE0E000FFFBF8007FFFF8001F1F1C001E1E1C001E1E1C00 -1C1C1C001C1C1C001C1C1C001C1C1C001C1C1C001C1C1C001C1C1C001C1C1C001C1C1C001C1C1C -001C1C1C007F1F1F00FFBFBF807F1F1F001914819318>I<7E3E00FEFF807FFFC00FC1C00F80E0 -0F00E00E00E00E00E00E00E00E00E00E00E00E00E00E00E00E00E00E00E00E00E00E00E07FC3FC -FFE7FE7FC3FC1714809318>I<01F0000FFE001FFF003E0F803803807001C07001C0E000E0E000 -E0E000E0E000E0E000E0F001E07001C07803C03C07803E0F801FFF000FFE0001F00013147E9318 ->I<7E3E00FEFF807FFFC00FC1E00F80E00F00700E00700E00380E00380E00380E00380E00380E -00380F00700F00700F80E00FC1E00FFFC00EFF800E3E000E00000E00000E00000E00000E00000E -00000E00007FC000FFE0007FC000151E809318>I<01E38007FB801FFF803E1F80380F80700780 -700780E00380E00380E00380E00380E00380E00380700780700780380F803C1F801FFF800FFB80 -03E380000380000380000380000380000380000380000380003FF8003FF8003FF8151E7E9318> -I<7F87E0FF9FF07FBFF803F87803F03003E00003C00003C0000380000380000380000380000380 -000380000380000380000380007FFE00FFFF007FFE0015147F9318>I<07F7003FFF007FFF0078 -0F00E00700E00700E007007C00007FE0001FFC0003FE00001F00600780E00380E00380F00380F8 -0F00FFFF00FFFC00E7F00011147D9318>I<0180000380000380000380000380007FFFC0FFFFC0 -FFFFC00380000380000380000380000380000380000380000380000380000380400380E00380E0 -0380E001C1C001FFC000FF80003E0013197F9818>I<7E07E0FE0FE07E07E00E00E00E00E00E00 -E00E00E00E00E00E00E00E00E00E00E00E00E00E00E00E00E00E00E00E01E00F03E007FFFC03FF -FE01FCFC1714809318>I<7F8FF0FF8FF87F8FF01E03C00E03800E03800E038007070007070007 -0700038E00038E00038E00038E0001DC0001DC0001DC0000F80000F80000700015147F9318>I< -FF8FF8FF8FF8FF8FF83800E03800E03800E01C01C01C01C01C71C01CF9C01CF9C01CD9C01CD9C0 -0DDD800DDD800DDD800D8D800F8F800F8F8007070015147F9318>I<7F8FF07F9FF07F8FF00707 -00078E00039E0001DC0001F80000F80000700000F00000F80001DC00039E00038E000707000F07 -807F8FF0FF8FF87F8FF015147F9318>I<7F8FF0FF8FF87F8FF00E01C00E03800E038007038007 -0700070700038700038600038E0001CE0001CE0000CC0000CC0000DC0000780000780000780000 -700000700000700000F00000E00079E0007BC0007F80003F00001E0000151E7F9318>I<3FFFF0 -7FFFF07FFFF07001E07003C0700780000F00001E00003C0000F80001F00003C0000780000F0070 -1E00703C0070780070FFFFF0FFFFF0FFFFF014147F9318>I<0007E0001FE0007FE000780000E0 -0000E00000E00000E00000E00000E00000E00000E00000E00000E00000E00001E0007FC000FF80 -00FF80007FC00001E00000E00000E00000E00000E00000E00000E00000E00000E00000E00000E0 -0000E000007800007FE0001FE00007E013247E9F18>I<60F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0 -F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0600424769F18>I<7C0000FF0000FFC00003C000 -00E00000E00000E00000E00000E00000E00000E00000E00000E00000E00000E00000F000007FC0 -003FE0003FE0007FC000F00000E00000E00000E00000E00000E00000E00000E00000E00000E000 -00E00000E00003C000FFC000FF00007C000013247E9F18>I<060C1F1E3FBEFBF8F1F060C00F06 -7C9B18>I E /Fo 75 123 df<001F83E000F06E3001C078780380F8780300F030070070000700 -70000700700007007000070070000700700007007000FFFFFF8007007000070070000700700007 -007000070070000700700007007000070070000700700007007000070070000700700007007000 -07007000070070000700700007007000070070007FE3FF001D20809F1B>11 -D<003F0000E0C001C0C00381E00701E00701E0070000070000070000070000070000070000FFFF -E00700E00700E00700E00700E00700E00700E00700E00700E00700E00700E00700E00700E00700 -E00700E00700E00700E00700E00700E07FC3FE1720809F19>I<003FE000E0E001C1E00381E007 -00E00700E00700E00700E00700E00700E00700E00700E0FFFFE00700E00700E00700E00700E007 -00E00700E00700E00700E00700E00700E00700E00700E00700E00700E00700E00700E00700E007 -00E07FE7FE1720809F19>I<001F81F80000F04F040001C07C06000380F80F000300F00F000700 -F00F00070070000007007000000700700000070070000007007000000700700000FFFFFFFF0007 -007007000700700700070070070007007007000700700700070070070007007007000700700700 -070070070007007007000700700700070070070007007007000700700700070070070007007007 -00070070070007007007007FE3FE3FF02420809F26>I<7038F87CFC7EFC7E743A040204020402 -0804080410081008201040200F0E7E9F17>34 D<70F8FCFC74040404080810102040060E7C9F0D ->39 D<0020004000800100020006000C000C00180018003000300030007000600060006000E000 -E000E000E000E000E000E000E000E000E000E000E0006000600060007000300030003000180018 -000C000C000600020001000080004000200B2E7DA112>I<800040002000100008000C00060006 -000300030001800180018001C000C000C000C000E000E000E000E000E000E000E000E000E000E0 -00E000E000C000C000C001C001800180018003000300060006000C00080010002000400080000B -2E7DA112>I<70F8FCFC74040404080810102040060E7C840D>44 DI<70 -F8F8F87005057C840D>I<03F0000E1C001C0E00180600380700700380700380700380700380F0 -03C0F003C0F003C0F003C0F003C0F003C0F003C0F003C0F003C0F003C0F003C0F003C0F003C070 -03807003807003807807803807001806001C0E000E1C0003F000121F7E9D17>48 -D<018003800F80F380038003800380038003800380038003800380038003800380038003800380 -03800380038003800380038003800380038007C0FFFE0F1E7C9D17>I<03F0000C1C00100E0020 -0700400780800780F007C0F803C0F803C0F803C02007C00007C0000780000780000F00000E0000 -1C0000380000700000600000C0000180000300000600400C00401800401000803FFF807FFF80FF -FF80121E7E9D17>I<03F0000C1C00100E00200F00780F80780780780780380F80000F80000F00 -000F00000E00001C0000380003F000003C00000E00000F000007800007800007C02007C0F807C0 -F807C0F807C0F00780400780400F00200E001C3C0003F000121F7E9D17>I<000600000600000E -00000E00001E00002E00002E00004E00008E00008E00010E00020E00020E00040E00080E00080E -00100E00200E00200E00400E00C00E00FFFFF0000E00000E00000E00000E00000E00000E00000E -0000FFE0141E7F9D17>I<1803001FFE001FFC001FF8001FE00010000010000010000010000010 -000010000011F000161C00180E001007001007800003800003800003C00003C00003C07003C0F0 -03C0F003C0E00380400380400700200600100E000C380003E000121F7E9D17>I<007C00018200 -0701000E03800C07801C0780380300380000780000700000700000F1F000F21C00F40600F80700 -F80380F80380F003C0F003C0F003C0F003C0F003C07003C07003C0700380380380380700180700 -0C0E00061C0001F000121F7E9D17>I<4000007FFFC07FFF807FFF804001008002008002008004 -0000080000080000100000200000200000400000400000C00000C00001C0000180000380000380 -00038000038000078000078000078000078000078000078000078000030000121F7D9D17>I<03 -F0000C0C001006003003002001806001806001806001807001807803003E03003F06001FC8000F -F00003F80007FC000C7E00103F00300F806003804001C0C001C0C000C0C000C0C000C0C0008060 -01802001001002000C0C0003F000121F7E9D17>I<03F0000E18001C0C00380600380700700700 -700380F00380F00380F003C0F003C0F003C0F003C0F003C07007C07007C03807C0180BC00E13C0 -03E3C0000380000380000380000700300700780600780E00700C002018001070000FC000121F7E -9D17>I<70F8F8F8700000000000000000000070F8F8F87005147C930D>I<70F8F8F87000000000 -00000000000070F0F8F878080808101010202040051D7C930D>I<000100000003800000038000 -000380000007C0000007C0000007C0000009E0000009E0000009E0000010F0000010F0000010F0 -0000207800002078000020780000403C0000403C0000403C0000801E0000801E0000FFFE000100 -0F0001000F0001000F00020007800200078002000780040003C00E0003C01F0007E0FFC03FFE1F -207F9F22>65 DI<000FC040007030C001C009C0038005C00700 -03C00E0001C01E0000C01C0000C03C0000C07C0000407C00004078000040F8000000F8000000F8 -000000F8000000F8000000F8000000F8000000F8000000F8000000780000007C0000407C000040 -3C0000401C0000401E0000800E000080070001000380020001C0040000703800000FC0001A217D -9F21>IIII<000FE0200078186000E004E0038002E0070001E00F0000E01E0000601E000060 -3C0000603C0000207C00002078000020F8000000F8000000F8000000F8000000F8000000F80000 -00F8000000F8007FFCF80003E0780001E07C0001E03C0001E03C0001E01E0001E01E0001E00F00 -01E0070001E0038002E000E0046000781820000FE0001E217D9F24>III<0FFFC0007C -00003C00003C00003C00003C00003C00003C00003C00003C00003C00003C00003C00003C00003C -00003C00003C00003C00003C00003C00003C00003C00003C00203C00F83C00F83C00F83C00F038 -0040780040700030E0000F800012207E9E17>I76 DII<001F800000F0F00001C0380007801E -000F000F000E0007001E0007803C0003C03C0003C07C0003E0780001E0780001E0F80001F0F800 -01F0F80001F0F80001F0F80001F0F80001F0F80001F0F80001F0F80001F0780001E07C0003E07C -0003E03C0003C03C0003C01E0007800E0007000F000F0007801E0001C0380000F0F000001F8000 -1C217D9F23>II<001F800000F0F00001C0380007801E000F00 -0F000E0007001E0007803C0003C03C0003C07C0003E07C0003E0780001E0F80001F0F80001F0F8 -0001F0F80001F0F80001F0F80001F0F80001F0F80001F0F80001F0780001E0780001E07C0003E0 -3C0003C03C0F03C01E1087800E2047000F204F0007A03E0001E0380000F0F010001FB010000030 -10000038300000387000003FF000001FE000001FE000000FC0000007801C297D9F23>II<07E0800C1980100780300380600180600180E00180E00080 -E00080E00080F00000F000007800007F00003FF0001FFC000FFE0003FF00001F800007800003C0 -0003C00001C08001C08001C08001C08001C0C00180C00380E00300F00600CE0C0081F80012217D -9F19>I<7FFFFFE0780F01E0600F0060400F0020400F0020C00F0030800F0010800F0010800F00 -10800F0010000F0000000F0000000F0000000F0000000F0000000F0000000F0000000F0000000F -0000000F0000000F0000000F0000000F0000000F0000000F0000000F0000000F0000000F000000 -0F0000001F800007FFFE001C1F7E9E21>IIII91 -D<080410082010201040204020804080408040B85CFC7EFC7E7C3E381C0F0E7B9F17>II<081020204040808080B8FCFC7C38060E7D9F0D>96 -D<1FE000303000781800781C00300E00000E00000E00000E0000FE00078E001E0E00380E00780E -00F00E10F00E10F00E10F01E10781E103867200F83C014147E9317>I<0E0000FE00000E00000E -00000E00000E00000E00000E00000E00000E00000E00000E00000E3E000EC3800F01C00F00E00E -00E00E00700E00700E00780E00780E00780E00780E00780E00780E00700E00700E00E00F00E00D -01C00CC300083E0015207F9F19>I<03F80E0C1C1E381E380C70007000F000F000F000F000F000 -F00070007000380138011C020E0C03F010147E9314>I<000380003F8000038000038000038000 -038000038000038000038000038000038000038003E380061B801C078038038038038070038070 -0380F00380F00380F00380F00380F00380F003807003807003803803803807801C07800E1B8003 -E3F815207E9F19>I<03F0000E1C001C0E00380700380700700700700380F00380F00380FFFF80 -F00000F00000F000007000007000003800801800800C010007060001F80011147F9314>I<007C -00C6018F038F07060700070007000700070007000700FFF0070007000700070007000700070007 -0007000700070007000700070007000700070007007FF01020809F0E>I<0000E003E3300E3C30 -1C1C30380E00780F00780F00780F00780F00780F00380E001C1C001E380033E000200000200000 -3000003000003FFE001FFF800FFFC03001E0600070C00030C00030C00030C000306000603000C0 -1C038003FC00141F7F9417>I<0E0000FE00000E00000E00000E00000E00000E00000E00000E00 -000E00000E00000E00000E3E000E43000E81800F01C00F01C00E01C00E01C00E01C00E01C00E01 -C00E01C00E01C00E01C00E01C00E01C00E01C00E01C00E01C00E01C0FFE7FC16207F9F19>I<1C -003E003E003E001C000000000000000000000000000E007E000E000E000E000E000E000E000E00 -0E000E000E000E000E000E000E000E000E000E00FFC00A1F809E0C>I<00E001F001F001F000E0 -000000000000000000000000007007F000F0007000700070007000700070007000700070007000 -7000700070007000700070007000700070007000706070F060F0C061803F000C28829E0E>I<0E -0000FE00000E00000E00000E00000E00000E00000E00000E00000E00000E00000E00000E0FF00E -03C00E03000E02000E04000E08000E10000E30000E70000EF8000F38000E1C000E1E000E0E000E -07000E07800E03800E03C00E03E0FFCFF815207F9F18>I<0E00FE000E000E000E000E000E000E -000E000E000E000E000E000E000E000E000E000E000E000E000E000E000E000E000E000E000E00 -0E000E000E000E00FFE00B20809F0C>I<0E1F01F000FE618618000E81C81C000F00F00E000F00 -F00E000E00E00E000E00E00E000E00E00E000E00E00E000E00E00E000E00E00E000E00E00E000E -00E00E000E00E00E000E00E00E000E00E00E000E00E00E000E00E00E000E00E00E00FFE7FE7FE0 -23147F9326>I<0E3E00FE43000E81800F01C00F01C00E01C00E01C00E01C00E01C00E01C00E01 -C00E01C00E01C00E01C00E01C00E01C00E01C00E01C00E01C0FFE7FC16147F9319>I<01F80007 -0E001C03803801C03801C07000E07000E0F000F0F000F0F000F0F000F0F000F0F000F07000E070 -00E03801C03801C01C0380070E0001F80014147F9317>I<0E3E00FEC3800F01C00F00E00E00E0 -0E00F00E00700E00780E00780E00780E00780E00780E00780E00700E00F00E00E00F01E00F01C0 -0EC3000E3E000E00000E00000E00000E00000E00000E00000E00000E0000FFE000151D7F9319> -I<03E0800619801C05803C0780380380780380700380F00380F00380F00380F00380F00380F003 -807003807803803803803807801C0B800E138003E3800003800003800003800003800003800003 -80000380000380003FF8151D7E9318>I<0E78FE8C0F1E0F1E0F0C0E000E000E000E000E000E00 -0E000E000E000E000E000E000E000E00FFE00F147F9312>I<1F9030704030C010C010C010E000 -78007F803FE00FF00070803880188018C018C018E030D0608F800D147E9312>I<020002000200 -060006000E000E003E00FFF80E000E000E000E000E000E000E000E000E000E000E000E080E080E -080E080E080610031001E00D1C7F9B12>I<0E01C0FE1FC00E01C00E01C00E01C00E01C00E01C0 -0E01C00E01C00E01C00E01C00E01C00E01C00E01C00E01C00E01C00E03C00603C0030DC001F1FC -16147F9319>III<7FC3FC0F01E00701C007018003810001C20000E40000EC00007800003800003C0000 -7C00004E000087000107000303800201C00601E01E01E0FF07FE1714809318>II<3FFF380E200E201C40384078407000E001E001C00380078007010E011E -011C0338027006700EFFFE10147F9314>I E /Fp 13 122 df<0000001FFC0000C000000003FF -FFC001C00000001FFFFFF003C00000007FFFFFFC07C0000001FFFC00FE0FC0000007FFC0001F9F -C000000FFE000007FFC000003FF8000003FFC000007FF0000000FFC00000FFE00000007FC00001 -FFC00000007FC00001FF800000003FC00003FF000000001FC00007FE000000001FC0000FFE0000 -00000FC0000FFC000000000FC0001FFC0000000007C0001FFC0000000007C0003FF80000000007 -C0003FF80000000003C0003FF80000000003C0007FF80000000003C0007FF80000000003C0007F -F0000000000000007FF000000000000000FFF000000000000000FFF000000000000000FFF00000 -0000000000FFF000000000000000FFF000000000000000FFF000000000000000FFF00000000000 -0000FFF000000000000000FFF000000000000000FFF000000000000000FFF000001FFFFFFF807F -F000001FFFFFFF807FF000001FFFFFFF807FF800001FFFFFFF807FF800000001FFC0003FF80000 -0001FFC0003FF800000001FFC0003FF800000001FFC0001FFC00000001FFC0001FFC00000001FF -C0000FFE00000001FFC0000FFE00000001FFC00007FF00000001FFC00003FF00000001FFC00001 -FF80000001FFC00001FFC0000001FFC00000FFE0000001FFC000007FF0000003FFC000003FFC00 -0003FFC000000FFF000007FFC0000007FFC0001FBFC0000001FFFC00FF1FC00000007FFFFFFE0F -C00000001FFFFFF803C000000003FFFFE000C0000000001FFE00000000413D7BBB4C>71 -DI76 D78 D85 D<003FFE00000001FFFFE0000007FFFFF800000FE0 -07FC00000FF001FE00001FF800FF00001FF8007F80001FF8007FC0001FF8003FC0000FF0003FE0 -0007E0003FE00003C0003FE0000000003FE0000000003FE0000000003FE0000000003FE0000000 -FFFFE000001FFFFFE000007FF83FE00003FF803FE00007FC003FE0000FF0003FE0001FE0003FE0 -003FE0003FE0007FC0003FE0007FC0003FE000FF80003FE000FF80003FE000FF80003FE000FF80 -003FE000FF80007FE0007FC0007FE0007FC000DFE0003FE0039FF0001FF80F0FFFE007FFFE0FFF -E001FFF807FFE0003FE000FFE02B267DA52F>97 D<00FE00000000FFFE00000000FFFE00000000 -FFFE00000000FFFE0000000007FE0000000003FE0000000003FE0000000003FE0000000003FE00 -00000003FE0000000003FE0000000003FE0000000003FE0000000003FE0000000003FE00000000 -03FE0000000003FE0000000003FE0000000003FE0000000003FE0000000003FE0000000003FE01 -FF000003FE1FFFF00003FE7FFFFC0003FEFC03FE0003FFF000FF0003FFC0003F8003FF00001FC0 -03FE00001FE003FE00000FF003FE00000FF803FE00000FF803FE000007FC03FE000007FC03FE00 -0007FC03FE000007FE03FE000007FE03FE000007FE03FE000007FE03FE000007FE03FE000007FE -03FE000007FE03FE000007FE03FE000007FE03FE000007FC03FE000007FC03FE000007FC03FE00 -000FFC03FE00000FF803FE00000FF003FE00001FF003FF00001FE003FF80003FC003FFC0007F80 -03F9E000FF0003F0FC07FE0003F07FFFF80003E01FFFE00003C003FE00002F3C7DBB36>I<01E0 -0007F8000FFC000FFC001FFE001FFE001FFE001FFE000FFC000FFC0007F80001E0000000000000 -0000000000000000000000000000000000000000000000000000000000FE00FFFE00FFFE00FFFE -00FFFE0007FE0003FE0003FE0003FE0003FE0003FE0003FE0003FE0003FE0003FE0003FE0003FE -0003FE0003FE0003FE0003FE0003FE0003FE0003FE0003FE0003FE0003FE0003FE0003FE0003FE -0003FE0003FE0003FE0003FE00FFFFF0FFFFF0FFFFF0FFFFF0143D7DBC1A>105 -D<0001FFC00000000FFFF80000007FFFFF000000FF80FF800003FE003FE00007F8000FF0000FF0 -0007F8000FF00007F8001FE00003FC003FE00003FE003FE00003FE007FC00001FF007FC00001FF -007FC00001FF007FC00001FF00FFC00001FF80FFC00001FF80FFC00001FF80FFC00001FF80FFC0 -0001FF80FFC00001FF80FFC00001FF80FFC00001FF80FFC00001FF807FC00001FF007FC00001FF -007FC00001FF003FE00003FE003FE00003FE001FE00003FC001FF00007FC000FF00007F80007F8 -000FF00003FE003FE00000FF80FF8000007FFFFF0000000FFFF800000001FFC0000029267DA530 ->111 D<01FC03F000FFFC0FFC00FFFC1FFF00FFFC3C3F80FFFC707F8007FCE0FFC003FCC0FFC0 -03FD80FFC003FD80FFC003FF807F8003FF003F0003FF001E0003FF00000003FE00000003FE0000 -0003FE00000003FE00000003FE00000003FE00000003FE00000003FE00000003FE00000003FE00 -000003FE00000003FE00000003FE00000003FE00000003FE00000003FE00000003FE00000003FE -00000003FE00000003FE00000003FE000000FFFFFC0000FFFFFC0000FFFFFC0000FFFFFC000022 -267DA528>114 D<003FF07003FFFEF007FFFFF01FC01FF03F0003F03E0001F07C0001F07C0000 -F0FC0000F0FC0000F0FE0000F0FF000000FFC00000FFFC00007FFFF0003FFFFE003FFFFF801FFF -FFC00FFFFFE003FFFFF000FFFFF8001FFFFC00007FFC000007FE700001FEF00000FEF000007EF8 -00007EF800007EFC00007EFC00007CFE0000FCFF0000F8FF8001F0FFF00FE0F9FFFFC0F07FFF00 -C01FF8001F267DA526>I<000F0000000F0000000F0000000F0000000F0000001F0000001F0000 -001F0000001F0000003F0000003F0000007F0000007F000000FF000001FF000003FF000007FF00 -001FFFFFF0FFFFFFF0FFFFFFF0FFFFFFF001FF000001FF000001FF000001FF000001FF000001FF -000001FF000001FF000001FF000001FF000001FF000001FF000001FF000001FF000001FF000001 -FF000001FF000001FF000001FF000001FF003C01FF003C01FF003C01FF003C01FF003C01FF003C -01FF003C01FF003C00FF007800FF8078007F80F0003FC1E0001FFFC0000FFF800001FE001E377E -B626>I121 -D E end -%%EndProlog -%%BeginSetup -%%Feature: *Resolution 300dpi -TeXDict begin - -%%EndSetup -%%Page: 1 1 -0 bop 0 1152 a Fp(GNU)33 b(History)f(Library)p 0 1201 1950 -17 v 1035 1250 a Fo(Edition)16 b(2.0,)e(for)h Fn(History)f(Library)g -Fo(V)l(ersion)i(2.0.)1759 1304 y(July)g(1994)0 2443 y Fm(Brian)23 -b(F)-6 b(o)n(x,)23 b(F)-6 b(ree)23 b(Soft)n(w)n(are)f(F)-6 -b(oundation)0 2509 y(Chet)22 b(Ramey)-6 b(,)23 b(Case)e(W)-6 -b(estern)23 b(Reserv)n(e)f(Univ)n(ersit)n(y)p 0 2545 1950 9 -v eop -%%Page: 2 2 -1 bop 0 295 a Fo(This)16 b(do)q(cumen)o(t)g(describ)q(es)h(the)f(GNU)f -(History)g(library)l(,)h(a)g(programming)e(to)q(ol)i(that)f(pro)o(vides)h(a)f -(consisten)o(t)0 358 y(user)g(in)o(terface)h(for)e(recalling)j(lines)g(of)e -(previously)h(t)o(yp)q(ed)g(input.)0 495 y(Published)h(b)o(y)f(the)f(F)l(ree) -g(Soft)o(w)o(are)f(F)l(oundation)0 557 y(675)g(Massac)o(h)o(usetts)g(Av)o(en) -o(ue,)0 619 y(Cam)o(bridge,)h(MA)g(02139)f(USA)0 756 y(P)o(ermission)f(is)g -(gran)o(ted)f(to)f(mak)o(e)h(and)h(distribute)h(v)o(erbatim)e(copies)h(of)f -(this)h(man)o(ual)g(pro)o(vided)g(the)f(cop)o(yrigh)o(t)0 818 -y(notice)k(and)f(this)h(p)q(ermission)h(notice)e(are)g(preserv)o(ed)h(on)f -(all)h(copies.)0 955 y(P)o(ermission)f(is)f(gran)o(ted)f(to)h(cop)o(y)g(and)g -(distribute)h(mo)q(di\014ed)h(v)o(ersions)e(of)f(this)i(man)o(ual)f(under)h -(the)f(conditions)0 1018 y(for)e(v)o(erbatim)g(cop)o(ying,)h(pro)o(vided)h -(that)d(the)i(en)o(tire)g(resulting)h(deriv)o(ed)f(w)o(ork)f(is)h -(distributed)h(under)f(the)g(terms)0 1080 y(of)i(a)g(p)q(ermission)h(notice)g -(iden)o(tical)h(to)e(this)g(one.)0 1217 y(P)o(ermission)20 -b(is)g(gran)o(ted)f(to)g(cop)o(y)h(and)f(distribute)i(translations)f(of)f -(this)h(man)o(ual)f(in)o(to)h(another)f(language,)0 1279 y(under)c(the)f(ab)q -(o)o(v)o(e)g(conditions)h(for)e(mo)q(di\014ed)j(v)o(ersions,)e(except)g(that) -g(this)g(p)q(ermission)i(notice)e(ma)o(y)g(b)q(e)h(stated)0 -1341 y(in)h(a)f(translation)g(appro)o(v)o(ed)g(b)o(y)g(the)g(F)l(oundation.)0 -2636 y(Cop)o(yrigh)o(t)226 2635 y(c)214 2636 y Fl(\015)g Fo(1989,)f(1991)g(F) -l(ree)h(Soft)o(w)o(are)f(F)l(oundation,)h(Inc.)p eop -%%Page: 1 3 -2 bop 0 -83 a Fo(Chapter)15 b(1:)k(Using)d(History)f(In)o(teractiv)o(ely)1157 -b(1)0 158 y Fk(1)41 b(Using)14 b(History)h(In)n(teractiv)n(ely)62 -330 y Fo(This)i(c)o(hapter)e(describ)q(es)j(ho)o(w)d(to)h(use)g(the)g(GNU)g -(History)f(Library)i(in)o(teractiv)o(ely)l(,)g(from)e(a)g(user's)h(stand-)0 -392 y(p)q(oin)o(t.)23 b(It)16 b(should)h(b)q(e)f(considered)i(a)d(user's)h -(guide.)23 b(F)l(or)15 b(information)h(on)g(using)h(the)f(GNU)g(History)f -(Library)0 454 y(in)h(y)o(our)f(o)o(wn)f(programs,)g(see)i(Chapter)e(2)h -([Programming)f(with)i(GNU)f(History],)f(page)h(5.)0 663 y -Fm(1.1)33 b(History)15 b(In)n(teraction)62 800 y Fo(The)j(History)g(library)g -(pro)o(vides)h(a)e(history)h(expansion)h(feature)e(that)g(is)i(similar)g(to)e -(the)h(history)f(expan-)0 862 y(sion)k(pro)o(vided)h(b)o(y)f -Fn(csh)p Fo(.)36 b(The)22 b(follo)o(wing)f(text)g(describ)q(es)h(the)f(syn)o -(tax)f(used)i(to)e(manipulate)i(the)f(history)0 924 y(information.)62 -1061 y(History)11 b(expansion)i(tak)o(es)d(place)i(in)h(t)o(w)o(o)d(parts.)18 -b(The)11 b(\014rst)g(is)h(to)f(determine)h(whic)o(h)g(line)h(from)e(the)g -(previous)0 1124 y(history)h(should)h(b)q(e)f(used)h(during)f(substitution.) -20 b(The)12 b(second)g(is)h(to)e(select)h(p)q(ortions)g(of)g(that)f(line)i -(for)f(inclusion)0 1186 y(in)o(to)f(the)h(curren)o(t)f(one.)18 -b(The)12 b(line)h(selected)f(from)f(the)g(previous)h(history)g(is)f(called)i -(the)e Fj(ev)o(en)o(t)p Fo(,)h(and)f(the)h(p)q(ortions)0 1248 -y(of)h(that)g(line)i(that)e(are)g(acted)g(up)q(on)h(are)g(called)h -Fj(w)o(ords)p Fo(.)j(The)c(line)h(is)f(brok)o(en)f(in)o(to)h(w)o(ords)f(in)h -(the)f(same)h(fashion)0 1310 y(that)j(Bash)h(do)q(es,)h(so)e(that)g(sev)o -(eral)h(English)i(\(or)d(Unix\))h(w)o(ords)f(surrounded)i(b)o(y)f(quotes)f -(are)h(considered)h(as)0 1373 y(one)c(w)o(ord.)0 1565 y Fi(1.1.1)30 -b(Ev)n(en)n(t)16 b(Designators)62 1702 y Fo(An)g(ev)o(en)o(t)f(designator)g -(is)g(a)g(reference)h(to)f(a)g(command)g(line)i(en)o(try)d(in)i(the)g -(history)f(list.)0 1847 y Fn(!)216 b Fo(Start)14 b(a)g(history)h -(substitution,)g(except)h(when)f(follo)o(w)o(ed)g(b)o(y)g(a)f(space,)h(tab,)f -(the)h(end)g(of)g(the)g(line,)240 1909 y Fn(=)g Fo(or)g Fn(\()p -Fo(.)0 1989 y Fn(!!)192 b Fo(Refer)16 b(to)e(the)i(previous)f(command.)20 -b(This)c(is)g(a)f(synon)o(ym)g(for)f Fn(!-1)p Fo(.)0 2068 y -Fn(!n)192 b Fo(Refer)16 b(to)e(command)h(line)i Fj(n)p Fo(.)0 -2148 y Fn(!-n)168 b Fo(Refer)16 b(to)e(the)i(command)f Fj(n)g -Fo(lines)i(bac)o(k.)0 2227 y Fn(!string)72 b Fo(Refer)16 b(to)e(the)i(most)e -(recen)o(t)h(command)g(starting)g(with)g Fj(string)p Fo(.)0 -2298 y Fn(!?string)p Fo([)p Fn(?)p Fo(])240 2360 y(Refer)h(to)e(the)i(most)e -(recen)o(t)h(command)g(con)o(taining)h Fj(string)p Fo(.)0 2440 -y Fn(!#)192 b Fo(The)15 b(en)o(tire)h(command)f(line)i(t)o(yp)q(ed)f(so)e -(far.)0 2510 y Fn(^string1^string2^)240 2573 y Fo(Quic)o(k)j(Substitution.)22 -b(Rep)q(eat)16 b(the)g(last)f(command,)h(replacing)h Fj(string1)h -Fo(with)e Fj(string2)p Fo(.)21 b(Equiv-)240 2635 y(alen)o(t)15 -b(to)g Fn(!!:s/string1/string2/)p Fo(.)p eop -%%Page: 2 4 -3 bop 0 -83 a Fo(2)1497 b(GNU)15 b(History)g(Library)0 158 -y Fi(1.1.2)30 b(W)-5 b(ord)15 b(Designators)62 295 y Fo(A)i -Fn(:)g Fo(separates)f(the)h(ev)o(en)o(t)f(sp)q(eci\014cation)j(from)d(the)g -(w)o(ord)g(designator.)25 b(It)17 b(can)g(b)q(e)g(omitted)g(if)g(the)g(w)o -(ord)0 358 y(designator)d(b)q(egins)h(with)f(a)f Fn(^)p Fo(,)h -Fn($)p Fo(,)f Fn(*)h Fo(or)f Fn(\045)p Fo(.)20 b(W)l(ords)13 -b(are)h(n)o(um)o(b)q(ered)g(from)f(the)h(b)q(eginning)i(of)d(the)h(line,)i -(with)e(the)0 420 y(\014rst)h(w)o(ord)f(b)q(eing)j(denoted)f(b)o(y)f(a)g(0)f -(\(zero\).)0 569 y Fn(0)h(\(zero\))57 b Fo(The)15 b Fn(0)p -Fo(th)g(w)o(ord.)20 b(F)l(or)14 b(man)o(y)h(applications,)h(this)g(is)g(the)f -(command)g(w)o(ord.)0 656 y Fn(n)216 b Fo(The)15 b Fj(n)p Fo(th)h(w)o(ord.)0 -744 y Fn(^)216 b Fo(The)15 b(\014rst)g(argumen)o(t;)f(that)h(is,)g(w)o(ord)g -(1.)0 831 y Fn($)216 b Fo(The)15 b(last)h(argumen)o(t.)0 918 -y Fn(\045)216 b Fo(The)15 b(w)o(ord)g(matc)o(hed)g(b)o(y)g(the)g(most)g -(recen)o(t)g Fn(?string?)f Fo(searc)o(h.)0 1005 y Fn(x-y)168 -b Fo(A)15 b(range)g(of)g(w)o(ords;)f Fn(-)p Fj(y)19 b Fo(abbreviates)c -Fn(0-)p Fj(y)t Fo(.)0 1092 y Fn(*)216 b Fo(All)17 b(of)f(the)g(w)o(ords,)f -(except)i(the)f Fn(0)p Fo(th.)22 b(This)17 b(is)f(a)g(synon)o(ym)g(for)f -Fn(1-$)p Fo(.)22 b(It)17 b(is)f(not)g(an)g(error)f(to)h(use)240 -1155 y Fn(*)f Fo(if)h(there)f(is)h(just)f(one)g(w)o(ord)f(in)i(the)g(ev)o(en) -o(t;)e(the)i(empt)o(y)e(string)i(is)f(returned)h(in)g(that)e(case.)0 -1242 y Fn(x*)192 b Fo(Abbreviates)16 b Fn(x-$)0 1329 y(x-)192 -b Fo(Abbreviates)16 b Fn(x-$)f Fo(lik)o(e)h Fn(x*)p Fo(,)e(but)i(omits)f(the) -g(last)g(w)o(ord.)0 1537 y Fi(1.1.3)30 b(Mo)r(di\014ers)62 -1674 y Fo(After)20 b(the)f(optional)i(w)o(ord)e(designator,)h(y)o(ou)f(can)h -(add)g(a)g(sequence)h(of)e(one)h(or)f(more)g(of)g(the)h(follo)o(wing)0 -1736 y(mo)q(di\014ers,)c(eac)o(h)f(preceded)i(b)o(y)e(a)g Fn(:)p -Fo(.)0 1885 y Fn(h)216 b Fo(Remo)o(v)o(e)15 b(a)g(trailing)h(pathname)f(comp) -q(onen)o(t,)g(lea)o(ving)h(only)g(the)f(head.)0 1973 y Fn(r)216 -b Fo(Remo)o(v)o(e)15 b(a)g(trailing)h(su\016x)f(of)g(the)g(form)g(`)p -Fn(.)p Fo(')p Fj(su\016x)p Fo(,)f(lea)o(ving)i(the)f(basename.)0 -2060 y Fn(e)216 b Fo(Remo)o(v)o(e)15 b(all)h(but)g(the)f(trailing)h(su\016x.) -0 2147 y Fn(t)216 b Fo(Remo)o(v)o(e)15 b(all)h(leading)h(pathname)e(comp)q -(onen)o(ts,)g(lea)o(ving)h(the)f(tail.)0 2234 y Fn(p)216 b -Fo(Prin)o(t)15 b(the)g(new)h(command)f(but)g(do)g(not)g(execute)h(it.)0 -2309 y Fn(s/old/new/)240 2371 y Fo(Substitute)g Fj(new)k Fo(for)15 -b(the)h(\014rst)f(o)q(ccurrence)h(of)g Fj(old)h Fo(in)g(the)e(ev)o(en)o(t)h -(line.)22 b(An)o(y)16 b(delimiter)h(ma)o(y)e(b)q(e)240 2433 -y(used)e(in)f(place)h(of)f Fn(/)p Fo(.)19 b(The)12 b(delimiter)i(ma)o(y)d(b)q -(e)i(quoted)f(in)h Fj(old)h Fo(and)e Fj(new)17 b Fo(with)12 -b(a)g(single)h(bac)o(kslash.)240 2496 y(If)g Fn(&)h Fo(app)q(ears)f(in)h -Fj(new)p Fo(,)f(it)h(is)g(replaced)g(b)o(y)f Fj(old)p Fo(.)20 -b(A)13 b(single)i(bac)o(kslash)e(will)i(quote)e(the)h Fn(&)p -Fo(.)19 b(The)13 b(\014nal)240 2558 y(delimiter)k(is)f(optional)g(if)f(it)h -(is)f(the)h(last)f(c)o(haracter)f(on)h(the)h(input)g(line.)0 -2645 y Fn(&)216 b Fo(Rep)q(eat)16 b(the)f(previous)h(substitution.)p -eop -%%Page: 3 5 -4 bop 0 -83 a Fo(Chapter)15 b(1:)k(Using)d(History)f(In)o(teractiv)o(ely)1157 -b(3)0 158 y Fn(g)216 b Fo(Cause)15 b(c)o(hanges)g(to)f(b)q(e)i(applied)h(o)o -(v)o(er)d(the)h(en)o(tire)g(ev)o(en)o(t)g(line.)21 b(Used)16 -b(in)g(conjunction)g(with)f Fn(s)p Fo(,)f(as)240 221 y(in)i -Fn(gs/old/new/)p Fo(,)d(or)i(with)h Fn(&)p Fo(.)p eop -%%Page: 4 6 -5 bop 0 -83 a Fo(4)1497 b(GNU)15 b(History)g(Library)p eop -%%Page: 5 7 -6 bop 0 -83 a Fo(Chapter)15 b(2:)k(Programming)c(with)g(GNU)g(History)1039 -b(5)0 158 y Fk(2)41 b(Programming)16 b(with)f(GNU)h(History)62 -347 y Fo(This)e(c)o(hapter)f(describ)q(es)i(ho)o(w)d(to)h(in)o(terface)g -(programs)f(that)h(y)o(ou)g(write)g(with)g(the)h(GNU)f(History)g(Library)l(.) -0 409 y(It)j(should)g(b)q(e)g(considered)h(a)f(tec)o(hnical)h(guide.)22 -b(F)l(or)15 b(information)h(on)f(the)h(in)o(teractiv)o(e)g(use)g(of)f(GNU)g -(History)l(,)0 471 y(see)g(Chapter)g(1)g([Using)h(History)f(In)o(teractiv)o -(ely],)g(page)g(1.)0 698 y Fm(2.1)33 b(In)n(tro)r(duction)17 -b(to)e(History)62 835 y Fo(Man)o(y)j(programs)g(read)h(input)h(from)e(the)g -(user)h(a)g(line)h(at)f(a)f(time.)31 b(The)19 b(GNU)g(History)f(library)i(is) -f(able)0 897 y(to)e(k)o(eep)g(trac)o(k)f(of)h(those)g(lines,)i(asso)q(ciate)e -(arbitrary)g(data)g(with)g(eac)o(h)g(line,)j(and)d(utilize)i(information)f -(from)0 960 y(previous)e(lines)h(in)f(comp)q(osing)f(new)h(ones.)62 -1097 y(The)i(programmer)f(using)h(the)g(History)g(library)g(has)g(a)o(v)m -(ailable)h(functions)g(for)e(remem)o(b)q(ering)h(lines)i(on)d(a)0 -1159 y(history)f(list,)g(asso)q(ciating)g(arbitrary)g(data)f(with)h(a)f -(line,)j(remo)o(ving)d(lines)j(from)d(the)h(list,)g(searc)o(hing)g(through)0 -1221 y(the)h(list)h(for)e(a)h(line)h(con)o(taining)g(an)f(arbitrary)f(text)h -(string,)g(and)g(referencing)h(an)o(y)f(line)h(in)g(the)f(list)h(directly)l -(.)0 1284 y(In)d(addition,)h(a)e(history)h Fj(expansion)h Fo(function)g(is)f -(a)o(v)m(ailable)h(whic)o(h)g(pro)o(vides)f(for)f(a)h(consisten)o(t)g(user)g -(in)o(terface)0 1346 y(across)f(di\013eren)o(t)i(programs.)62 -1483 y(The)i(user)g(using)g(programs)f(written)g(with)h(the)g(History)f -(library)i(has)e(the)h(b)q(ene\014t)h(of)e(a)g(consisten)o(t)h(user)0 -1545 y(in)o(terface)d(with)g(a)f(set)h(of)f(w)o(ell-kno)o(wn)h(commands)g -(for)f(manipulating)i(the)f(text)f(of)g(previous)h(lines)h(and)f(using)0 -1608 y(that)g(text)g(in)i(new)e(commands.)22 b(The)15 b(basic)i(history)e -(manipulation)j(commands)d(are)g(similar)i(to)e(the)h(history)0 -1670 y(substitution)g(pro)o(vided)g(b)o(y)f Fn(csh)p Fo(.)62 -1807 y(If)g(the)g(programmer)e(desires,)i(he)g(can)g(use)g(the)f(Readline)j -(library)l(,)e(whic)o(h)h(includes)g(some)f(history)f(manip-)0 -1870 y(ulation)i(b)o(y)f(default,)h(and)f(has)g(the)g(added)h(adv)m(an)o -(tage)f(of)g(command)g(line)h(editing.)0 2096 y Fm(2.2)33 b(History)15 -b(Storage)62 2234 y Fo(The)h(history)f(list)h(is)g(an)f(arra)o(y)f(of)g -(history)i(en)o(tries.)k(A)15 b(history)g(en)o(try)g(is)h(declared)g(as)f -(follo)o(ws:)120 2358 y Fn(typedef)23 b(struct)g(_hist_entry)f({)168 -2408 y(char)h(*line;)168 2458 y(char)g(*data;)120 2508 y(})h(HIST_ENTRY;)62 -2645 y Fo(The)16 b(history)f(list)h(itself)g(migh)o(t)f(therefore)g(b)q(e)h -(declared)g(as)p eop -%%Page: 6 8 -7 bop 0 -83 a Fo(6)1497 b(GNU)15 b(History)g(Library)120 158 -y Fn(HIST_ENTRY)22 b(**the_history_list;)62 302 y Fo(The)16 -b(state)e(of)h(the)g(History)g(library)h(is)g(encapsulated)g(in)o(to)f(a)g -(single)i(structure:)120 434 y Fn(/*)24 b(A)f(structure)g(used)g(to)h(pass)f -(the)h(current)f(state)g(of)g(the)h(history)f(stuff)g(around.)g(*/)120 -484 y(typedef)g(struct)g(_hist_state)f({)168 534 y(HIST_ENTRY)g(**entries;) -214 b(/*)23 b(Pointer)g(to)h(the)f(entries)g(themselves.)f(*/)168 -584 y(int)h(offset;)453 b(/*)23 b(The)h(location)e(pointer)h(within)g(this)h -(array.)f(*/)168 633 y(int)g(length;)453 b(/*)23 b(Number)g(of)h(elements)f -(within)g(this)g(array.)g(*/)168 683 y(int)g(size;)501 b(/*)23 -b(Number)g(of)h(slots)f(allocated)g(to)g(this)h(array.)f(*/)168 -733 y(int)g(flags;)120 783 y(})h(HISTORY_STATE;)62 927 y Fo(If)16 -b(the)f(\015ags)g(mem)o(b)q(er)g(includes)j Fn(HS_STIFLED)p -Fo(,)13 b(the)i(history)h(has)f(b)q(een)h(sti\015ed.)0 1215 -y Fm(2.3)33 b(History)15 b(F)-6 b(unctions)62 1359 y Fo(This)16 -b(section)g(describ)q(es)h(the)e(calling)i(sequence)f(for)f(the)g(v)m(arious) -h(functions)g(presen)o(t)f(in)h(GNU)f(History)l(.)0 1631 y -Fi(2.3.1)30 b(Initializing)15 b(History)g(and)g(State)g(Managemen)n(t)62 -1775 y Fo(This)j(section)g(describ)q(es)h(functions)f(used)g(to)e(initialize) -21 b(and)c(manage)g(the)g(state)g(of)g(the)g(History)g(library)0 -1837 y(when)f(y)o(ou)f(w)o(an)o(t)f(to)g(use)i(the)f(history)g(functions)h -(in)g(y)o(our)f(program.)1725 2021 y(F)l(unction)-1899 b Fh(void)20 -b Fg(using)p 258 2021 18 3 v 20 w(history)j Ff(\(\))120 2083 -y Fo(Begin)g(a)f(session)g(in)h(whic)o(h)g(the)f(history)g(functions)g(migh)o -(t)g(b)q(e)h(used.)40 b(This)23 b(initializes)i(the)120 2145 -y(in)o(teractiv)o(e)16 b(v)m(ariables.)1725 2328 y(F)l(unction)-1899 -b Fh(HISTORY_STATE)21 b(*)e Fg(history)p 582 2328 V 21 w(get)p -680 2328 V 21 w(history)p 876 2328 V 21 w(state)j Ff(\(\))120 -2391 y Fo(Return)16 b(a)f(structure)g(describing)i(the)e(curren)o(t)g(state)f -(of)h(the)g(input)i(history)l(.)1725 2574 y(F)l(unction)-1899 -b Fh(void)20 b Fg(history)p 302 2574 V 20 w(set)p 393 2574 -V 21 w(history)p 589 2574 V 21 w(state)j Ff(\()p Fn(HISTORY_STATE)13 -b(*state)p Ff(\))120 2636 y Fo(Set)i(the)h(state)e(of)h(the)g(history)g(list) -h(according)g(to)e Fj(state)p Fo(.)p eop -%%Page: 7 9 -8 bop 0 -83 a Fo(Chapter)15 b(2:)k(Programming)c(with)g(GNU)g(History)1039 -b(7)0 158 y Fi(2.3.2)30 b(History)15 b(List)g(Managemen)n(t)62 -295 y Fo(These)i(functions)h(manage)e(individual)k(en)o(tries)d(on)f(the)h -(history)g(list,)g(or)f(set)h(parameters)e(managing)i(the)0 -358 y(list)f(itself.)1725 520 y(F)l(unction)-1899 b Fh(void)20 -b Fg(add)p 219 520 18 3 v 20 w(history)j Ff(\()p Fn(char)14 -b(*string)p Ff(\))120 582 y Fo(Place)j Fj(string)k Fo(at)16 -b(the)g(end)i(of)e(the)g(history)h(list.)25 b(The)17 b(asso)q(ciated)g(data)f -(\014eld)h(\(if)g(an)o(y\))f(is)h(set)g(to)120 644 y Fn(NULL)p -Fo(.)1725 806 y(F)l(unction)-1899 b Fh(HIST_ENTRY)21 b(*)e -Fg(remo)n(v)n(e)p 509 806 V 20 w(history)k Ff(\()p Fn(int)14 -b(which)p Ff(\))120 868 y Fo(Remo)o(v)o(e)d(history)g(en)o(try)g(at)g -(o\013set)f Fj(whic)o(h)i Fo(from)f(the)g(history)l(.)19 b(The)11 -b(remo)o(v)o(ed)g(elemen)o(t)h(is)g(returned)120 930 y(so)j(y)o(ou)g(can)g -(free)g(the)h(line,)g(data,)e(and)i(con)o(taining)g(structure.)1725 -1092 y(F)l(unction)-1899 b Fh(HIST_ENTRY)21 b(*)e Fg(replace)p -505 1092 V 22 w(history)p 702 1092 V 20 w(en)n(try)24 b Ff(\()p -Fn(int)14 b(which,)g(char)h(*line,)f(char)208 1155 y(*data)p -Ff(\))120 1217 y Fo(Mak)o(e)d(the)i(history)f(en)o(try)g(at)f(o\013set)h -Fj(whic)o(h)h Fo(ha)o(v)o(e)e Fj(line)17 b Fo(and)12 b Fj(data)p -Fo(.)19 b(This)12 b(returns)g(the)h(old)g(en)o(try)e(so)120 -1279 y(y)o(ou)i(can)g(disp)q(ose)h(of)e(the)h(data.)19 b(In)13 -b(the)g(case)g(of)f(an)h(in)o(v)m(alid)i Fj(whic)o(h)p Fo(,)f(a)f -Fn(NULL)f Fo(p)q(oin)o(ter)i(is)f(returned.)1725 1441 y(F)l(unction)-1899 -b Fh(void)20 b Fg(sti\015e)p 245 1441 V 21 w(history)j Ff(\()p -Fn(int)14 b(max)p Ff(\))120 1503 y Fo(Sti\015e)i(the)f(history)h(list,)f -(remem)o(b)q(ering)h(only)g(the)f(last)g Fj(max)j Fo(en)o(tries.)1725 -1665 y(F)l(unction)-1899 b Fh(int)20 b Fg(unsti\015e)p 283 -1665 V 21 w(history)i Ff(\(\))120 1728 y Fo(Stop)13 b(sti\015ing)h(the)f -(history)l(.)19 b(This)14 b(returns)f(the)g(previous)h(amoun)o(t)e(the)h -(history)g(w)o(as)g(sti\015ed.)20 b(The)120 1790 y(v)m(alue)c(is)g(p)q -(ositiv)o(e)g(if)g(the)f(history)g(w)o(as)g(sti\015ed,)h(negativ)o(e)f(if)g -(it)h(w)o(asn't.)1725 1952 y(F)l(unction)-1899 b Fh(int)20 -b Fg(history)p 276 1952 V 20 w(is)p 334 1952 V 21 w(sti\015ed)k -Ff(\(\))120 2014 y Fo(Returns)16 b(non-zero)f(if)h(the)f(history)g(is)h -(sti\015ed,)g(zero)f(if)g(it)h(is)g(not.)0 2222 y Fi(2.3.3)30 -b(Information)14 b(Ab)r(out)h(the)g(History)g(List)62 2359 -y Fo(These)h(functions)g(return)f(information)g(ab)q(out)g(the)h(en)o(tire)f -(history)g(list)h(or)f(individual)j(list)f(en)o(tries.)1725 -2521 y(F)l(unction)-1899 b Fh(HIST_ENTRY)21 b(**)e Fg(history)p -530 2521 V 21 w(list)24 b Ff(\(\))120 2583 y Fo(Return)e(a)e -Fn(NULL)h Fo(terminated)g(arra)o(y)f(of)g Fn(HIST_ENTRY)g Fo(whic)o(h)i(is)f -(the)g(curren)o(t)g(input)h(history)l(.)120 2645 y(Elemen)o(t)16 -b(0)f(of)f(this)i(list)g(is)g(the)f(b)q(eginning)i(of)e(time.)20 -b(If)c(there)f(is)h(no)f(history)l(,)g(return)g Fn(NULL)p Fo(.)p -eop -%%Page: 8 10 -9 bop 0 -83 a Fo(8)1497 b(GNU)15 b(History)g(Library)1725 158 -y(F)l(unction)-1899 b Fh(int)20 b Fg(where)p 250 158 18 3 v -20 w(history)j Ff(\(\))120 221 y Fo(Returns)16 b(the)f(o\013set)f(of)h(the)g -(curren)o(t)g(history)g(elemen)o(t.)1725 378 y(F)l(unction)-1899 -b Fh(HIST_ENTRY)21 b(*)e Fg(curren)n(t)p 512 378 V 21 w(history)k -Ff(\(\))120 440 y Fo(Return)14 b(the)g(history)g(en)o(try)f(at)h(the)g -(curren)o(t)f(p)q(osition,)i(as)e(determined)j(b)o(y)d Fn(where_history)h -(\(\))p Fo(.)120 502 y(If)h(there)h(is)f(no)h(en)o(try)e(there,)h(return)g(a) -g Fn(NULL)g Fo(p)q(oin)o(ter.)1725 660 y(F)l(unction)-1899 -b Fh(HIST_ENTRY)21 b(*)e Fg(history)p 504 660 V 21 w(get)j -Ff(\()p Fn(int)15 b(offset)p Ff(\))120 722 y Fo(Return)g(the)g(history)f(en)o -(try)g(at)g(p)q(osition)i Fj(o\013set)p Fo(,)d(starting)h(from)g -Fn(history_base)p Fo(.)k(If)c(there)h(is)g(no)120 784 y(en)o(try)g(there,)g -(or)f(if)i Fj(o\013set)f Fo(is)h(greater)e(than)h(the)h(history)f(length,)g -(return)g(a)g Fn(NULL)g Fo(p)q(oin)o(ter.)1725 942 y(F)l(unction)-1899 -b Fh(int)20 b Fg(history)p 276 942 V 20 w(total)p 412 942 V -22 w(b)n(ytes)j Ff(\(\))120 1004 y Fo(Return)17 b(the)f(n)o(um)o(b)q(er)g(of) -g(b)o(ytes)g(that)f(the)h(primary)g(history)g(en)o(tries)h(are)e(using.)23 -b(This)17 b(function)120 1066 y(returns)e(the)g(sum)h(of)e(the)i(lengths)f -(of)g(all)h(the)g(lines)g(in)g(the)g(history)l(.)0 1265 y Fi(2.3.4)30 -b(Mo)n(ving)15 b(Around)h(the)f(History)g(List)62 1402 y Fo(These)h -(functions)g(allo)o(w)f(the)g(curren)o(t)h(index)g(in)o(to)f(the)h(history)f -(list)h(to)e(b)q(e)i(set)f(or)g(c)o(hanged.)1725 1559 y(F)l(unction)-1899 -b Fh(int)20 b Fg(history)p 276 1559 V 20 w(set)p 367 1559 V -21 w(p)r(os)h Ff(\()p Fn(int)15 b(pos)p Ff(\))120 1621 y Fo(Set)g(the)h(p)q -(osition)g(in)g(the)f(history)g(list)h(to)f Fj(p)q(os)p Fo(,)g(an)g(absolute) -g(index)i(in)o(to)e(the)g(list.)1725 1779 y(F)l(unction)-1899 -b Fh(HIST_ENTRY)21 b(*)e Fg(previous)p 540 1779 V 20 w(history)k -Ff(\(\))120 1841 y Fo(Bac)o(k)16 b(up)h(the)g(curren)o(t)f(history)h -(o\013set)e(to)h(the)h(previous)g(history)g(en)o(try)l(,)f(and)h(return)f(a)g -(p)q(oin)o(ter)120 1903 y(to)f(that)f(en)o(try)l(.)20 b(If)15 -b(there)g(is)h(no)f(previous)h(en)o(try)l(,)f(return)g(a)g -Fn(NULL)g Fo(p)q(oin)o(ter.)1725 2061 y(F)l(unction)-1899 b -Fh(HIST_ENTRY)21 b(*)e Fg(next)p 439 2061 V 21 w(history)k -Ff(\(\))120 2123 y Fo(Mo)o(v)o(e)c(the)h(curren)o(t)g(history)f(o\013set)g -(forw)o(ard)g(to)g(the)h(next)g(history)g(en)o(try)l(,)g(and)g(return)g(the)g -(a)120 2185 y(p)q(oin)o(ter)c(to)e(that)h(en)o(try)l(.)k(If)d(there)f(is)h -(no)f(next)g(en)o(try)l(,)g(return)g(a)g Fn(NULL)g Fo(p)q(oin)o(ter.)0 -2384 y Fi(2.3.5)30 b(Searc)n(hing)15 b(the)h(History)f(List)62 -2521 y Fo(These)e(functions)g(allo)o(w)f(searc)o(hing)h(of)f(the)g(history)g -(list)h(for)f(en)o(tries)h(con)o(taining)g(a)f(sp)q(eci\014c)i(string.)19 -b(Searc)o(h-)0 2583 y(ing)e(ma)o(y)g(b)q(e)g(p)q(erformed)g(b)q(oth)g(forw)o -(ard)f(and)h(bac)o(kw)o(ard)f(from)g(the)h(curren)o(t)f(history)h(p)q -(osition.)26 b(The)17 b(searc)o(h)0 2645 y(ma)o(y)d(b)q(e)i -Fj(anc)o(hored)p Fo(,)f(meaning)h(that)f(the)g(string)g(m)o(ust)g(matc)o(h)f -(at)h(the)g(b)q(eginning)i(of)e(the)h(history)f(en)o(try)l(.)p -eop -%%Page: 9 11 -10 bop 0 -83 a Fo(Chapter)15 b(2:)k(Programming)c(with)g(GNU)g(History)1039 -b(9)1725 158 y(F)l(unction)-1899 b Fh(int)20 b Fg(history)p -276 158 18 3 v 20 w(searc)n(h)j Ff(\()p Fn(char)14 b(*string,)g(int)h -(direction)p Ff(\))120 221 y Fo(Searc)o(h)k(the)g(history)g(for)f -Fj(string)p Fo(,)i(starting)e(at)g(the)h(curren)o(t)g(history)g(o\013set.)30 -b(If)19 b Fj(direction)h Fn(<)f Fo(0,)120 283 y(then)14 b(the)f(searc)o(h)g -(is)h(through)e(previous)i(en)o(tries,)g(else)g(through)f(subsequen)o(t.)20 -b(If)13 b Fj(string)k Fo(is)d(found,)120 345 y(then)f(the)g(curren)o(t)g -(history)g(index)i(is)e(set)g(to)f(that)h(history)g(en)o(try)l(,)f(and)i(the) -f(v)m(alue)h(returned)f(is)h(the)120 407 y(o\013set)h(in)i(the)f(line)i(of)d -(the)h(en)o(try)g(where)g Fj(string)k Fo(w)o(as)c(found.)22 -b(Otherwise,)17 b(nothing)f(is)h(c)o(hanged,)120 470 y(and)e(a)g(-1)g(is)h -(returned.)1725 659 y(F)l(unction)-1899 b Fh(int)20 b Fg(history)p -276 659 V 20 w(searc)n(h)p 452 659 V 21 w(pre\014x)i Ff(\()p -Fn(char)15 b(*string,)f(int)g(direction)p Ff(\))120 721 y Fo(Searc)o(h)22 -b(the)h(history)f(for)f Fj(string)p Fo(,)j(starting)e(at)f(the)i(curren)o(t)f -(history)g(o\013set.)40 b(The)22 b(searc)o(h)g(is)120 783 y(anc)o(hored:)i -(matc)o(hing)18 b(lines)h(m)o(ust)d(b)q(egin)j(with)f Fj(string)p -Fo(.)26 b(If)17 b Fj(direction)i Fn(<)e Fo(0,)g(then)h(the)f(searc)o(h)g(is) -120 845 y(through)e(previous)h(en)o(tries,)f(else)i(through)d(subsequen)o(t.) -21 b(If)16 b Fj(string)j Fo(is)d(found,)f(then)h(the)f(curren)o(t)120 -908 y(history)20 b(index)i(is)e(set)g(to)g(that)f(en)o(try)l(,)i(and)f(the)g -(return)h(v)m(alue)g(is)g(0.)34 b(Otherwise,)22 b(nothing)e(is)120 -970 y(c)o(hanged,)15 b(and)h(a)e(-1)h(is)h(returned.)1725 1159 -y(F)l(unction)-1899 b Fh(int)20 b Fg(history)p 276 1159 V 20 -w(searc)n(h)p 452 1159 V 21 w(p)r(os)h Ff(\()p Fn(char)15 b(*string,)f(int)g -(direction,)g(int)h(pos)p Ff(\))120 1221 y Fo(Searc)o(h)d(for)f -Fj(string)k Fo(in)d(the)g(history)f(list,)i(starting)e(at)g -Fj(p)q(os)p Fo(,)h(an)f(absolute)h(index)h(in)o(to)e(the)h(list.)19 -b(If)12 b Fj(di-)120 1283 y(rection)g Fo(is)h(negativ)o(e,)f(the)g(searc)o(h) -g(pro)q(ceeds)h(bac)o(kw)o(ard)e(from)g Fj(p)q(os)p Fo(,)i(otherwise)f(forw)o -(ard.)17 b(Returns)120 1345 y(the)e(absolute)h(index)g(of)f(the)g(history)h -(elemen)o(t)f(where)h Fj(string)j Fo(w)o(as)14 b(found,)h(or)g(-1)g -(otherwise.)0 1634 y Fi(2.3.6)30 b(Managing)14 b(the)i(History)f(File)62 -1780 y Fo(The)f(History)g(library)h(can)f(read)g(the)g(history)g(from)f(and)i -(write)f(it)g(to)f(a)h(\014le.)20 b(This)15 b(section)g(do)q(cumen)o(ts)f -(the)0 1842 y(functions)i(for)f(managing)g(a)f(history)i(\014le.)1725 -2031 y(F)l(unction)-1899 b Fh(int)20 b Fg(read)p 211 2031 V -20 w(history)i Ff(\()p Fn(char)15 b(*filename)p Ff(\))120 2093 -y Fo(Add)i(the)f(con)o(ten)o(ts)g(of)g Fj(\014lename)k Fo(to)c(the)h(history) -f(list,)h(a)f(line)i(at)e(a)g(time.)24 b(If)17 b Fj(\014lename)j -Fo(is)d Fn(NULL)p Fo(,)120 2155 y(then)f(read)f(from)f(`)p -Fn(~/.history)p Fo('.)k(Returns)e(0)e(if)i(successful,)g(or)f(errno)g(if)h -(not.)1725 2344 y(F)l(unction)-1899 b Fh(int)20 b Fg(read)p -211 2344 V 20 w(history)p 406 2344 V 20 w(range)i Ff(\()p Fn(char)15 -b(*filename,)e(int)i(from,)g(int)f(to)p Ff(\))120 2407 y Fo(Read)j(a)e(range) -h(of)f(lines)j(from)d Fj(\014lename)p Fo(,)i(adding)f(them)g(to)f(the)h -(history)g(list.)23 b(Start)15 b(reading)i(at)120 2469 y(line)f -Fj(from)f Fo(and)g(end)g(at)f Fj(to)p Fo(.)19 b(If)d Fj(from)e -Fo(is)h(zero,)f(start)g(at)g(the)h(b)q(eginning.)22 b(If)15 -b Fj(to)i Fo(is)e(less)g(than)g Fj(from)p Fo(,)120 2531 y(then)i(read)g(un)o -(til)h(the)f(end)g(of)g(the)g(\014le.)25 b(If)17 b Fj(\014lename)k -Fo(is)c Fn(NULL)p Fo(,)f(then)i(read)e(from)g(`)p Fn(~/.history)p -Fo('.)120 2593 y(Returns)g(0)f(if)g(successful,)h(or)f Fn(errno)g -Fo(if)g(not.)p eop -%%Page: 10 12 -11 bop 0 -83 a Fo(10)1474 b(GNU)15 b(History)g(Library)1725 -158 y(F)l(unction)-1899 b Fh(int)20 b Fg(write)p 229 158 18 -3 v 22 w(history)i Ff(\()p Fn(char)15 b(*filename)p Ff(\))120 -221 y Fo(W)l(rite)20 b(the)g(curren)o(t)f(history)h(to)f Fj(\014lename)p -Fo(,)i(o)o(v)o(erwriting)f Fj(\014lename)j Fo(if)d(necessary)l(.)34 -b(If)20 b Fj(\014lename)120 283 y Fo(is)d Fn(NULL)p Fo(,)g(then)g(write)g -(the)g(history)g(list)h(to)e(`)p Fn(~/.history)p Fo('.)23 b(V)l(alues)18 -b(returned)g(are)e(as)h(in)h Fn(read_)120 345 y(history)c(\(\))p -Fo(.)1725 504 y(F)l(unction)-1899 b Fh(int)20 b Fg(app)r(end)p -285 504 V 19 w(history)j Ff(\()p Fn(int)14 b(nelements,)g(char)h(*filename)p -Ff(\))120 566 y Fo(App)q(end)i(the)e(last)g Fj(nelemen)o(ts)j -Fo(of)d(the)g(history)g(list)h(to)f Fj(\014lename)p Fo(.)1725 -724 y(F)l(unction)-1899 b Fh(int)20 b Fg(history)p 276 724 -V 20 w(truncate)p 507 724 V 21 w(\014le)k Ff(\()p Fn(char)14 -b(*filename,)g(int)h(nlines)p Ff(\))120 787 y Fo(T)l(runcate)g(the)h(history) -f(\014le)h Fj(\014lename)p Fo(,)g(lea)o(ving)g(only)g(the)f(last)g -Fj(nlines)k Fo(lines.)0 988 y Fi(2.3.7)30 b(History)15 b(Expansion)62 -1125 y Fo(These)h(functions)g(implemen)o(t)g Fn(csh)p Fo(-lik)o(e)g(history)g -(expansion.)1725 1283 y(F)l(unction)-1899 b Fh(int)20 b Fg(history)p -276 1283 V 20 w(expand)j Ff(\()p Fn(char)14 b(*string,)g(char)h(**output)p -Ff(\))120 1345 y Fo(Expand)20 b Fj(string)p Fo(,)f(placing)i(the)e(result)h -(in)o(to)f Fj(output)p Fo(,)h(a)f(p)q(oin)o(ter)h(to)e(a)h(string)h(\(see)f -(Section)h(1.1)120 1408 y([History)15 b(In)o(teraction],)f(page)h(1\).)20 -b(Returns:)120 1555 y Fn(0)216 b Fo(If)21 b(no)g(expansions)h(to)q(ok)e -(place)h(\(or,)g(if)h(the)f(only)g(c)o(hange)g(in)h(the)f(text)f(w)o(as)g -(the)360 1618 y(de-slashifying)d(of)e(the)g(history)h(expansion)g(c)o -(haracter\);)120 1701 y Fn(1)216 b Fo(if)16 b(expansions)g(did)g(tak)o(e)e -(place;)120 1785 y Fn(-1)192 b Fo(if)16 b(there)f(w)o(as)f(an)h(error)g(in)h -(expansion;)120 1869 y Fn(2)216 b Fo(if)14 b(the)f(returned)h(line)h(should)f -(only)g(b)q(e)f(displa)o(y)o(ed,)i(but)e(not)g(executed,)h(as)f(with)h(the) -360 1931 y Fn(:p)h Fo(mo)q(di\014er)h(\(see)f(Section)h(1.1.3)e([Mo)q -(di\014ers],)h(page)g(2\).)120 2079 y(If)g(an)h(error)e(o)q(curred)i(in)g -(expansion,)f(then)h Fj(output)g Fo(con)o(tains)f(a)g(descriptiv)o(e)i(error) -d(message.)1725 2238 y(F)l(unction)-1899 b Fh(char)20 b(*)f -Fg(history)p 347 2238 V 21 w(arg)p 449 2238 V 19 w(extract)24 -b Ff(\()p Fn(int)14 b(first,)h(int)g(last,)f(char)h(*string)p -Ff(\))120 2300 y Fo(Extract)10 b(a)h(string)g(segmen)o(t)g(consisting)h(of)f -(the)g Fj(\014rst)h Fo(through)f Fj(last)h Fo(argumen)o(ts)e(presen)o(t)h(in) -h Fj(string)p Fo(.)120 2362 y(Argumen)o(ts)j(are)g(brok)o(en)g(up)g(as)g(in)h -(Bash.)1725 2521 y(F)l(unction)-1899 b Fh(char)20 b(*)f Fg(get)p -249 2521 V 21 w(history)p 445 2521 V 20 w(ev)n(en)n(t)25 b -Ff(\()p Fn(char)14 b(*string,)g(int)h(*cindex,)f(int)h(qchar)p -Ff(\))120 2583 y Fo(Returns)e(the)f(text)f(of)h(the)g(history)g(ev)o(en)o(t)f -(b)q(eginning)k(at)c Fj(string)16 b Fn(+)c Fj(*cindex)p Fo(.)20 -b Fj(*cindex)c Fo(is)d(mo)q(di\014ed)120 2645 y(to)h(p)q(oin)o(t)h(to)f -(after)h(the)f(ev)o(en)o(t)h(sp)q(eci\014er.)21 b(A)o(t)15 -b(function)g(en)o(try)l(,)f Fj(cindex)20 b Fo(p)q(oin)o(ts)15 -b(to)f(the)h(index)h(in)o(to)p eop -%%Page: 11 13 -12 bop 0 -83 a Fo(Chapter)15 b(2:)k(Programming)c(with)g(GNU)g(History)1017 -b(11)120 158 y Fj(string)17 b Fo(where)d(the)f(history)h(ev)o(en)o(t)f(sp)q -(eci\014cation)i(b)q(egins.)20 b Fj(qc)o(har)d Fo(is)c(a)g(c)o(haracter)g -(that)g(is)h(allo)o(w)o(ed)120 221 y(to)h(end)g(the)h(ev)o(en)o(t)f(sp)q -(eci\014cation)i(in)f(addition)g(to)f(the)g(\\normal")g(terminating)g(c)o -(haracters.)1725 394 y(F)l(unction)-1899 b Fh(char)20 b(**)f -Fg(history)p 373 394 18 3 v 21 w(tok)n(enize)25 b Ff(\()p Fn(char)14 -b(*string)p Ff(\))120 456 y Fo(Return)k(an)f(arra)o(y)f(of)h(tok)o(ens)f -(parsed)i(out)e(of)h Fj(string)p Fo(,)g(m)o(uc)o(h)h(as)e(the)i(shell)g(migh) -o(t.)26 b(The)17 b(tok)o(ens)120 519 y(are)c(split)h(on)f(white)g(space)h -(and)f(on)g(the)g(c)o(haracters)f Fn(\(\)<>;&|$)p Fo(,)g(and)h(shell)i -(quoting)e(con)o(v)o(en)o(tions)120 581 y(are)i(ob)q(ey)o(ed.)0 -840 y Fm(2.4)33 b(History)15 b(V)-6 b(ariables)62 981 y Fo(This)16 -b(section)g(describ)q(es)h(the)e(externally)h(visible)i(v)m(ariables)e(exp)q -(orted)g(b)o(y)f(the)g(GNU)g(History)g(Library)l(.)1736 1155 -y(V)l(ariable)-1899 b Fh(int)20 b Fg(history)p 276 1155 V 20 -w(base)120 1217 y Fo(The)15 b(logical)i(o\013set)d(of)h(the)g(\014rst)g(en)o -(try)g(in)h(the)f(history)g(list.)1736 1390 y(V)l(ariable)-1899 -b Fh(int)20 b Fg(history)p 276 1390 V 20 w(length)120 1453 -y Fo(The)15 b(n)o(um)o(b)q(er)h(of)f(en)o(tries)g(curren)o(tly)h(stored)f(in) -h(the)f(history)g(list.)1736 1626 y(V)l(ariable)-1899 b Fh(int)20 -b Fg(max)p 208 1626 V 19 w(input)p 360 1626 V 21 w(history)120 -1689 y Fo(The)12 b(maxim)o(um)g(n)o(um)o(b)q(er)g(of)f(history)h(en)o(tries.) -19 b(This)12 b(m)o(ust)f(b)q(e)h(c)o(hanged)g(using)h Fn(stifle_history)120 -1751 y(\(\))p Fo(.)1736 1924 y(V)l(ariable)-1899 b Fh(char)20 -b Fg(history)p 302 1924 V 20 w(expansion)p 569 1924 V 21 w(c)n(har)120 -1987 y Fo(The)15 b(c)o(haracter)g(that)f(starts)g(a)h(history)g(ev)o(en)o(t.) -20 b(The)15 b(default)h(is)g(`)p Fn(!)p Fo('.)1736 2160 y(V)l(ariable)-1899 -b Fh(char)20 b Fg(history)p 302 2160 V 20 w(subst)p 454 2160 -V 20 w(c)n(har)120 2222 y Fo(The)13 b(c)o(haracter)e(that)h(in)o(v)o(ok)o(es) -g(w)o(ord)g(substitution)h(if)g(found)g(at)e(the)i(start)e(of)h(a)g(line.)21 -b(The)12 b(default)120 2285 y(is)k(`)p Fn(^)p Fo('.)1736 2458 -y(V)l(ariable)-1899 b Fh(char)20 b Fg(history)p 302 2458 V -20 w(commen)n(t)p 552 2458 V 19 w(c)n(har)120 2521 y Fo(During)12 -b(tok)o(enization,)h(if)f(this)h(c)o(haracter)e(is)i(seen)f(as)g(the)g -(\014rst)f(c)o(haracter)g(of)h(a)g(w)o(ord,)f(then)i(it)f(and)120 -2583 y(all)19 b(subsequen)o(t)g(c)o(haracters)e(up)h(to)g(a)f(newline)j(are)e -(ignored,)h(suppressing)g(history)f(expansion)120 2645 y(for)d(the)g -(remainder)h(of)f(the)g(line.)21 b(This)16 b(is)g(disabled)h(b)o(y)e -(default.)p eop -%%Page: 12 14 -13 bop 0 -83 a Fo(12)1474 b(GNU)15 b(History)g(Library)1736 -158 y(V)l(ariable)-1899 b Fh(char)20 b(*)f Fg(history)p 347 -158 18 3 v 21 w(no)p 429 158 V 20 w(expand)p 629 158 V 20 w(c)n(hars)120 -221 y Fo(The)f(list)g(of)g(c)o(haracters)e(whic)o(h)j(inhibit)h(history)d -(expansion)i(if)f(found)g(immediately)h(follo)o(wing)120 283 -y Fj(history)p 261 283 14 2 v 16 w(expansion)p 472 283 V 18 -w(c)o(har)p Fo(.)g(The)d(default)f(is)h(whitespace)g(and)g(`)p -Fn(=)p Fo('.)0 575 y Fm(2.5)33 b(History)15 b(Programming)h(Example)62 -720 y Fo(The)g(follo)o(wing)g(program)e(demonstrates)g(simple)j(use)e(of)g -(the)g(GNU)g(History)g(Library)l(.)120 852 y Fn(main)23 b(\(\))120 -902 y({)168 951 y(char)g(line[1024],)f(*t;)168 1001 y(int)h(len,)g(done)h(=)g -(0;)168 1101 y(line[0])f(=)g(0;)168 1201 y(using_history)f(\(\);)168 -1250 y(while)h(\(!done\))215 1300 y({)263 1350 y(printf)g(\("history$)g("\);) -263 1400 y(fflush)g(\(stdout\);)263 1450 y(t)h(=)g(fgets)f(\(line,)g(sizeof)g -(\(line\))g(-)h(1,)f(stdin\);)263 1499 y(if)h(\(t)f(&&)h(*t\))311 -1549 y({)359 1599 y(len)f(=)h(strlen)f(\(t\);)359 1649 y(if)g(\(t[len)g(-)h -(1])g(==)f('\\n'\))406 1699 y(t[len)h(-)f(1])h(=)g('\\0';)311 -1748 y(})263 1848 y(if)g(\(!t\))311 1898 y(strcpy)f(\(line,)g("quit"\);)263 -1998 y(if)h(\(line[0]\))311 2047 y({)359 2097 y(char)f(*expansion;)359 -2147 y(int)g(result;)359 2247 y(result)g(=)g(history_expand)f(\(line,)h -(&expansion\);)359 2296 y(if)g(\(result\))406 2346 y(fprintf)g(\(stderr,)g -("\045s\\n",)g(expansion\);)359 2446 y(if)g(\(result)g(<)h(0)g(||)f(result)g -(==)h(2\))406 2496 y({)454 2545 y(free)f(\(expansion\);)454 -2595 y(continue;)406 2645 y(})p eop -%%Page: 13 15 -14 bop 0 -83 a Fo(Chapter)15 b(2:)k(Programming)c(with)g(GNU)g(History)1017 -b(13)359 208 y Fn(add_history)22 b(\(expansion\);)359 258 y(strncpy)h -(\(line,)g(expansion,)f(sizeof)h(\(line\))g(-)h(1\);)359 308 -y(free)f(\(expansion\);)311 358 y(})263 457 y(if)h(\(strcmp)f(\(line,)g -("quit"\))g(==)g(0\))311 507 y(done)g(=)h(1;)263 557 y(else)f(if)h(\(strcmp)f -(\(line,)g("save"\))g(==)h(0\))311 607 y(write_history)e(\("history_file"\);) -263 656 y(else)h(if)h(\(strcmp)f(\(line,)g("read"\))g(==)h(0\))311 -706 y(read_history)e(\("history_file"\);)263 756 y(else)h(if)h(\(strcmp)f -(\(line,)g("list"\))g(==)h(0\))311 806 y({)359 856 y(register)e(HIST_ENTRY)h -(**the_list;)359 906 y(register)f(int)i(i;)359 1005 y(the_list)e(=)i -(history_list)e(\(\);)359 1055 y(if)h(\(the_list\))406 1105 -y(for)h(\(i)f(=)h(0;)g(the_list[i];)e(i++\))454 1155 y(printf)h(\("\045d:)g -(\045s\\n",)g(i)h(+)g(history_base,)e(the_list[i]->line\);)311 -1204 y(})263 1254 y(else)h(if)h(\(strncmp)f(\(line,)g("delete",)g(6\))g(==)h -(0\))311 1304 y({)359 1354 y(int)f(which;)359 1404 y(if)g(\(\(sscanf)g -(\(line)g(+)h(6,)f("\045d",)h(&which\)\))e(==)i(1\))406 1453 -y({)454 1503 y(HIST_ENTRY)f(*entry)g(=)g(remove_history)f(\(which\);)454 -1553 y(if)i(\(!entry\))502 1603 y(fprintf)f(\(stderr,)f("No)i(such)f(entry)g -(\045d\\n",)g(which\);)454 1653 y(else)502 1703 y({)550 1752 -y(free)g(\(entry->line\);)550 1802 y(free)g(\(entry\);)502 -1852 y(})406 1902 y(})359 1952 y(else)406 2001 y({)454 2051 -y(fprintf)g(\(stderr,)g("non-numeric)f(arg)h(given)h(to)f(`delete'\\n"\);)406 -2101 y(})311 2151 y(})215 2201 y(})120 2250 y(})p eop -%%Page: 14 16 -15 bop 0 -83 a Fo(14)1474 b(GNU)15 b(History)g(Library)p eop -%%Page: 15 17 -16 bop 0 -83 a Fo(App)q(endix)17 b(A:)e(Concept)g(Index)1346 -b(15)0 158 y Fk(App)r(endix)13 b(A)41 b(Concept)15 b(Index)0 -405 y Fm(A)0 471 y Fe(anc)o(hored)f(searc)o(h)5 b Fd(:)i(:)f(:)g(:)g(:)g(:)g -(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g -(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)18 b Fe(8)0 -579 y Fm(E)0 646 y Fe(ev)o(en)o(t)13 b(designators)g Fd(:)6 -b(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g -(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)23 -b Fe(1)1015 405 y(expansion)5 b Fd(:)k(:)d(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:) -g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f -(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)18 b Fe(1)1015 -521 y Fm(H)1015 587 y Fe(history)d(ev)o(en)o(ts)5 b Fd(:)i(:)f(:)g(:)g(:)g(:) -g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g -(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)18 b -Fe(1)1015 646 y(History)c(Searc)o(hing)7 b Fd(:)h(:)e(:)g(:)g(:)g(:)g(:)h(:)f -(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g -(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)20 b Fe(8)p eop -%%Page: 16 18 -17 bop 0 -83 a Fo(16)1474 b(GNU)15 b(History)g(Library)p eop -%%Page: 17 19 -18 bop 0 -83 a Fo(App)q(endix)17 b(B:)e(F)l(unction)h(and)g(V)l(ariable)g -(Index)1069 b(17)0 158 y Fk(App)r(endix)13 b(B)41 b(F)-7 b(unction)15 -b(and)g(V)-7 b(ariable)14 b(Index)0 405 y Fm(A)0 471 y Fc(add)p -62 471 12 2 v 13 w(history)8 b Fd(:)s(:)e(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g -(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g -(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)20 b Fe(7)0 529 y Fc(append)p -122 529 V 12 w(history)9 b Fd(:)d(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g -(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f -(:)g(:)g(:)g(:)24 b Fe(10)0 654 y Fm(C)0 720 y Fc(current)p -142 720 V 11 w(history)9 b Fd(:)d(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g -(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g -(:)g(:)g(:)g(:)24 b Fe(8)0 845 y Fm(G)0 911 y Fc(get)p 62 911 -V 13 w(history)p 215 911 V 11 w(event)9 b Fd(:)d(:)g(:)g(:)g(:)g(:)g(:)g(:)g -(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f -(:)g(:)g(:)g(:)g(:)23 b Fe(10)0 1036 y Fm(H)0 1102 y Fc(history)p -142 1102 V 11 w(arg)p 213 1102 V 13 w(extract)8 b Fd(:)t(:)e(:)g(:)g(:)g(:)g -(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g -(:)g(:)g(:)g(:)g(:)21 b Fe(10)0 1160 y Fc(history)p 142 1160 -V 11 w(base)e Fd(:)6 b(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:) -g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h -(:)f(:)g(:)20 b Fe(11)0 1218 y Fc(history)p 142 1218 V 11 w(comment)p -293 1218 V 12 w(char)g Fd(:)6 b(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f -(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)21 -b Fe(11)0 1276 y Fc(history)p 142 1276 V 11 w(expand)10 b Fd(:)c(:)g(:)g(:)g -(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g -(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)24 b Fe(10)0 -1335 y Fc(history)p 142 1335 V 11 w(expansion)p 333 1335 V -11 w(char)17 b Fd(:)7 b(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g -(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)19 b Fe(11)0 -1393 y Fc(history)p 142 1393 V 11 w(get)8 b Fd(:)d(:)h(:)g(:)g(:)g(:)g(:)h(:) -f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g -(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)20 b Fe(8)0 -1451 y Fc(history)p 142 1451 V 11 w(get)p 213 1451 V 13 w(history)p -366 1451 V 12 w(state)t Fd(:)t(:)6 b(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g -(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)17 b Fe(6)0 -1509 y Fc(history)p 142 1509 V 11 w(is)p 193 1509 V 14 w(stifled)7 -b Fd(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g -(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)23 b -Fe(7)0 1567 y Fc(history)p 142 1567 V 11 w(length)16 b Fd(:)6 -b(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g -(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)18 -b Fe(11)0 1625 y Fc(history)p 142 1625 V 11 w(list)7 b Fd(:)t(:)g(:)f(:)g(:)g -(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g -(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)19 -b Fe(7)0 1683 y Fc(history)p 142 1683 V 11 w(no)p 193 1683 -V 14 w(expand)p 327 1683 V 12 w(chars)f Fd(:)6 b(:)g(:)g(:)g(:)g(:)g(:)h(:)f -(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)20 -b Fe(12)0 1741 y Fc(history)p 142 1741 V 11 w(search)t Fd(:)t(:)6 -b(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g -(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)17 -b Fe(9)0 1800 y Fc(history)p 142 1800 V 11 w(search)p 273 1800 -V 12 w(pos)9 b Fd(:)d(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g -(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)23 -b Fe(9)0 1858 y Fc(history)p 142 1858 V 11 w(search)p 273 1858 -V 12 w(prefix)6 b Fd(:)t(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g -(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)19 -b Fe(9)0 1916 y Fc(history)p 142 1916 V 11 w(set)p 213 1916 -V 13 w(history)p 366 1916 V 12 w(state)t Fd(:)t(:)6 b(:)g(:)g(:)g(:)g(:)g(:)g -(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)17 -b Fe(6)0 1974 y Fc(history)p 142 1974 V 11 w(set)p 213 1974 -V 13 w(pos)5 b Fd(:)h(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g -(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g -(:)g(:)18 b Fe(8)0 2032 y Fc(history)p 142 2032 V 11 w(subst)p -253 2032 V 13 w(char)k Fd(:)6 b(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g -(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)24 -b Fe(11)1015 405 y Fc(history)p 1157 405 V 12 w(tokenize)9 -b Fd(:)s(:)d(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g -(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)22 -b Fe(11)1015 463 y Fc(history)p 1157 463 V 12 w(total)p 1269 -463 V 12 w(bytes)9 b Fd(:)t(:)d(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g -(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)22 -b Fe(8)1015 521 y Fc(history)p 1157 521 V 12 w(truncate)p 1329 -521 V 11 w(file)5 b Fd(:)g(:)h(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:) -f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)19 -b Fe(10)1015 629 y Fm(M)1015 695 y Fc(max)p 1077 695 V 13 w(input)p -1190 695 V 13 w(history)14 b Fd(:)6 b(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g -(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g -(:)g(:)17 b Fe(11)1015 803 y Fm(N)1015 870 y Fc(next)p 1097 -870 V 13 w(history)7 b Fd(:)s(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g -(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g -(:)g(:)g(:)g(:)g(:)g(:)g(:)20 b Fe(8)1015 978 y Fm(P)1015 1044 -y Fc(previous)p 1177 1044 V 12 w(history)7 b Fd(:)f(:)g(:)g(:)g(:)g(:)g(:)g -(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h -(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)23 b Fe(8)1015 1152 y Fm(R)1015 -1218 y Fc(read)p 1097 1218 V 13 w(history)7 b Fd(:)s(:)f(:)g(:)g(:)g(:)g(:)g -(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f -(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)20 b Fe(9)1015 -1276 y Fc(read)p 1097 1276 V 13 w(history)p 1250 1276 V 11 -w(range)9 b Fd(:)d(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:) -g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)23 -b Fe(9)1015 1335 y Fc(remove)p 1137 1335 V 12 w(history)t Fd(:)t(:)6 -b(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g -(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)17 -b Fe(7)1015 1393 y Fc(replace)p 1157 1393 V 12 w(history)p -1309 1393 V 11 w(entry)6 b Fd(:)f(:)h(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h -(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)19 -b Fe(7)1015 1501 y Fm(S)1015 1567 y Fc(stifle)p 1137 1567 V -12 w(history)t Fd(:)t(:)6 b(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h -(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g -(:)g(:)g(:)g(:)17 b Fe(7)1015 1675 y Fm(U)1015 1741 y Fc(unstifle)p -1177 1741 V 12 w(history)7 b Fd(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h -(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g -(:)g(:)g(:)g(:)23 b Fe(7)1015 1800 y Fc(using)p 1117 1800 V -13 w(history)5 b Fd(:)s(:)h(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g -(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g -(:)g(:)h(:)f(:)g(:)18 b Fe(6)1015 1907 y Fm(W)1015 1974 y Fc(where)p -1117 1974 V 13 w(history)5 b Fd(:)s(:)h(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g -(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g -(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)18 b Fe(8)1015 2032 y Fc(write)p -1117 2032 V 13 w(history)5 b Fd(:)s(:)h(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g -(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g(:)g -(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)18 b Fe(9)p eop -%%Page: 18 20 -19 bop 0 -83 a Fo(18)1474 b(GNU)15 b(History)g(Library)p eop -%%Page: -1 21 -20 bop 1937 -83 a Fo(i)0 158 y Fk(T)-7 b(able)15 b(of)g(Con)n(ten)n(ts)0 -333 y Fm(1)67 b(Using)22 b(History)h(In)n(teractiv)n(ely)9 -b Fb(:)k(:)d(:)g(:)g(:)h(:)f(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g -(:)h(:)f(:)g(:)g(:)h(:)f(:)g(:)31 b Fm(1)149 411 y Fo(1.1)45 -b(History)15 b(In)o(teraction)9 b Fa(:)f(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g -(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g -(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)23 -b Fo(1)299 473 y(1.1.1)44 b(Ev)o(en)o(t)14 b(Designators)6 -b Fa(:)h(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g -(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f -(:)g(:)g(:)20 b Fo(1)299 535 y(1.1.2)44 b(W)l(ord)15 b(Designators)9 -b Fa(:)d(:)h(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h -(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g -(:)h(:)f(:)23 b Fo(2)299 597 y(1.1.3)44 b(Mo)q(di\014ers)14 -b Fa(:)8 b(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:) -g(:)g(:)g(:)h(:)f(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g -(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)28 b Fo(2)0 722 -y Fm(2)67 b(Programming)23 b(with)g(GNU)f(History)13 b Fb(:)e(:)f(:)g(:)g(:)h -(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)36 b -Fm(5)149 800 y Fo(2.1)45 b(In)o(tro)q(duction)16 b(to)f(History)6 -b Fa(:)h(:)g(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g -(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f -(:)g(:)g(:)g(:)h(:)f(:)g(:)20 b Fo(5)149 862 y(2.2)45 b(History)15 -b(Storage)d Fa(:)7 b(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g -(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f -(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)27 -b Fo(5)149 924 y(2.3)45 b(History)15 b(F)l(unctions)c Fa(:)d(:)f(:)h(:)f(:)g -(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f -(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h -(:)f(:)g(:)g(:)g(:)h(:)25 b Fo(6)299 986 y(2.3.1)44 b(Initializing)18 -b(History)d(and)h(State)e(Managemen)o(t)f Fa(:)7 b(:)g(:)g(:)h(:)f(:)g(:)g(:) -g(:)h(:)f(:)g(:)g(:)g(:)h(:)27 b Fo(6)299 1049 y(2.3.2)44 b(History)15 -b(List)h(Managemen)o(t)c Fa(:)7 b(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h -(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g -(:)28 b Fo(7)299 1111 y(2.3.3)44 b(Information)15 b(Ab)q(out)g(the)h(History) -f(List)5 b Fa(:)i(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g -(:)g(:)g(:)h(:)f(:)g(:)g(:)19 b Fo(7)299 1173 y(2.3.4)44 b(Mo)o(ving)15 -b(Around)g(the)g(History)g(List)6 b Fa(:)i(:)f(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:) -g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)20 -b Fo(8)299 1236 y(2.3.5)44 b(Searc)o(hing)16 b(the)f(History)g(List)7 -b Fa(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f -(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)21 b -Fo(8)299 1298 y(2.3.6)44 b(Managing)15 b(the)g(History)g(File)5 -b Fa(:)j(:)f(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g -(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)19 b -Fo(9)299 1360 y(2.3.7)44 b(History)15 b(Expansion)d Fa(:)7 -b(:)g(:)h(:)f(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g -(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)26 -b Fo(10)149 1422 y(2.4)45 b(History)15 b(V)l(ariables)5 b Fa(:)k(:)e(:)g(:)g -(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g -(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f -(:)g(:)g(:)g(:)h(:)f(:)g(:)20 b Fo(11)149 1485 y(2.5)45 b(History)15 -b(Programming)f(Example)8 b Fa(:)g(:)f(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:) -g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f -(:)g(:)g(:)g(:)23 b Fo(12)0 1609 y Fm(App)r(endix)h(A)67 b(Concept)22 -b(Index)15 b Fb(:)c(:)f(:)h(:)f(:)g(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g -(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)g(:)g(:)h(:)37 b Fm(15)0 1749 -y(App)r(endix)24 b(B)67 b(F)-6 b(unction)25 b(and)e(V)-6 b(ariable)24 -b(Index)8 b Fb(:)j(:)f(:)g(:)h(:)f(:)g(:)g(:)g(:)h(:)f(:)31 -b Fm(17)p eop -%%Page: -2 22 -21 bop 0 -83 a Fo(ii)1496 b(GNU)15 b(History)g(Library)p eop -%%Trailer -end -userdict /end-hook known{end-hook}if -%%EOF diff --git a/lib/readline/doc/rlman.texinfo b/lib/readline/doc/rlman.texinfo index ec14066..655f3db 100644 --- a/lib/readline/doc/rlman.texinfo +++ b/lib/readline/doc/rlman.texinfo @@ -7,13 +7,13 @@ @setchapternewpage odd @ignore -last change: Thu Jul 21 16:02:40 EDT 1994 +last change: Thu Mar 21 16:06:39 EST 1996 @end ignore -@set EDITION 2.0 -@set VERSION 2.0 -@set UPDATED 21 July 1994 -@set UPDATE-MONTH July 1994 +@set EDITION 2.1 +@set VERSION 2.1 +@set UPDATED 21 March 1996 +@set UPDATE-MONTH March 1996 @ifinfo This document describes the GNU Readline Library, a utility which aids @@ -45,7 +45,6 @@ by the Foundation. @end ifinfo @titlepage -@sp 10 @title GNU Readline Library @subtitle Edition @value{EDITION}, for @code{Readline Library} Version @value{VERSION}. @subtitle @value{UPDATE-MONTH} diff --git a/lib/readline/doc/rltech.texinfo b/lib/readline/doc/rltech.texinfo index 636c923..6704d0e 100644 --- a/lib/readline/doc/rltech.texinfo +++ b/lib/readline/doc/rltech.texinfo @@ -8,7 +8,7 @@ This document describes the GNU Readline Library, a utility for aiding in the consitency of user interface across discrete programs that need to provide a command line interface. -Copyright (C) 1988, 1994 Free Software Foundation, Inc. +Copyright (C) 1988, 1994, 1996 Free Software Foundation, Inc. Permission is granted to make and distribute verbatim copies of this manual provided the copyright notice and this permission notice @@ -273,6 +273,10 @@ The prompt Readline uses. This is set from the argument to @code{readline ()}, and should not be assigned to directly. @end deftypevar +@deftypevar {char *} rl_library_version +The version number of this revision of the library. +@end deftypevar + @deftypevar {char *} rl_terminal_name The terminal type, used for initialization. @end deftypevar @@ -301,6 +305,30 @@ If non-zero, this is the address of a function to call periodically when readline is waiting for terminal input. @end deftypevar +@deftypevar {Function *} rl_getc_function +If non-zero, @code{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 @code{readline} character input function +(@pxref{Utility Functions}). +@end deftypevar + +@deftypevar {Function *} rl_redisplay_function +If non-zero, @code{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 @code{readline} +redisplay function (@pxref{Redisplay}). +@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 + @node Readline Convenience Functions @section Readline Convenience Functions @@ -314,6 +342,7 @@ when readline is waiting for terminal input. * Redisplay:: Functions to control line display. * Modifying Text:: Functions to modify @code{rl_line_buffer}. * Utility Functions:: Generally useful functions and hooks. +* Alternate Interface:: Using Readline in a `callback' fashion. @end menu @node Function Naming @@ -611,6 +640,10 @@ the input stream via @var{pending input} (@pxref{Readline Variables}) and @code{rl_stuff_char ()}, macros, and characters read from the keyboard. @end deftypefun +@deftypefun int rl_getc (FILE *) +Return the next character available from 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 @@ -666,6 +699,37 @@ lowercase character. If @var{c} is a number, return the value it represents. @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 (char *prompt, Vfunction *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 callback when a complete line of input has been entered. +@end deftypefun + +@deftypefun void rl_callback_read_char () +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. @code{EOF} is indicated by calling @var{lhandler} with a +@code{NULL} line. +@end deftypefun + +@deftypefun void rl_callback_handler_remove () +Restore the terminal to its initial state and remove the line handler. +This may be called from within a callback as well as independently. +@end deftypefun + @subsection An Example Here is a function which changes lowercase characters to their uppercase @@ -894,6 +958,40 @@ returns @code{NULL}, or if this variable is set to @code{NULL}, then array of strings returned will be used. @end deftypevar +@deftypevar {CPFunction *} 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 {CPFunction *} 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 {Function *} 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 int rl_completion_query_items Up to this many items will be displayed in response to a possible-completions call. After that, we ask the user if she is sure @@ -907,6 +1005,10 @@ which break words for completion in Bash, i.e., @code{" \t\n\"\\'`@@$><=;|&@{("}. @end deftypevar +@deftypevar {char *} rl_basic_quote_characters +List of quote characters which can cause a word break. +@end deftypevar + @deftypevar {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 @@ -920,6 +1022,11 @@ Completion occurs on the entire substring, and within the substring unless they also appear within this list. @end deftypevar +@deftypevar {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 empty. +@end deftypevar + @deftypevar {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. @@ -928,6 +1035,16 @@ For instance, Bash sets this variable to "$@@" so that it can complete shell variables and hostnames. @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 custom completion functions to +provide the ``most sensible word separator character'' according to +an application-specific command line syntax specification. +@end deftypevar + @deftypevar int rl_ignore_completion_duplicates If non-zero, then disallow duplicates in the matches. Default is 1. @end deftypevar @@ -945,9 +1062,15 @@ characters. 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_completer_word_break_chars}. This is @emph{always} non-zero +@code{rl_filename_quote_chars}. This is @emph{always} non-zero on entry, and can only be changed within a completion entry generator -function. +function. The quoting is effected via a call to the function pointed to +by @code{rl_filename_quoting_function}. +@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 @deftypevar {Function *} rl_ignore_some_completions_function @@ -1174,10 +1297,11 @@ initialize_readline () rl_attempted_completion_function = (CPPFunction *)fileman_completion; @} -/* Attempt to complete on the contents of TEXT. START and END show the - region of TEXT that contains the word to complete. We can use the - entire line in case we want to do some simple parsing. Return the - array of matches, or NULL if there aren't any. */ +/* 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. Return the array of matches, + or NULL if there aren't any. */ char ** fileman_completion (text, start, end) char *text; diff --git a/lib/readline/doc/rluser.texinfo b/lib/readline/doc/rluser.texinfo index 3567549..65111f3 100644 --- a/lib/readline/doc/rluser.texinfo +++ b/lib/readline/doc/rluser.texinfo @@ -10,7 +10,7 @@ use these features. There is a document entitled "readline.texinfo" which contains both end-user and programmer documentation for the GNU Readline Library. -Copyright (C) 1988 Free Software Foundation, Inc. +Copyright (C) 1988, 1991, 1993, 1996 Free Software Foundation, Inc. Authored by Brian Fox and Chet Ramey. @@ -39,7 +39,7 @@ into another language, under the above conditions for modified versions. @node Command Line Editing @chapter Command Line Editing -This chapter describes the basic features of the GNU +This chapter describes the basic features of the @sc{GNU} command line editing interface. @menu @@ -59,11 +59,12 @@ The following paragraphs describe the notation used to represent keystrokes. The text @key{C-k} is read as `Control-K' and describes the character -produced when the Control key is depressed and the @key{k} key is struck. +produced when the @key{k} key is pressed while the Control key +is depressed. The text @key{M-k} is read as `Meta-K' and describes the character produced when the meta key (if you have one) is depressed, and the @key{k} -key is struck. If you do not have a meta key, the identical keystroke +key is pressed. If you do not have a meta key, the identical keystroke can be generated by typing @key{ESC} @i{first}, and then typing @key{k}. Either process is known as @dfn{metafying} the @key{k} key. @@ -73,7 +74,7 @@ character produced by @dfn{metafying} @key{C-k}. In addition, several keys have their own names. Specifically, @key{DEL}, @key{ESC}, @key{LFD}, @key{SPC}, @key{RET}, and @key{TAB} all stand for themselves when seen in this text, or in an init file -(@pxref{Readline Init File}, for more info). +(@pxref{Readline Init File}). @node Readline Interaction @section Readline Interaction @@ -95,10 +96,14 @@ regardless of the location of the cursor within the line. * Readline Movement Commands:: Moving about the input line. * Readline Killing Commands:: How to delete text, and how to get it back! * Readline Arguments:: Giving numeric arguments to commands. -@end menu +* Searching:: Searching through previous lines. + @end menu @node Readline Bare Essentials @subsection Readline Bare Essentials +@cindex notation, readline +@cindex command editing +@cindex editing command lines In order to enter characters into the line, simply type them. The typed character appears where the cursor was, and then the cursor moves one @@ -164,8 +169,8 @@ operate on characters while meta keystrokes operate on words. @node Readline Killing Commands @subsection Readline Killing Commands -@cindex Killing text -@cindex Yanking text +@cindex killing text +@cindex yanking text @dfn{Killing} text means to delete the text from the line, but to save it away for later use, usually by @dfn{yanking} (re-inserting) @@ -180,7 +185,7 @@ that when you yank it back, you get it all. The kill ring is not line specific; the text that you killed on a previously typed line is available to be yanked back later, when you are typing another line. -@cindex Kill ring +@cindex kill ring Here is the list of commands for killing text. @@ -222,24 +227,59 @@ argument acts as a repeat count, other times it is the @i{sign} of the argument that is significant. If you pass a negative argument to a command which normally acts in a forward direction, that command will act in a backward direction. For example, to kill text back to the -start of the line, you might type @key{M--} @key{C-k}. +start of the line, you might type @w{@kbd{M-- C-k}}. The general way to pass numeric arguments to a command is to type meta digits before the command. If the first `digit' you type is a minus sign (@key{-}), then the sign of the argument will be negative. Once you have typed one meta digit to get the argument started, you can type the remainder of the digits, and then the command. For example, to give -the @key{C-d} command an argument of 10, you could type @key{M-1 0 C-d}. +the @key{C-d} command an argument of 10, you could type @samp{M-1 0 C-d}. + +@node Searching +@subsection Searching for Commands in the History +Readline provides commands for searching through the command history +@ifset BashFeatures +(@pxref{Bash History Facilities}) +@end ifset +for lines containing a specified string. +There are two search modes: @var{incremental} and @var{non-incremental}. + +Incremental searches begin before the user has finished typing the +search string. +As each character of the search string is typed, readline displays +the next entry from the history matching the string typed so far. +An incremental search requires only as many characters as needed to +find the desired history entry. +The Escape character is used to terminate an incremental search. +Control-J will also terminate the search. +Control-G will abort an incremental search and restore the original +line. +When the search is terminated, the history entry containing the +search string becomes the current line. +To find other matching entries in the history list, type Control-S or +Control-R as appropriate. +This will search backward or forward in the history for the next +entry matching the search string typed so far. +Any other key sequence bound to a readline command will terminate +the search and execute that command. +For instance, a @code{newline} will terminate the search and accept +the line, thereby executing the command from the history list. + +Non-incremental searches read the entire search string before starting +to search for matching history lines. The search string may be +typed by the user or part of the contents of the current line. @node Readline Init File @section Readline Init File +@cindex initialization file, readline -Although the Readline library comes with a set of Emacs-like +Although the Readline library comes with a set of @code{emacs}-like keybindings installed by default, it is possible that you would like to use a different set of keybindings. You can customize programs that use Readline by putting -commands in an @dfn{init} file in your home directory. The name of this +commands in an @dfn{inputrc} file in your home directory. The name of this @ifset BashFeatures file is taken from the value of the shell variable @code{INPUTRC}. If @end ifset @@ -255,17 +295,20 @@ In addition, the @code{C-x C-r} command re-reads this init file, thus incorporating any changes that you might have made to it. @menu -* Readline Init Syntax:: Syntax for the commands in the inputrc file. +* Readline Init File Syntax:: Syntax for the commands in the inputrc file. + * Conditional Init Constructs:: Conditional key bindings in the inputrc file. + +* Sample Init File:: An example inputrc file. @end menu -@node Readline Init Syntax -@subsection Readline Init Syntax +@node Readline Init File Syntax +@subsection Readline Init File Syntax There are only a few basic constructs allowed in the Readline init file. Blank lines are ignored. -Lines beginning with a @key{#} are comments. -Lines beginning with a @key{$} indicate conditional +Lines beginning with a @samp{#} are comments. +Lines beginning with a @samp{$} indicate conditional constructs (@pxref{Conditional Init Constructs}). Other lines denote variable settings and key bindings. @@ -284,61 +327,20 @@ so few, in fact, that we just list them here: @table @code -@item editing-mode -@vindex editing-mode -The @code{editing-mode} variable controls which editing mode you are -using. By default, Readline starts up in Emacs editing mode, where -the keystrokes are most similar to Emacs. This variable can be -set to either @code{emacs} or @code{vi}. - -@item horizontal-scroll-mode -@vindex horizontal-scroll-mode -This variable can be set to either @code{On} or @code{Off}. Setting it -to @code{On} means that the text of the lines that you edit will scroll -horizontally on a single screen line when they are longer than the width -of the screen, instead of wrapping onto a new screen line. By default, -this variable is set to @code{Off}. - -@item mark-modified-lines -@vindex mark-modified-lines -This variable, when set to @code{On}, says to display an asterisk -(@samp{*}) at the start of history lines which have been modified. -This variable is @code{off} by default. - @item bell-style @vindex bell-style Controls what happens when Readline wants to ring the terminal bell. -If set to @code{none}, Readline never rings the bell. If set to -@code{visible}, Readline uses a visible bell if one is available. -If set to @code{audible} (the default), Readline attempts to ring +If set to @samp{none}, Readline never rings the bell. If set to +@samp{visible}, Readline uses a visible bell if one is available. +If set to @samp{audible} (the default), Readline attempts to ring the terminal's bell. @item comment-begin @vindex comment-begin The string to insert at the beginning of the line when the -@code{vi-comment} command is executed. The default value +@code{insert-comment} command is executed. The default value is @code{"#"}. -@item meta-flag -@vindex meta-flag -If set to @code{on}, Readline will enable eight-bit input (it -will not strip the eighth bit from the characters it reads), -regardless of what the terminal claims it can support. The -default value is @code{off}. - -@item convert-meta -@vindex convert-meta -If set to @code{on}, Readline will convert characters with the -eigth bit set to an ASCII key sequence by stripping the eigth -bit and prepending an @key{ESC} character, converting them to a -meta-prefixed key sequence. The default value is @code{on}. - -@item output-meta -@vindex output-meta -If set to @code{on}, Readline will display characters with the -eighth bit set directly rather than as a meta-prefixed escape -sequence. The default is @code{off}. - @item completion-query-items @vindex completion-query-items The number of possible completions that determines when the user is @@ -348,6 +350,45 @@ Readline will ask the user whether or not he wishes to view them; otherwise, they are simply listed. The default limit is @code{100}. +@item convert-meta +@vindex convert-meta +If set to @samp{on}, Readline will convert characters with the +eigth bit set to an ASCII key sequence by stripping the eigth +bit and prepending an @key{ESC} character, converting them to a +meta-prefixed key sequence. The default value is @samp{on}. + +@item disable-completion +@vindex disable-completion +If set to @samp{On}, readline will inhibit word completion. +Completion characters will be inserted into the line as if they had +been mapped to @code{self-insert}. The default is @samp{off}. + +@item editing-mode +@vindex editing-mode +The @code{editing-mode} variable controls which editing mode you are +using. By default, Readline starts up in Emacs editing mode, where +the keystrokes are most similar to Emacs. This variable can be +set to either @samp{emacs} or @samp{vi}. + +@item enable-keypad +@vindex enable-keypad +When set to @samp{on}, readline will try to enable the application +keypad when it is called. Some systems need this to enable the +arrow keys. The default is @samp{off}. + +@item expand-tilde +@vindex expand-tilde +If set to @samp{on}, tilde expansion is performed when Readline +attempts word completion. The default is @samp{off}. + +@item horizontal-scroll-mode +@vindex horizontal-scroll-mode +This variable can be set to either @samp{on} or @samp{off}. Setting it +to @samp{on} means that the text of the lines that you edit will scroll +horizontally on a single screen line when they are longer than the width +of the screen, instead of wrapping onto a new screen line. By default, +this variable is set to @samp{off}. + @item keymap @vindex keymap Sets Readline's idea of the current keymap for key binding commands. @@ -357,7 +398,6 @@ Acceptable @code{keymap} names are @code{emacs-meta}, @code{emacs-ctlx}, @code{vi}, -@code{vi-move}, @code{vi-command}, and @code{vi-insert}. @code{vi} is equivalent to @code{vi-command}; @code{emacs} is @@ -365,18 +405,44 @@ equivalent to @code{emacs-standard}. The default value is @code{emacs}. The value of the @code{editing-mode} variable also affects the default keymap. +@item mark-directories +If set to @samp{on}, completed directory names have a slash +appended. The default is @samp{on}. + +@item mark-modified-lines +@vindex mark-modified-lines +This variable, when set to @samp{on}, says to display an asterisk +(@samp{*}) at the start of history lines which have been modified. +This variable is @samp{off} by default. + +@item input-meta +@vindex input-meta +@vindex meta-flag +If set to @samp{on}, Readline will enable eight-bit input (it +will not strip the eighth bit from the characters it reads), +regardless of what the terminal claims it can support. The +default value is @samp{off}. The name @code{meta-flag} is a +synonym for this variable. + +@item output-meta +@vindex output-meta +If set to @samp{on}, Readline will display characters with the +eighth bit set directly rather than as a meta-prefixed escape +sequence. The default is @samp{off}. + @item show-all-if-ambiguous @vindex show-all-if-ambiguous This alters the default behavior of the completion functions. If -set to @code{on}, +set to @samp{on}, words which have more than one possible completion cause the matches to be listed immediately instead of ringing the bell. -The default value is @code{off}. +The default value is @samp{off}. -@item expand-tilde -@vindex expand-tilde -If set to @code{on}, tilde expansion is performed when Readline -attempts word completion. The default is @code{off}. +@item visible-stats +@vindex visible-stats +If set to @samp{on}, a character denoting a file's type +is appended to the filename when listing possible +completions. The default is @samp{off}. @end table @@ -399,13 +465,13 @@ comfortable for you. @example Control-u: universal-argument Meta-Rubout: backward-kill-word -Control-o: ">&output" +Control-o: "> output" @end example In the above example, @samp{C-u} is bound to the function @code{universal-argument}, and @samp{C-o} is bound to run the macro expressed on the right hand side (that is, to insert the text -@samp{>&output} into the line). +@samp{> output} into the line). @item @w{"@var{keyseq}": @var{function-name} or @var{macro}} @var{keyseq} differs from @var{keyname} above in that strings @@ -445,10 +511,10 @@ backslash When entering the text of a macro, single or double quotes should be used to indicate a macro definition. Unquoted text is assumed to be a function name. Backslash -will quote any character in the macro text, including @key{"} -and @key{'}. -For example, the following binding will make @kbd{C-x \} -insert a single @key{\} into the line: +will quote any character in the macro text, including @samp{"} +and @samp{'}. +For example, the following binding will make @samp{C-x \} +insert a single @samp{\} into the line: @example "\C-x\\": "\\" @end example @@ -464,7 +530,7 @@ compilation features of the C preprocessor which allows key bindings and variable settings to be performed as the result of tests. There are three parser directives used. -@ftable @code +@table @code @item $if The @code{$if} construct allows bindings to be made based on the editing mode, the terminal being used, or the application using @@ -486,7 +552,7 @@ key bindings, perhaps to bind the key sequences output by the terminal's function keys. The word on the right side of the @samp{=} is tested against the full name of the terminal and the portion of the terminal name before the first @samp{-}. This -allows @var{sun} to match both @var{sun} and @var{sun-cmd}, +allows @code{sun} to match both @code{sun} and @code{sun-cmd}, for instance. @item application @@ -497,7 +563,7 @@ This could be used to bind key sequences to functions useful for a specific program. For instance, the following command adds a key sequence that quotes the current or previous word in Bash: @example -$if bash +$if Bash # Quote the current or previous word "\C-xq": "\eb\"\ef\"" $endif @@ -511,7 +577,109 @@ This command, as you saw in the previous example, terminates an @item $else Commands in this branch of the @code{$if} directive are executed if the test fails. -@end ftable +@end table + +@node Sample Init File +@subsection Sample Init File + +Here is an example of an inputrc file. This illustrates key +binding, variable assignment, and conditional syntax. + +@example +@page +# This file controls the behaviour of line input editing for +# programs that use the Gnu Readline library. Existing programs +# include FTP, Bash, and Gdb. +# +# You can re-read the inputrc file with C-x C-r. +# Lines beginning with '#' are comments. +# +# Set various bindings for emacs mode. + +set editing-mode emacs + +$if mode=emacs + +Meta-Control-h: backward-kill-word Text after the function name is ignored + +# +# Arrow keys in keypad mode +# +#"\M-OD" backward-char +#"\M-OC" forward-char +#"\M-OA" previous-history +#"\M-OB" next-history +# +# Arrow keys in ANSI mode +# +"\M-[D" backward-char +"\M-[C" forward-char +"\M-[A" previous-history +"\M-[B" next-history +# +# Arrow keys in 8 bit keypad mode +# +#"\M-\C-OD" backward-char +#"\M-\C-OC" forward-char +#"\M-\C-OA" previous-history +#"\M-\C-OB" next-history +# +# Arrow keys in 8 bit ANSI mode +# +#"\M-\C-[D" backward-char +#"\M-\C-[C" forward-char +#"\M-\C-[A" previous-history +#"\M-\C-[B" next-history + +C-q: quoted-insert + +$endif + +# An old-style binding. This happens to be the default. +TAB: complete + +# Macros that are convenient for shell interaction +$if Bash +# edit the path +"\C-xp": "PATH=$@{PATH@}\e\C-e\C-a\ef\C-f" +# prepare to type a quoted word -- insert open and close double quotes +# and move to just after the open quote +"\C-x\"": "\"\"\C-b" +# insert a backslash (testing backslash escapes in sequences and macros) +"\C-x\\": "\\" +# Quote the current or previous word +"\C-xq": "\eb\"\ef\"" +# Add a binding to refresh the line, which is unbound +"\C-xr": redraw-current-line +# Edit variable on current line. +"\M-\C-v": "\C-a\C-k$\C-y\M-\C-e\C-a\C-y=" +$endif + +# use a visible bell if one is available +set bell-style visible + +# don't strip characters to 7 bits when reading +set input-meta on + +# allow iso-latin1 characters to be inserted rather than converted to +# prefix-meta sequences +set convert-meta off + +# display characters with the eighth bit set directly rather than +# as meta-prefixed characters +set output-meta on + +# if there are more than 150 possible completions for a word, ask the +# user if he wants to see all of them +set completion-query-items 150 + +# For FTP +$if Ftp +"\C-xg": "get \M-?" +"\C-xt": "put \M-?" +"\M-.": yank-last-arg +$endif +@end example @node Bindable Readline Commands @section Bindable Readline Commands @@ -527,6 +695,9 @@ the test fails. * Miscellaneous Commands:: Other miscellaneous commands. @end menu +This section describes Readline commands that may be bound to key +sequences. + @node Commands For Moving @subsection Commands For Moving @ftable @code @@ -608,12 +779,13 @@ for a string supplied by the user. @item history-search-forward () Search forward through the history for the string of characters -between the start of the current line and the current point. This -is a non-incremental search. By default, this command is unbound. +between the start of the current line and the current cursor +position (the `point'). This is a non-incremental search. By +default, this command is unbound. @item history-search-backward () Search backward through the history for the string of characters -between the start of the current line and the current point. This +between the start of the current line and the point. This is a non-incremental search. By default, this command is unbound. @item yank-nth-arg (M-C-y) @@ -624,8 +796,8 @@ in the previous command begin with word 0). A negative argument inserts the @var{n}th word from the end of the previous command. @item yank-last-arg (M-., M-_) -Insert last argument to the previous command (the last word on the -previous line). With an +Insert last argument to the previous command (the last word of the +previous history entry). With an argument, behave exactly like @code{yank-nth-arg}. @end ftable @@ -637,7 +809,7 @@ argument, behave exactly like @code{yank-nth-arg}. @item delete-char (C-d) Delete the character under the cursor. If the cursor is at the beginning of the line, there are no characters in the line, and -the last character typed was not C-d, then return EOF. +the last character typed was not @kbd{C-d}, then return @code{EOF}. @item backward-delete-char (Rubout) Delete the character behind the cursor. A numeric arg says to kill @@ -714,6 +886,23 @@ boundary. The killed text is saved on the kill-ring. @item delete-horizontal-space () Delete all spaces and tabs around point. By default, this is unbound. +@item kill-region () +Kill the text between the point and the @emph{mark} (saved +cursor position. This text is referred to as the @var{region}. +By default, this command is unbound. + +@item copy-region-as-kill () +Copy the text in the region to the kill buffer, so you can yank it +right away. By default, this command is unbound. + +@item copy-backward-word () +Copy the word before point to the kill buffer. +By default, this command is unbound. + +@item copy-forward-word () +Copy the word following point to the kill buffer. +By default, this command is unbound. + @item yank (C-y) Yank the top of the kill ring into the buffer at the current cursor position. @@ -729,7 +918,7 @@ the prior command is yank or yank-pop. @item digit-argument (M-0, M-1, ... M--) Add this digit to the argument already accumulating, or start a new -argument. M-- starts a negative argument. +argument. @key{M--} starts a negative argument. @item universal-argument () Each time this is executed, the argument count is multiplied by four. @@ -750,18 +939,74 @@ you can do command completion, if you are typing in a symbol to GDB, you can do symbol name completion, if you are typing in a variable to Bash, you can do variable name completion, and so on. @ifset BashFeatures -See the Bash manual page for a complete list of available completion -functions. +Bash attempts completion treating the text as a variable (if the +text begins with @samp{$}), username (if the text begins with +@samp{~}), hostname (if the text begins with @samp{@@}), or +command (including aliases and functions) in turn. If none +of these produces a match, filename completion is attempted. @end ifset @item possible-completions (M-?) List the possible completions of the text before the cursor. -@item insert-completions () +@item insert-completions (M-*) Insert all completions of the text before point that would have -been generated by @code{possible-completions}. By default, this -is not bound to a key. +been generated by @code{possible-completions}. +@ifset BashFeatures +@item complete-filename (M-/) +Attempt filename completion on the text before point. + +@item possible-filename-completions (C-x /) +List the possible completions of the text before point, +treating it as a filename. + +@item complete-username (M-~) +Attempt completion on the text before point, treating +it as a username. + +@item possible-username-completions (C-x ~) +List the possible completions of the text before point, +treating it as a username. + +@item complete-variable (M-$) +Attempt completion on the text before point, treating +it as a shell variable. + +@item possible-variable-completions (C-x $) +List the possible completions of the text before point, +treating it as a shell variable. + +@item complete-hostname (M-@@) +Attempt completion on the text before point, treating +it as a hostname. + +@item possible-hostname-completions (C-x @@) +List the possible completions of the text before point, +treating it as a hostname. + +@item complete-command (M-!) +Attempt completion on the text before point, treating +it as a command name. Command completion attempts to +match the text against aliases, reserved words, shell +functions, builtins, and finally executable filenames, +in that order. + +@item possible-command-completions (C-x !) +List the possible completions of the text before point, +treating it as a command name. + +@item dynamic-complete-history (M-TAB) +Attempt completion on the text before point, comparing +the text against lines from the history list for possible +completion matches. + +@item complete-into-braces (M-@{) +Perform filename completion and return the list of possible completions +enclosed within braces so the list is available to the shell +(@pxref{Brace Expansion}). + +@end ifset @end ftable @node Keyboard Macros @@ -786,7 +1031,7 @@ in the macro appear as if typed at the keyboard. @ftable @code @item re-read-init-file (C-x C-r) -Read in the contents of your init file, and incorporate +Read in the contents of the inputrc file, and incorporate any bindings or variable assignments found there. @item abort (C-g) @@ -794,9 +1039,9 @@ Abort the current editing command and ring the terminal's bell (subject to the setting of @code{bell-style}). -@item do-uppercase-version (M-a, M-b, ...) -Run the command that is bound to the corresoponding uppercase -character. +@item do-uppercase-version (M-a, M-b, M-@var{x}, @dots{}) +If the metafied character @var{x} is lowercase, run the command +that is bound to the corresponding uppercase character. @item prefix-meta (ESC) Make the next character that you type be metafied. This is for people @@ -813,13 +1058,59 @@ command enough times to get back to the beginning. @item tilde-expand (M-~) Perform tilde expansion on the current word. +@item set-mark (C-@@) +Set the mark to the current point. If a +numeric argument is supplied, the mark is set to that position. + +@item exchange-point-and-mark (C-x C-x) +Swap the point with the mark. The current cursor position is set to +the saved position, and the old cursor position is saved as the mark. + +@item character-search (C-]) +A character is read and point is moved to the next occurrence of that +character. A negative count searches for previous occurrences. + +@item character-search-backward (M-C-]) +A character is read and point is moved to the previous occurrence +of that character. A negative count searches for subsequent +occurrences. + +@item insert-comment (M-#) +The value of the @code{comment-begin} +variable is inserted at the beginning of the current line, +and the line is accepted as if a newline had been typed. +@ifset BashFeatures +This makes the current line a shell comment. +@end ifset + @item dump-functions () Print all of the functions and their key bindings to the readline output stream. If a numeric argument is supplied, the output is formatted in such a way that it can be made part -of an @var{inputrc} file. +of an @var{inputrc} file. This command is unbound by default. + +@item dump-variables () +Print all of the settable variables and their values to the +readline output stream. If a numeric argument is supplied, +the output is formatted in such a way that it can be made part +of an @var{inputrc} file. This command is unbound by default. + +@item dump-macros () +Print all of the readline key sequences bound to macros and the +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 @var{inputrc} file. This command is unbound by default. @ifset BashFeatures +@item glob-expand-word (C-x *) +The word before point is treated as a pattern for pathname expansion, +and the list of matching file names is inserted, replacing the word. + +@item glob-list-expansions (C-x g) +The list of expansions that would have been generated by +@code{glob-expand-word} +is inserted into the line, replacing the word before point. + @item display-shell-version (C-x C-v) Display version information about the current instance of Bash. @@ -841,7 +1132,7 @@ argument is ignored. @item emacs-editing-mode (C-e) When in @code{vi} editing mode, this causes a switch back to -emacs editing mode, as if the command @code{set -o emacs} had +@code{emacs} editing mode, as if the command @samp{set -o emacs} had been executed. @end ifset @@ -854,15 +1145,15 @@ been executed. While the Readline library does not have a full set of @code{vi} editing functions, it does contain enough to allow simple editing of the line. The Readline @code{vi} mode behaves as specified in -the Posix 1003.2 standard. +the @sc{POSIX} 1003.2 standard. @ifset BashFeatures -In order to switch interactively between @code{Emacs} and @code{Vi} -editing modes, use the @code{set -o emacs} and @code{set -o vi} +In order to switch interactively between @code{emacs} and @code{vi} +editing modes, use the @samp{set -o emacs} and @samp{set -o vi} commands (@pxref{The Set Builtin}). @end ifset @ifclear BashFeatures -In order to switch interactively between @code{Emacs} and @code{Vi} +In order to switch interactively between @code{emacs} and @code{vi} editing modes, use the command M-C-j (toggle-editing-mode). @end ifclear The Readline default is @code{emacs} mode. @@ -871,5 +1162,5 @@ When you enter a line in @code{vi} mode, you are already placed in `insertion' mode, as if you had typed an @samp{i}. Pressing @key{ESC} switches you into `command' mode, where you can edit the text of the line with the standard @code{vi} movement keys, move to previous -history lines with @samp{k}, and following lines with @samp{j}, and +history lines with @samp{k} and subsequent lines with @samp{j}, and so forth. diff --git a/lib/readline/doc/texindex.c b/lib/readline/doc/texindex.c deleted file mode 100644 index 9233bab..0000000 --- a/lib/readline/doc/texindex.c +++ /dev/null @@ -1,1666 +0,0 @@ -/* Prepare TeX index dribble output into an actual index. - - Version 1.45 - - Copyright (C) 1987, 1991, 1992 Free Software Foundation, Inc. - - This program 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. - - This program 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 this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ - - -#include -#include -#include -#include "getopt.h" -#include "bashansi.h" - -#if !defined (errno) -extern int errno; -#endif - -#if defined (HAVE_UNISTD_H) -# include -#else /* !HAVE_UNISTD_H */ -extern long lseek (); -#endif /* !HAVE_UNISTD_H */ - -extern char *mktemp (); - -#if !defined (HAVE_STRERROR) -extern int sys_nerr; -extern char *sys_errlist[]; -#endif - -#include - -#if defined (_AIX) || !defined (_POSIX_VERSION) -# include -#endif - -#include - -#define TI_NO_ERROR 0 -#define TI_FATAL_ERROR 1 - -#if !defined (SEEK_SET) -# define SEEK_SET 0 -# define SEEK_CUR 1 -# define SEEK_END 2 -#endif /* !SEEK_SET */ - -/* When sorting in core, this structure describes one line - and the position and length of its first keyfield. */ -struct lineinfo -{ - char *text; /* The actual text of the line. */ - union { - char *text; /* The start of the key (for textual comparison). */ - long number; /* The numeric value (for numeric comparison). */ - } key; - long keylen; /* Length of KEY field. */ -}; - -/* This structure describes a field to use as a sort key. */ -struct keyfield -{ - int startwords; /* Number of words to skip. */ - int startchars; /* Number of additional chars to skip. */ - int endwords; /* Number of words to ignore at end. */ - int endchars; /* Ditto for characters of last word. */ - char ignore_blanks; /* Non-zero means ignore spaces and tabs. */ - char fold_case; /* Non-zero means case doesn't matter. */ - char reverse; /* Non-zero means compare in reverse order. */ - char numeric; /* Non-zeros means field is ASCII numeric. */ - char positional; /* Sort according to file position. */ - char braced; /* Count balanced-braced groupings as fields. */ -}; - -/* Vector of keyfields to use. */ -struct keyfield keyfields[3]; - -/* Number of keyfields stored in that vector. */ -int num_keyfields = 3; - -/* Vector of input file names, terminated with a null pointer. */ -char **infiles; - -/* Vector of corresponding output file names, or NULL, meaning default it - (add an `s' to the end). */ -char **outfiles; - -/* Length of `infiles'. */ -int num_infiles; - -/* Pointer to the array of pointers to lines being sorted. */ -char **linearray; - -/* The allocated length of `linearray'. */ -long nlines; - -/* Directory to use for temporary files. On Unix, it ends with a slash. */ -char *tempdir; - -/* Start of filename to use for temporary files. */ -char *tempbase; - -/* Number of last temporary file. */ -int tempcount; - -/* Number of last temporary file already deleted. - Temporary files are deleted by `flush_tempfiles' in order of creation. */ -int last_deleted_tempcount; - -/* During in-core sort, this points to the base of the data block - which contains all the lines of data. */ -char *text_base; - -/* Additional command switches .*/ - -/* Nonzero means do not delete tempfiles -- for debugging. */ -int keep_tempfiles; - -/* The name this program was run with. */ -char *program_name; - -/* Forward declarations of functions in this file. */ - -void decode_command (); -void sort_in_core (); -void sort_offline (); -char **parsefile (); -char *find_field (); -char *find_pos (); -long find_value (); -char *find_braced_pos (); -char *find_braced_end (); -void writelines (); -int compare_field (); -int compare_full (); -long readline (); -int merge_files (); -int merge_direct (); -void pfatal_with_name (); -void fatal (); -void error (); -void *xmalloc (), *xrealloc (); -char *concat (); -char *maketempname (); -void flush_tempfiles (); -char *tempcopy (); - -#define MAX_IN_CORE_SORT 500000 - -void -main (argc, argv) - int argc; - char **argv; -{ - int i; - - tempcount = 0; - last_deleted_tempcount = 0; - program_name = argv[0]; - - /* Describe the kind of sorting to do. */ - /* The first keyfield uses the first braced field and folds case. */ - keyfields[0].braced = 1; - keyfields[0].fold_case = 1; - keyfields[0].endwords = -1; - keyfields[0].endchars = -1; - - /* The second keyfield uses the second braced field, numerically. */ - keyfields[1].braced = 1; - keyfields[1].numeric = 1; - keyfields[1].startwords = 1; - keyfields[1].endwords = -1; - keyfields[1].endchars = -1; - - /* The third keyfield (which is ignored while discarding duplicates) - compares the whole line. */ - keyfields[2].endwords = -1; - keyfields[2].endchars = -1; - - decode_command (argc, argv); - - tempbase = mktemp (concat ("txiXXXXXX", "", "")); - - /* Process input files completely, one by one. */ - - for (i = 0; i < num_infiles; i++) - { - int desc; - long ptr; - char *outfile; - - desc = open (infiles[i], O_RDONLY, 0); - if (desc < 0) - pfatal_with_name (infiles[i]); - lseek (desc, 0L, SEEK_END); - ptr = lseek (desc, 0L, SEEK_CUR); - - close (desc); - - outfile = outfiles[i]; - if (!outfile) - { - outfile = concat (infiles[i], "s", ""); - } - - if (ptr < MAX_IN_CORE_SORT) - /* Sort a small amount of data. */ - sort_in_core (infiles[i], ptr, outfile); - else - sort_offline (infiles[i], ptr, outfile); - } - - flush_tempfiles (tempcount); - exit (TI_NO_ERROR); -} - -void -usage () -{ - fprintf (stderr, "\ -Usage: %s [-k] infile [-o outfile] ...\n", program_name); - exit (1); -} - -/* Decode the command line arguments to set the parameter variables - and set up the vector of keyfields and the vector of input files. */ - -void -decode_command (argc, argv) - int argc; - char **argv; -{ - int optc; - char **ip; - char **op; - - /* Store default values into parameter variables. */ - - tempdir = getenv ("TMPDIR"); - if (tempdir == NULL) - tempdir = "/tmp/"; - else - tempdir = concat (tempdir, "/", ""); - - keep_tempfiles = 0; - - /* Allocate ARGC input files, which must be enough. */ - - infiles = (char **) xmalloc (argc * sizeof (char *)); - outfiles = (char **) xmalloc (argc * sizeof (char *)); - ip = infiles; - op = outfiles; - - while ((optc = getopt (argc, argv, "-ko:")) != EOF) - { - switch (optc) - { - case 1: /* Non-option filename. */ - *ip++ = optarg; - *op++ = NULL; - break; - - case 'k': - keep_tempfiles = 1; - break; - - case 'o': - if (op > outfiles) - *(op - 1) = optarg; - break; - - default: - usage (); - } - } - - /* Record number of keyfields and terminate list of filenames. */ - num_infiles = ip - infiles; - *ip = 0; - if (num_infiles == 0) - usage (); -} - -/* Return a name for a temporary file. */ - -char * -maketempname (count) - int count; -{ - char tempsuffix[10]; - sprintf (tempsuffix, "%d", count); - return concat (tempdir, tempbase, tempsuffix); -} - -/* Delete all temporary files up to TO_COUNT. */ - -void -flush_tempfiles (to_count) - int to_count; -{ - if (keep_tempfiles) - return; - while (last_deleted_tempcount < to_count) - unlink (maketempname (++last_deleted_tempcount)); -} - -/* Copy the input file open on IDESC into a temporary file - and return the temporary file name. */ - -#define BUFSIZE 1024 - -char * -tempcopy (idesc) - int idesc; -{ - char *outfile = maketempname (++tempcount); - int odesc; - char buffer[BUFSIZE]; - - odesc = open (outfile, O_WRONLY | O_CREAT, 0666); - - if (odesc < 0) - pfatal_with_name (outfile); - - while (1) - { - int nread = read (idesc, buffer, BUFSIZE); - write (odesc, buffer, nread); - if (!nread) - break; - } - - close (odesc); - - return outfile; -} - -/* Compare LINE1 and LINE2 according to the specified set of keyfields. */ - -int -compare_full (line1, line2) - char **line1, **line2; -{ - int i; - - /* Compare using the first keyfield; - if that does not distinguish the lines, try the second keyfield; - and so on. */ - - for (i = 0; i < num_keyfields; i++) - { - long length1, length2; - char *start1 = find_field (&keyfields[i], *line1, &length1); - char *start2 = find_field (&keyfields[i], *line2, &length2); - int tem = compare_field (&keyfields[i], start1, length1, *line1 - text_base, - start2, length2, *line2 - text_base); - if (tem) - { - if (keyfields[i].reverse) - return -tem; - return tem; - } - } - - return 0; /* Lines match exactly. */ -} - -/* Compare LINE1 and LINE2, described by structures - in which the first keyfield is identified in advance. - For positional sorting, assumes that the order of the lines in core - reflects their nominal order. */ - -int -compare_prepared (line1, line2) - struct lineinfo *line1, *line2; -{ - int i; - int tem; - char *text1, *text2; - - /* Compare using the first keyfield, which has been found for us already. */ - if (keyfields->positional) - { - if (line1->text - text_base > line2->text - text_base) - tem = 1; - else - tem = -1; - } - else if (keyfields->numeric) - tem = line1->key.number - line2->key.number; - else - tem = compare_field (keyfields, line1->key.text, line1->keylen, 0, - line2->key.text, line2->keylen, 0); - if (tem) - { - if (keyfields->reverse) - return -tem; - return tem; - } - - text1 = line1->text; - text2 = line2->text; - - /* Compare using the second keyfield; - if that does not distinguish the lines, try the third keyfield; - and so on. */ - - for (i = 1; i < num_keyfields; i++) - { - long length1, length2; - char *start1 = find_field (&keyfields[i], text1, &length1); - char *start2 = find_field (&keyfields[i], text2, &length2); - int tem = compare_field (&keyfields[i], start1, length1, text1 - text_base, - start2, length2, text2 - text_base); - if (tem) - { - if (keyfields[i].reverse) - return -tem; - return tem; - } - } - - return 0; /* Lines match exactly. */ -} - -/* Like compare_full but more general. - You can pass any strings, and you can say how many keyfields to use. - POS1 and POS2 should indicate the nominal positional ordering of - the two lines in the input. */ - -int -compare_general (str1, str2, pos1, pos2, use_keyfields) - char *str1, *str2; - long pos1, pos2; - int use_keyfields; -{ - int i; - - /* Compare using the first keyfield; - if that does not distinguish the lines, try the second keyfield; - and so on. */ - - for (i = 0; i < use_keyfields; i++) - { - long length1, length2; - char *start1 = find_field (&keyfields[i], str1, &length1); - char *start2 = find_field (&keyfields[i], str2, &length2); - int tem = compare_field (&keyfields[i], start1, length1, pos1, - start2, length2, pos2); - if (tem) - { - if (keyfields[i].reverse) - return -tem; - return tem; - } - } - - return 0; /* Lines match exactly. */ -} - -/* Find the start and length of a field in STR according to KEYFIELD. - A pointer to the starting character is returned, and the length - is stored into the int that LENGTHPTR points to. */ - -char * -find_field (keyfield, str, lengthptr) - struct keyfield *keyfield; - char *str; - long *lengthptr; -{ - char *start; - char *end; - char *(*fun) (); - - if (keyfield->braced) - fun = find_braced_pos; - else - fun = find_pos; - - start = (*fun) (str, keyfield->startwords, keyfield->startchars, - keyfield->ignore_blanks); - if (keyfield->endwords < 0) - { - if (keyfield->braced) - end = find_braced_end (start); - else - { - end = start; - while (*end && *end != '\n') - end++; - } - } - else - { - end = (*fun) (str, keyfield->endwords, keyfield->endchars, 0); - if (end - str < start - str) - end = start; - } - *lengthptr = end - start; - return start; -} - -/* Return a pointer to a specified place within STR, - skipping (from the beginning) WORDS words and then CHARS chars. - If IGNORE_BLANKS is nonzero, we skip all blanks - after finding the specified word. */ - -char * -find_pos (str, words, chars, ignore_blanks) - char *str; - int words, chars; - int ignore_blanks; -{ - int i; - char *p = str; - - for (i = 0; i < words; i++) - { - char c; - /* Find next bunch of nonblanks and skip them. */ - while ((c = *p) == ' ' || c == '\t') - p++; - while ((c = *p) && c != '\n' && !(c == ' ' || c == '\t')) - p++; - if (!*p || *p == '\n') - return p; - } - - while (*p == ' ' || *p == '\t') - p++; - - for (i = 0; i < chars; i++) - { - if (!*p || *p == '\n') - break; - p++; - } - return p; -} - -/* Like find_pos but assumes that each field is surrounded by braces - and that braces within fields are balanced. */ - -char * -find_braced_pos (str, words, chars, ignore_blanks) - char *str; - int words, chars; - int ignore_blanks; -{ - int i; - int bracelevel; - char *p = str; - char c; - - for (i = 0; i < words; i++) - { - bracelevel = 1; - while ((c = *p++) != '{' && c != '\n' && c) - /* Do nothing. */ ; - if (c != '{') - return p - 1; - while (bracelevel) - { - c = *p++; - if (c == '{') - bracelevel++; - if (c == '}') - bracelevel--; - if (c == 0 || c == '\n') - return p - 1; - } - } - - while ((c = *p++) != '{' && c != '\n' && c) - /* Do nothing. */ ; - - if (c != '{') - return p - 1; - - if (ignore_blanks) - while ((c = *p) == ' ' || c == '\t') - p++; - - for (i = 0; i < chars; i++) - { - if (!*p || *p == '\n') - break; - p++; - } - return p; -} - -/* Find the end of the balanced-brace field which starts at STR. - The position returned is just before the closing brace. */ - -char * -find_braced_end (str) - char *str; -{ - int bracelevel; - char *p = str; - char c; - - bracelevel = 1; - while (bracelevel) - { - c = *p++; - if (c == '{') - bracelevel++; - if (c == '}') - bracelevel--; - if (c == 0 || c == '\n') - return p - 1; - } - return p - 1; -} - -long -find_value (start, length) - char *start; - long length; -{ - while (length != 0L) - { - if (isdigit (*start)) - return atol (start); - length--; - start++; - } - return 0l; -} - -/* Vector used to translate characters for comparison. - This is how we make all alphanumerics follow all else, - and ignore case in the first sorting. */ -int char_order[256]; - -void -init_char_order () -{ - int i; - for (i = 1; i < 256; i++) - char_order[i] = i; - - for (i = '0'; i <= '9'; i++) - char_order[i] += 512; - - for (i = 'a'; i <= 'z'; i++) - { - char_order[i] = 512 + i; - char_order[i + 'A' - 'a'] = 512 + i; - } -} - -/* Compare two fields (each specified as a start pointer and a character count) - according to KEYFIELD. - The sign of the value reports the relation between the fields. */ - -int -compare_field (keyfield, start1, length1, pos1, start2, length2, pos2) - struct keyfield *keyfield; - char *start1; - long length1; - long pos1; - char *start2; - long length2; - long pos2; -{ - if (keyfields->positional) - { - if (pos1 > pos2) - return 1; - else - return -1; - } - if (keyfield->numeric) - { - long value = find_value (start1, length1) - find_value (start2, length2); - if (value > 0) - return 1; - if (value < 0) - return -1; - return 0; - } - else - { - char *p1 = start1; - char *p2 = start2; - char *e1 = start1 + length1; - char *e2 = start2 + length2; - - while (1) - { - int c1, c2; - - if (p1 == e1) - c1 = 0; - else - c1 = *p1++; - if (p2 == e2) - c2 = 0; - else - c2 = *p2++; - - if (char_order[c1] != char_order[c2]) - return char_order[c1] - char_order[c2]; - if (!c1) - break; - } - - /* Strings are equal except possibly for case. */ - p1 = start1; - p2 = start2; - while (1) - { - int c1, c2; - - if (p1 == e1) - c1 = 0; - else - c1 = *p1++; - if (p2 == e2) - c2 = 0; - else - c2 = *p2++; - - if (c1 != c2) - /* Reverse sign here so upper case comes out last. */ - return c2 - c1; - if (!c1) - break; - } - - return 0; - } -} - -/* A `struct linebuffer' is a structure which holds a line of text. - `readline' reads a line from a stream into a linebuffer - and works regardless of the length of the line. */ - -struct linebuffer -{ - long size; - char *buffer; -}; - -/* Initialize LINEBUFFER for use. */ - -void -initbuffer (linebuffer) - struct linebuffer *linebuffer; -{ - linebuffer->size = 200; - linebuffer->buffer = (char *) xmalloc (200); -} - -/* Read a line of text from STREAM into LINEBUFFER. - Return the length of the line. */ - -long -readline (linebuffer, stream) - struct linebuffer *linebuffer; - FILE *stream; -{ - char *buffer = linebuffer->buffer; - char *p = linebuffer->buffer; - char *end = p + linebuffer->size; - - while (1) - { - int c = getc (stream); - if (p == end) - { - buffer = (char *) xrealloc (buffer, linebuffer->size *= 2); - p += buffer - linebuffer->buffer; - end += buffer - linebuffer->buffer; - linebuffer->buffer = buffer; - } - if (c < 0 || c == '\n') - { - *p = 0; - break; - } - *p++ = c; - } - - return p - buffer; -} - -/* Sort an input file too big to sort in core. */ - -void -sort_offline (infile, nfiles, total, outfile) - char *infile; - int nfiles; - long total; - char *outfile; -{ - /* More than enough. */ - int ntemps = 2 * (total + MAX_IN_CORE_SORT - 1) / MAX_IN_CORE_SORT; - char **tempfiles = (char **) xmalloc (ntemps * sizeof (char *)); - FILE *istream = fopen (infile, "r"); - int i; - struct linebuffer lb; - long linelength; - int failure = 0; - - initbuffer (&lb); - - /* Read in one line of input data. */ - - linelength = readline (&lb, istream); - - if (lb.buffer[0] != '\\' && lb.buffer[0] != '@') - { - error ("%s: not a texinfo index file", infile); - return; - } - - /* Split up the input into `ntemps' temporary files, or maybe fewer, - and put the new files' names into `tempfiles' */ - - for (i = 0; i < ntemps; i++) - { - char *outname = maketempname (++tempcount); - FILE *ostream = fopen (outname, "w"); - long tempsize = 0; - - if (!ostream) - pfatal_with_name (outname); - tempfiles[i] = outname; - - /* Copy lines into this temp file as long as it does not make file - "too big" or until there are no more lines. */ - - while (tempsize + linelength + 1 <= MAX_IN_CORE_SORT) - { - tempsize += linelength + 1; - fputs (lb.buffer, ostream); - putc ('\n', ostream); - - /* Read another line of input data. */ - - linelength = readline (&lb, istream); - if (!linelength && feof (istream)) - break; - - if (lb.buffer[0] != '\\' && lb.buffer[0] != '@') - { - error ("%s: not a texinfo index file", infile); - failure = 1; - goto fail; - } - } - fclose (ostream); - if (feof (istream)) - break; - } - - free (lb.buffer); - -fail: - /* Record number of temp files we actually needed. */ - - ntemps = i; - - /* Sort each tempfile into another tempfile. - Delete the first set of tempfiles and put the names of the second - into `tempfiles'. */ - - for (i = 0; i < ntemps; i++) - { - char *newtemp = maketempname (++tempcount); - sort_in_core (&tempfiles[i], MAX_IN_CORE_SORT, newtemp); - if (!keep_tempfiles) - unlink (tempfiles[i]); - tempfiles[i] = newtemp; - } - - if (failure) - return; - - /* Merge the tempfiles together and indexify. */ - - merge_files (tempfiles, ntemps, outfile); -} - -/* Sort INFILE, whose size is TOTAL, - assuming that is small enough to be done in-core, - then indexify it and send the output to OUTFILE (or to stdout). */ - -void -sort_in_core (infile, total, outfile) - char *infile; - long total; - char *outfile; -{ - char **nextline; - char *data = (char *) xmalloc (total + 1); - char *file_data; - long file_size; - int i; - FILE *ostream = stdout; - struct lineinfo *lineinfo; - - /* Read the contents of the file into the moby array `data'. */ - - int desc = open (infile, O_RDONLY, 0); - - if (desc < 0) - fatal ("failure reopening %s", infile); - for (file_size = 0;;) - { - i = read (desc, data + file_size, total - file_size); - if (i <= 0) - break; - file_size += i; - } - file_data = data; - data[file_size] = 0; - - close (desc); - - if (file_size > 0 && data[0] != '\\' && data[0] != '@') - { - error ("%s: not a texinfo index file", infile); - return; - } - - init_char_order (); - - /* Sort routines want to know this address. */ - - text_base = data; - - /* Create the array of pointers to lines, with a default size - frequently enough. */ - - nlines = total / 50; - if (!nlines) - nlines = 2; - linearray = (char **) xmalloc (nlines * sizeof (char *)); - - /* `nextline' points to the next free slot in this array. - `nlines' is the allocated size. */ - - nextline = linearray; - - /* Parse the input file's data, and make entries for the lines. */ - - nextline = parsefile (infile, nextline, file_data, file_size); - if (nextline == 0) - { - error ("%s: not a texinfo index file", infile); - return; - } - - /* Sort the lines. */ - - /* If we have enough space, find the first keyfield of each line in advance. - Make a `struct lineinfo' for each line, which records the keyfield - as well as the line, and sort them. */ - - lineinfo = (struct lineinfo *) malloc ((nextline - linearray) * sizeof (struct lineinfo)); - - if (lineinfo) - { - struct lineinfo *lp; - char **p; - - for (lp = lineinfo, p = linearray; p != nextline; lp++, p++) - { - lp->text = *p; - lp->key.text = find_field (keyfields, *p, &lp->keylen); - if (keyfields->numeric) - lp->key.number = find_value (lp->key.text, lp->keylen); - } - - qsort (lineinfo, nextline - linearray, sizeof (struct lineinfo), compare_prepared); - - for (lp = lineinfo, p = linearray; p != nextline; lp++, p++) - *p = lp->text; - - free (lineinfo); - } - else - qsort (linearray, nextline - linearray, sizeof (char *), compare_full); - - /* Open the output file. */ - - if (outfile) - { - ostream = fopen (outfile, "w"); - if (!ostream) - pfatal_with_name (outfile); - } - - writelines (linearray, nextline - linearray, ostream); - if (outfile) - fclose (ostream); - - free (linearray); - free (data); -} - -/* Parse an input string in core into lines. - DATA is the input string, and SIZE is its length. - Data goes in LINEARRAY starting at NEXTLINE. - The value returned is the first entry in LINEARRAY still unused. - Value 0 means input file contents are invalid. */ - -char ** -parsefile (filename, nextline, data, size) - char *filename; - char **nextline; - char *data; - long size; -{ - char *p, *end; - char **line = nextline; - - p = data; - end = p + size; - *end = 0; - - while (p != end) - { - if (p[0] != '\\' && p[0] != '@') - return 0; - - *line = p; - while (*p && *p != '\n') - p++; - if (p != end) - p++; - - line++; - if (line == linearray + nlines) - { - char **old = linearray; - linearray = (char **) xrealloc (linearray, sizeof (char *) * (nlines *= 4)); - line += linearray - old; - } - } - - return line; -} - -/* Indexification is a filter applied to the sorted lines - as they are being written to the output file. - Multiple entries for the same name, with different page numbers, - get combined into a single entry with multiple page numbers. - The first braced field, which is used for sorting, is discarded. - However, its first character is examined, folded to lower case, - and if it is different from that in the previous line fed to us - a \initial line is written with one argument, the new initial. - - If an entry has four braced fields, then the second and third - constitute primary and secondary names. - In this case, each change of primary name - generates a \primary line which contains only the primary name, - and in between these are \secondary lines which contain - just a secondary name and page numbers. */ - -/* The last primary name we wrote a \primary entry for. - If only one level of indexing is being done, this is the last name seen. */ -char *lastprimary; -/* Length of storage allocated for lastprimary. */ -int lastprimarylength; - -/* Similar, for the secondary name. */ -char *lastsecondary; -int lastsecondarylength; - -/* Zero if we are not in the middle of writing an entry. - One if we have written the beginning of an entry but have not - yet written any page numbers into it. - Greater than one if we have written the beginning of an entry - plus at least one page number. */ -int pending; - -/* The initial (for sorting purposes) of the last primary entry written. - When this changes, a \initial {c} line is written */ - -char *lastinitial; - -int lastinitiallength; - -/* When we need a string of length 1 for the value of lastinitial, - store it here. */ - -char lastinitial1[2]; - -/* Initialize static storage for writing an index. */ - -static void -xbzero(s, n) - char *s; - int n; -{ - register char *p; - for (p = s; n--; ) - *p++ = '\0'; -} - -void -init_index () -{ - pending = 0; - lastinitial = lastinitial1; - lastinitial1[0] = 0; - lastinitial1[1] = 0; - lastinitiallength = 0; - lastprimarylength = 100; - lastprimary = (char *) xmalloc (lastprimarylength + 1); - xbzero (lastprimary, lastprimarylength + 1); - lastsecondarylength = 100; - lastsecondary = (char *) xmalloc (lastsecondarylength + 1); - xbzero (lastsecondary, lastsecondarylength + 1); -} - -/* Indexify. Merge entries for the same name, - insert headers for each initial character, etc. */ - -void -indexify (line, ostream) - char *line; - FILE *ostream; -{ - char *primary, *secondary, *pagenumber; - int primarylength, secondarylength = 0, pagelength; - int nosecondary; - int initiallength; - char *initial; - char initial1[2]; - register char *p; - - /* First, analyze the parts of the entry fed to us this time. */ - - p = find_braced_pos (line, 0, 0, 0); - if (*p == '{') - { - initial = p; - /* Get length of inner pair of braces starting at `p', - including that inner pair of braces. */ - initiallength = find_braced_end (p + 1) + 1 - p; - } - else - { - initial = initial1; - initial1[0] = *p; - initial1[1] = 0; - initiallength = 1; - - if (initial1[0] >= 'a' && initial1[0] <= 'z') - initial1[0] -= 040; - } - - pagenumber = find_braced_pos (line, 1, 0, 0); - pagelength = find_braced_end (pagenumber) - pagenumber; - if (pagelength == 0) - abort (); - - primary = find_braced_pos (line, 2, 0, 0); - primarylength = find_braced_end (primary) - primary; - - secondary = find_braced_pos (line, 3, 0, 0); - nosecondary = !*secondary; - if (!nosecondary) - secondarylength = find_braced_end (secondary) - secondary; - - /* If the primary is different from before, make a new primary entry. */ - if (strncmp (primary, lastprimary, primarylength)) - { - /* Close off current secondary entry first, if one is open. */ - if (pending) - { - fputs ("}\n", ostream); - pending = 0; - } - - /* If this primary has a different initial, include an entry for - the initial. */ - if (initiallength != lastinitiallength || - strncmp (initial, lastinitial, initiallength)) - { - fprintf (ostream, "\\initial {"); - fwrite (initial, 1, initiallength, ostream); - fprintf (ostream, "}\n", initial); - if (initial == initial1) - { - lastinitial = lastinitial1; - *lastinitial1 = *initial1; - } - else - { - lastinitial = initial; - } - lastinitiallength = initiallength; - } - - /* Make the entry for the primary. */ - if (nosecondary) - fputs ("\\entry {", ostream); - else - fputs ("\\primary {", ostream); - fwrite (primary, primarylength, 1, ostream); - if (nosecondary) - { - fputs ("}{", ostream); - pending = 1; - } - else - fputs ("}\n", ostream); - - /* Record name of most recent primary. */ - if (lastprimarylength < primarylength) - { - lastprimarylength = primarylength + 100; - lastprimary = (char *) xrealloc (lastprimary, - 1 + lastprimarylength); - } - strncpy (lastprimary, primary, primarylength); - lastprimary[primarylength] = 0; - - /* There is no current secondary within this primary, now. */ - lastsecondary[0] = 0; - } - - /* Should not have an entry with no subtopic following one with a subtopic. */ - - if (nosecondary && *lastsecondary) - error ("entry %s follows an entry with a secondary name", line); - - /* Start a new secondary entry if necessary. */ - if (!nosecondary && strncmp (secondary, lastsecondary, secondarylength)) - { - if (pending) - { - fputs ("}\n", ostream); - pending = 0; - } - - /* Write the entry for the secondary. */ - fputs ("\\secondary {", ostream); - fwrite (secondary, secondarylength, 1, ostream); - fputs ("}{", ostream); - pending = 1; - - /* Record name of most recent secondary. */ - if (lastsecondarylength < secondarylength) - { - lastsecondarylength = secondarylength + 100; - lastsecondary = (char *) xrealloc (lastsecondary, - 1 + lastsecondarylength); - } - strncpy (lastsecondary, secondary, secondarylength); - lastsecondary[secondarylength] = 0; - } - - /* Here to add one more page number to the current entry. */ - if (pending++ != 1) - fputs (", ", ostream); /* Punctuate first, if this is not the first. */ - fwrite (pagenumber, pagelength, 1, ostream); -} - -/* Close out any unfinished output entry. */ - -void -finish_index (ostream) - FILE *ostream; -{ - if (pending) - fputs ("}\n", ostream); - free (lastprimary); - free (lastsecondary); -} - -/* Copy the lines in the sorted order. - Each line is copied out of the input file it was found in. */ - -void -writelines (linearray, nlines, ostream) - char **linearray; - int nlines; - FILE *ostream; -{ - char **stop_line = linearray + nlines; - char **next_line; - - init_index (); - - /* Output the text of the lines, and free the buffer space. */ - - for (next_line = linearray; next_line != stop_line; next_line++) - { - /* If -u was specified, output the line only if distinct from previous one. */ - if (next_line == linearray - /* Compare previous line with this one, using only the - explicitly specd keyfields. */ - || compare_general (*(next_line - 1), *next_line, 0L, 0L, num_keyfields - 1)) - { - char *p = *next_line; - char c; - - while ((c = *p++) && c != '\n') - /* Do nothing. */ ; - *(p - 1) = 0; - indexify (*next_line, ostream); - } - } - - finish_index (ostream); -} - -/* Assume (and optionally verify) that each input file is sorted; - merge them and output the result. - Returns nonzero if any input file fails to be sorted. - - This is the high-level interface that can handle an unlimited - number of files. */ - -#define MAX_DIRECT_MERGE 10 - -int -merge_files (infiles, nfiles, outfile) - char **infiles; - int nfiles; - char *outfile; -{ - char **tempfiles; - int ntemps; - int i; - int value = 0; - int start_tempcount = tempcount; - - if (nfiles <= MAX_DIRECT_MERGE) - return merge_direct (infiles, nfiles, outfile); - - /* Merge groups of MAX_DIRECT_MERGE input files at a time, - making a temporary file to hold each group's result. */ - - ntemps = (nfiles + MAX_DIRECT_MERGE - 1) / MAX_DIRECT_MERGE; - tempfiles = (char **) xmalloc (ntemps * sizeof (char *)); - for (i = 0; i < ntemps; i++) - { - int nf = MAX_DIRECT_MERGE; - if (i + 1 == ntemps) - nf = nfiles - i * MAX_DIRECT_MERGE; - tempfiles[i] = maketempname (++tempcount); - value |= merge_direct (&infiles[i * MAX_DIRECT_MERGE], nf, tempfiles[i]); - } - - /* All temporary files that existed before are no longer needed - since their contents have been merged into our new tempfiles. - So delete them. */ - flush_tempfiles (start_tempcount); - - /* Now merge the temporary files we created. */ - - merge_files (tempfiles, ntemps, outfile); - - free (tempfiles); - - return value; -} - -/* Assume (and optionally verify) that each input file is sorted; - merge them and output the result. - Returns nonzero if any input file fails to be sorted. - - This version of merging will not work if the number of - input files gets too high. Higher level functions - use it only with a bounded number of input files. */ - -int -merge_direct (infiles, nfiles, outfile) - char **infiles; - int nfiles; - char *outfile; -{ - struct linebuffer *lb1, *lb2; - struct linebuffer **thisline, **prevline; - FILE **streams; - int i; - int nleft; - int lossage = 0; - int *file_lossage; - struct linebuffer *prev_out = 0; - FILE *ostream = stdout; - - if (outfile) - { - ostream = fopen (outfile, "w"); - } - if (!ostream) - pfatal_with_name (outfile); - - init_index (); - - if (nfiles == 0) - { - if (outfile) - fclose (ostream); - return 0; - } - - /* For each file, make two line buffers. - Also, for each file, there is an element of `thisline' - which points at any time to one of the file's two buffers, - and an element of `prevline' which points to the other buffer. - `thisline' is supposed to point to the next available line from the file, - while `prevline' holds the last file line used, - which is remembered so that we can verify that the file is properly sorted. */ - - /* lb1 and lb2 contain one buffer each per file. */ - lb1 = (struct linebuffer *) xmalloc (nfiles * sizeof (struct linebuffer)); - lb2 = (struct linebuffer *) xmalloc (nfiles * sizeof (struct linebuffer)); - - /* thisline[i] points to the linebuffer holding the next available line in file i, - or is zero if there are no lines left in that file. */ - thisline = (struct linebuffer **) - xmalloc (nfiles * sizeof (struct linebuffer *)); - /* prevline[i] points to the linebuffer holding the last used line - from file i. This is just for verifying that file i is properly - sorted. */ - prevline = (struct linebuffer **) - xmalloc (nfiles * sizeof (struct linebuffer *)); - /* streams[i] holds the input stream for file i. */ - streams = (FILE **) xmalloc (nfiles * sizeof (FILE *)); - /* file_lossage[i] is nonzero if we already know file i is not - properly sorted. */ - file_lossage = (int *) xmalloc (nfiles * sizeof (int)); - - /* Allocate and initialize all that storage. */ - - for (i = 0; i < nfiles; i++) - { - initbuffer (&lb1[i]); - initbuffer (&lb2[i]); - thisline[i] = &lb1[i]; - prevline[i] = &lb2[i]; - file_lossage[i] = 0; - streams[i] = fopen (infiles[i], "r"); - if (!streams[i]) - pfatal_with_name (infiles[i]); - - readline (thisline[i], streams[i]); - } - - /* Keep count of number of files not at eof. */ - nleft = nfiles; - - while (nleft) - { - struct linebuffer *best = 0; - struct linebuffer *exch; - int bestfile = -1; - int i; - - /* Look at the next avail line of each file; choose the least one. */ - - for (i = 0; i < nfiles; i++) - { - if (thisline[i] && - (!best || - 0 < compare_general (best->buffer, thisline[i]->buffer, - (long) bestfile, (long) i, num_keyfields))) - { - best = thisline[i]; - bestfile = i; - } - } - - /* Output that line, unless it matches the previous one and we - don't want duplicates. */ - - if (!(prev_out && - !compare_general (prev_out->buffer, - best->buffer, 0L, 1L, num_keyfields - 1))) - indexify (best->buffer, ostream); - prev_out = best; - - /* Now make the line the previous of its file, and fetch a new - line from that file. */ - - exch = prevline[bestfile]; - prevline[bestfile] = thisline[bestfile]; - thisline[bestfile] = exch; - - while (1) - { - /* If the file has no more, mark it empty. */ - - if (feof (streams[bestfile])) - { - thisline[bestfile] = 0; - /* Update the number of files still not empty. */ - nleft--; - break; - } - readline (thisline[bestfile], streams[bestfile]); - if (thisline[bestfile]->buffer[0] || !feof (streams[bestfile])) - break; - } - } - - finish_index (ostream); - - /* Free all storage and close all input streams. */ - - for (i = 0; i < nfiles; i++) - { - fclose (streams[i]); - free (lb1[i].buffer); - free (lb2[i].buffer); - } - free (file_lossage); - free (lb1); - free (lb2); - free (thisline); - free (prevline); - free (streams); - - if (outfile) - fclose (ostream); - - return lossage; -} - -/* Print error message and exit. */ - -void -fatal (s1, s2) - char *s1, *s2; -{ - error (s1, s2); - exit (TI_FATAL_ERROR); -} - -/* Print error message. S1 is printf control string, S2 is arg for it. */ - -void -error (s1, s2) - char *s1, *s2; -{ - printf ("%s: ", program_name); - printf (s1, s2); - printf ("\n"); -} - -#if !defined (HAVE_STRERROR) -static char * -strerror (n) - int n; -{ - static char ebuf[40]; - - if (n < sys_nerr) - return sys_errlist[n]; - else - { - sprintf (ebuf, "Unknown error %d", n); - return ebuf; - } -} -#endif - -void -perror_with_name (name) - char *name; -{ - char *s; - - s = concat ("", strerror (errno), " for %s"); - error (s, name); -} - -void -pfatal_with_name (name) - char *name; -{ - char *s; - - s = concat ("", strerror (errno), " for %s"); - fatal (s, name); -} - -/* Return a newly-allocated string whose contents concatenate those of - S1, S2, S3. */ - -char * -concat (s1, s2, s3) - char *s1, *s2, *s3; -{ - int len1 = strlen (s1), len2 = strlen (s2), len3 = strlen (s3); - char *result = (char *) xmalloc (len1 + len2 + len3 + 1); - - strcpy (result, s1); - strcpy (result + len1, s2); - strcpy (result + len1 + len2, s3); - *(result + len1 + len2 + len3) = 0; - - return result; -} - -/* Just like malloc, but kills the program in case of fatal error. */ -void * -xmalloc (nbytes) - int nbytes; -{ - void *temp = (void *) malloc (nbytes); - - if (nbytes && temp == (void *)NULL) - memory_error ("xmalloc", nbytes); - - return (temp); -} - -/* Like realloc (), but barfs if there isn't enough memory. */ -void * -xrealloc (pointer, nbytes) - void *pointer; - int nbytes; -{ - void *temp; - - if (!pointer) - temp = (void *)xmalloc (nbytes); - else - temp = (void *)realloc (pointer, nbytes); - - if (nbytes && !temp) - memory_error ("xrealloc", nbytes); - - return (temp); -} - -memory_error (callers_name, bytes_wanted) - char *callers_name; - int bytes_wanted; -{ - char printable_string[80]; - - sprintf (printable_string, - "Virtual memory exhausted in %s ()! Needed %d bytes.", - callers_name, bytes_wanted); - - error (printable_string, ""); - abort (); -} diff --git a/lib/readline/emacs_keymap.c b/lib/readline/emacs_keymap.c index 849d85f..4ba3858 100644 --- a/lib/readline/emacs_keymap.c +++ b/lib/readline/emacs_keymap.c @@ -33,7 +33,7 @@ KEYMAP_ENTRY_ARRAY emacs_standard_keymap = { /* Control keys. */ - { ISFUNC, (Function *)0x0 }, /* Control-@ */ + { ISFUNC, rl_set_mark }, /* Control-@ */ { ISFUNC, rl_beg_of_line }, /* Control-a */ { ISFUNC, rl_backward }, /* Control-b */ { ISFUNC, (Function *)0x0 }, /* Control-c */ @@ -62,7 +62,7 @@ KEYMAP_ENTRY_ARRAY emacs_standard_keymap = { { ISFUNC, (Function *)0x0 }, /* Control-z */ { ISKMAP, (Function *)emacs_meta_keymap }, /* Control-[ */ { ISFUNC, (Function *)0x0 }, /* Control-\ */ - { ISFUNC, (Function *)0x0 }, /* Control-] */ + { ISFUNC, rl_char_search }, /* Control-] */ { ISFUNC, (Function *)0x0 }, /* Control-^ */ { ISFUNC, rl_undo_command }, /* Control-_ */ @@ -358,22 +358,22 @@ KEYMAP_ENTRY_ARRAY emacs_meta_keymap = { { ISFUNC, rl_complete }, /* Meta-Control-[ */ { ISFUNC, (Function *)0x0 }, /* Meta-Control-\ */ - { ISFUNC, (Function *)0x0 }, /* Meta-Control-] */ + { ISFUNC, rl_backward_char_search }, /* Meta-Control-] */ { ISFUNC, (Function *)0x0 }, /* Meta-Control-^ */ { ISFUNC, (Function *)0x0 }, /* Meta-Control-_ */ /* The start of printing characters. */ - { ISFUNC, (Function *)0x0 }, /* Meta-SPACE */ + { ISFUNC, rl_set_mark }, /* Meta-SPACE */ { ISFUNC, (Function *)0x0 }, /* Meta-! */ { ISFUNC, (Function *)0x0 }, /* Meta-" */ - { ISFUNC, (Function *)0x0 }, /* Meta-# */ + { ISFUNC, rl_insert_comment },/* Meta-# */ { ISFUNC, (Function *)0x0 }, /* Meta-$ */ { ISFUNC, (Function *)0x0 }, /* Meta-% */ { ISFUNC, rl_tilde_expand }, /* Meta-& */ { ISFUNC, (Function *)0x0 }, /* Meta-' */ { ISFUNC, (Function *)0x0 }, /* Meta-( */ { ISFUNC, (Function *)0x0 }, /* Meta-) */ - { ISFUNC, (Function *)0x0 }, /* Meta-* */ + { ISFUNC, rl_insert_completions }, /* Meta-* */ { ISFUNC, (Function *)0x0 }, /* Meta-+ */ { ISFUNC, (Function *)0x0 }, /* Meta-, */ { ISFUNC, rl_digit_argument }, /* Meta-- */ @@ -396,7 +396,7 @@ KEYMAP_ENTRY_ARRAY emacs_meta_keymap = { { ISFUNC, (Function *)0x0 }, /* Meta-: */ { ISFUNC, (Function *)0x0 }, /* Meta-; */ { ISFUNC, rl_beginning_of_history }, /* Meta-< */ - { ISFUNC, (Function *)0x0 }, /* Meta-= */ + { ISFUNC, rl_possible_completions }, /* Meta-= */ { ISFUNC, rl_end_of_history }, /* Meta-> */ { ISFUNC, rl_possible_completions }, /* Meta-? */ { ISFUNC, (Function *)0x0 }, /* Meta-@ */ @@ -632,7 +632,7 @@ KEYMAP_ENTRY_ARRAY emacs_ctlx_keymap = { { ISFUNC, rl_undo_command }, /* Control-u */ { ISFUNC, (Function *)0x0 }, /* Control-v */ { ISFUNC, (Function *)0x0 }, /* Control-w */ - { ISFUNC, (Function *)0x0 }, /* Control-x */ + { ISFUNC, rl_exchange_point_and_mark },/* Control-x */ { ISFUNC, (Function *)0x0 }, /* Control-y */ { ISFUNC, (Function *)0x0 }, /* Control-z */ { ISFUNC, (Function *)0x0 }, /* Control-[ */ diff --git a/lib/readline/examples/Makefile b/lib/readline/examples/Makefile index 3d1fc52..cfa7745 100644 --- a/lib/readline/examples/Makefile +++ b/lib/readline/examples/Makefile @@ -1,12 +1,19 @@ # This is the Makefile for the examples subdirectory of readline. -*- text -*- # - -EXECUTABLES = fileman -CFLAGS = -g -I../.. +EXECUTABLES = fileman rltest +CFLAGS = -g -I../.. -I.. LDFLAGS = -g -L.. +.c.o: + $(CC) $(CFLAGS) -c $< + +all: $(EXECUTABLES) + fileman: fileman.o - $(CC) $(LDFLAGS) -o fileman fileman.o -lreadline -ltermcap + $(CC) $(LDFLAGS) -o $@ fileman.o -lreadline -ltermcap + +rltest: rltest.o + $(CC) $(LDFLAGS) -o $@ rltest.o -lreadline -ltermcap fileman.o: fileman.c - +rltest.o: rltest.c diff --git a/lib/readline/examples/fileman.c b/lib/readline/examples/fileman.c index 3ecb9f1..8709120 100644 --- a/lib/readline/examples/fileman.c +++ b/lib/readline/examples/fileman.c @@ -194,10 +194,11 @@ initialize_readline () rl_attempted_completion_function = (CPPFunction *)fileman_completion; } -/* Attempt to complete on the contents of TEXT. START and END show the - region of TEXT that contains the word to complete. We can use the - entire line in case we want to do some simple parsing. Return the - array of matches, or NULL if there aren't any. */ +/* 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. Return the array of matches, + or NULL if there aren't any. */ char ** fileman_completion (text, start, end) char *text; diff --git a/lib/readline/examples/rltest.c b/lib/readline/examples/rltest.c new file mode 100644 index 0000000..311629f --- /dev/null +++ b/lib/readline/examples/rltest.c @@ -0,0 +1,54 @@ +/* **************************************************************** */ +/* */ +/* Testing Readline */ +/* */ +/* **************************************************************** */ + +#include +#include +#include "../readline.h" +#include "../history.h" + +main () +{ + HIST_ENTRY **history_list (); + char *temp = (char *)NULL; + char *prompt = "readline$ "; + int done = 0; + + while (!done) + { + temp = readline (prompt); + + /* Test for EOF. */ + if (!temp) + exit (1); + + /* If there is anything on the line, print it and remember it. */ + if (*temp) + { + fprintf (stderr, "%s\r\n", temp); + add_history (temp); + } + + /* Check for `command' that we handle. */ + if (strcmp (temp, "quit") == 0) + done = 1; + + if (strcmp (temp, "list") == 0) + { + HIST_ENTRY **list = history_list (); + register int i; + if (list) + { + for (i = 0; list[i]; i++) + { + fprintf (stderr, "%d: %s\r\n", i, list[i]->line); + free (list[i]->line); + } + free (list); + } + } + free (temp); + } +} diff --git a/lib/readline/funmap.c b/lib/readline/funmap.c index 9255974..6b7d351 100644 --- a/lib/readline/funmap.c +++ b/lib/readline/funmap.c @@ -21,11 +21,11 @@ 675 Mass Ave, Cambridge, MA 02139, USA. */ #define READLINE_LIBRARY -#if defined (STATIC_MALLOC) -static char *xmalloc (), *xrealloc (); -#else +#if defined (HAVE_CONFIG_H) +# include +#endif + extern char *xmalloc (), *xrealloc (); -#endif /* STATIC_MALLOC */ #if !defined (BUFSIZ) #include @@ -40,18 +40,17 @@ extern char *xmalloc (), *xrealloc (); #include "rlconf.h" #include "readline.h" -static int qsort_string_compare (); +extern int _rl_qsort_string_compare (); -FUNMAP **funmap = (FUNMAP **)NULL; -static int funmap_size = 0; -static int funmap_entry = 0; +FUNMAP **funmap; +static int funmap_size; +static int funmap_entry; /* After initializing the function map, this is the index of the first program specific function. */ int funmap_program_specific_entry_start; static FUNMAP default_funmap[] = { - { "abort", rl_abort }, { "accept-line", rl_newline }, { "arrow-key-prefix", rl_arrow_keys }, @@ -64,26 +63,35 @@ static FUNMAP default_funmap[] = { { "beginning-of-line", rl_beg_of_line }, { "call-last-kbd-macro", rl_call_last_kbd_macro }, { "capitalize-word", rl_capitalize_word }, + { "character-search", rl_char_search }, + { "character-search-backward", rl_backward_char_search }, { "clear-screen", rl_clear_screen }, { "complete", rl_complete }, + { "copy-backward-word", rl_copy_backward_word }, + { "copy-forward-word", rl_copy_forward_word }, + { "copy-region-as-kill", rl_copy_region_to_kill }, { "delete-char", rl_delete }, { "delete-horizontal-space", rl_delete_horizontal_space }, { "digit-argument", rl_digit_argument }, { "do-lowercase-version", rl_do_lowercase_version }, { "downcase-word", rl_downcase_word }, { "dump-functions", rl_dump_functions }, + { "dump-variables", rl_dump_variables }, { "emacs-editing-mode", rl_emacs_editing_mode }, { "end-kbd-macro", rl_end_kbd_macro }, { "end-of-history", rl_end_of_history }, { "end-of-line", rl_end_of_line }, + { "exchange-point-and-mark", rl_exchange_point_and_mark }, { "forward-char", rl_forward }, { "forward-search-history", rl_forward_search_history }, { "forward-word", rl_forward_word }, { "history-search-backward", rl_history_search_backward }, { "history-search-forward", rl_history_search_forward }, + { "insert-comment", rl_insert_comment }, { "insert-completions", rl_insert_completions }, { "kill-whole-line", rl_kill_full_line }, { "kill-line", rl_kill_line }, + { "kill-region", rl_kill_region }, { "kill-word", rl_kill_word }, { "next-history", rl_get_next_history }, { "non-incremental-forward-search-history", rl_noninc_forward_search }, @@ -98,6 +106,7 @@ static FUNMAP default_funmap[] = { { "reverse-search-history", rl_reverse_search_history }, { "revert-line", rl_revert_line }, { "self-insert", rl_insert }, + { "set-mark", rl_set_mark }, { "start-kbd-macro", rl_start_kbd_macro }, { "tab-insert", rl_tab_insert }, { "tilde-expand", rl_tilde_expand }, @@ -118,6 +127,7 @@ static FUNMAP default_funmap[] = { { "vi-append-eol", rl_vi_append_eol }, { "vi-append-mode", rl_vi_append_mode }, { "vi-arg-digit", rl_vi_arg_digit }, + { "vi-back-to-indent", rl_vi_back_to_indent }, { "vi-bWord", rl_vi_bWord }, { "vi-bracktype", rl_vi_bracktype }, { "vi-bword", rl_vi_bword }, @@ -126,7 +136,6 @@ static FUNMAP default_funmap[] = { { "vi-change-to", rl_vi_change_to }, { "vi-char-search", rl_vi_char_search }, { "vi-column", rl_vi_column }, - { "vi-comment", rl_vi_comment }, { "vi-complete", rl_vi_complete }, { "vi-delete", rl_vi_delete }, { "vi-delete-to", rl_vi_delete_to }, @@ -136,8 +145,10 @@ static FUNMAP default_funmap[] = { { "vi-eof-maybe", rl_vi_eof_maybe }, { "vi-eword", rl_vi_eword }, { "vi-fWord", rl_vi_fWord }, + { "vi-fetch-history", rl_vi_fetch_history }, { "vi-first-print", rl_vi_first_print }, { "vi-fword", rl_vi_fword }, + { "vi-goto-mark", rl_vi_goto_mark }, { "vi-insert-beg", rl_vi_insert_beg }, { "vi-insertion-mode", rl_vi_insertion_mode }, { "vi-match", rl_vi_match }, @@ -151,6 +162,7 @@ static FUNMAP default_funmap[] = { { "vi-replace", rl_vi_replace }, { "vi-search", rl_vi_search }, { "vi-search-again", rl_vi_search_again }, + { "vi-set-mark", rl_vi_set_mark }, { "vi-subst", rl_vi_subst }, { "vi-tilde-expand", rl_vi_tilde_expand }, { "vi-yank-arg", rl_vi_yank_arg }, @@ -160,16 +172,16 @@ static FUNMAP default_funmap[] = { {(char *)NULL, (Function *)NULL } }; +int rl_add_funmap_entry (name, function) char *name; Function *function; { if (funmap_entry + 2 >= funmap_size) - if (!funmap) - funmap = (FUNMAP **)xmalloc ((funmap_size = 80) * sizeof (FUNMAP *)); - else - funmap = - (FUNMAP **)xrealloc (funmap, (funmap_size += 80) * sizeof (FUNMAP *)); + { + funmap_size += 64; + funmap = (FUNMAP **)xrealloc (funmap, funmap_size * sizeof (FUNMAP *)); + } funmap[funmap_entry] = (FUNMAP *)xmalloc (sizeof (FUNMAP)); funmap[funmap_entry]->name = name; @@ -179,7 +191,7 @@ rl_add_funmap_entry (name, function) return funmap_entry; } -static int funmap_initialized = 0; +static int funmap_initialized; /* Make the funmap contain all of the default entries. */ void @@ -203,46 +215,28 @@ rl_initialize_funmap () char ** rl_funmap_names () { - char **result = (char **)NULL; + char **result; int result_size, result_index; - result_size = result_index = 0; - /* Make sure that the function map has been initialized. */ rl_initialize_funmap (); - for (result_index = 0; funmap[result_index]; result_index++) + for (result_index = result_size = 0, result = (char **)NULL; funmap[result_index]; result_index++) { if (result_index + 2 > result_size) { - if (!result) - result = (char **)xmalloc ((result_size = 20) * sizeof (char *)); - else - result = (char **) - xrealloc (result, (result_size += 20) * sizeof (char *)); + result_size += 20; + result = (char **)xrealloc (result, result_size * sizeof (char *)); } result[result_index] = funmap[result_index]->name; result[result_index + 1] = (char *)NULL; } - qsort (result, result_index, sizeof (char *), qsort_string_compare); + qsort (result, result_index, sizeof (char *), _rl_qsort_string_compare); return (result); } -/* Stupid comparison routine for qsort () ing strings. */ -static int -qsort_string_compare (s1, s2) - register char **s1, **s2; -{ - int r; - - r = **s1 - **s2; - if (r == 0) - r = strcmp (*s1, *s2); - return r; -} - /* Things that mean `Control'. */ char *possible_control_prefixes[] = { "Control-", "C-", "CTRL-", (char *)NULL @@ -251,49 +245,3 @@ char *possible_control_prefixes[] = { char *possible_meta_prefixes[] = { "Meta", "M-", (char *)NULL }; - -#if defined (STATIC_MALLOC) - -/* **************************************************************** */ -/* */ -/* xmalloc and xrealloc () */ -/* */ -/* **************************************************************** */ - -static void memory_error_and_abort (); - -static char * -xmalloc (bytes) - int bytes; -{ - char *temp = (char *)malloc (bytes); - - if (!temp) - memory_error_and_abort (); - return (temp); -} - -static char * -xrealloc (pointer, bytes) - char *pointer; - int bytes; -{ - char *temp; - - if (!pointer) - temp = (char *)malloc (bytes); - else - temp = (char *)realloc (pointer, bytes); - - if (!temp) - memory_error_and_abort (); - return (temp); -} - -static void -memory_error_and_abort () -{ - fprintf (stderr, "history: Out of virtual memory!\n"); - abort (); -} -#endif /* STATIC_MALLOC */ diff --git a/lib/readline/histexpand.c b/lib/readline/histexpand.c new file mode 100644 index 0000000..d916c74 --- /dev/null +++ b/lib/readline/histexpand.c @@ -0,0 +1,1358 @@ +/* histexpand.c -- history expansion. */ + +/* Copyright (C) 1989, 1992 Free Software Foundation, Inc. + + This file contains the GNU History Library (the Library), a set of + routines for managing the text of previously typed lines. + + The 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 1, or (at your option) + any later version. + + The 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, + 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#define READLINE_LIBRARY + +#if defined (HAVE_CONFIG_H) +# include +#endif + +#include + +#if defined (HAVE_STDLIB_H) +# include +#else +# include "ansi_stdlib.h" +#endif /* HAVE_STDLIB_H */ + +#if defined (HAVE_UNISTD_H) +# include +#endif + +#if defined (HAVE_STRING_H) +# include +#else +# include +#endif /* !HAVE_STRING_H */ + +#include "history.h" +#include "histlib.h" + +static char error_pointer; + +static char *subst_lhs; +static char *subst_rhs; +static int subst_lhs_len; +static int subst_rhs_len; + +static char *get_history_word_specifier (); +static char *history_find_word (); + +extern int history_offset; + +#if defined (SHELL) +extern char *single_quote (); +#else +static char *single_quote (); +#endif /* !SHELL */ +static char *quote_breaks (); + +extern char *xmalloc (), *xrealloc (); + +/* Variables exported by this file. */ +/* The character that represents the start of a history expansion + request. This is usually `!'. */ +char history_expansion_char = '!'; + +/* The character that invokes word substitution if found at the start of + a line. This is usually `^'. */ +char history_subst_char = '^'; + +/* During tokenization, if this character is seen as the first character + of a word, then it, and all subsequent characters upto a newline are + ignored. For a Bourne shell, this should be '#'. Bash special cases + the interactive comment character to not be a comment delimiter. */ +char history_comment_char = '\0'; + +/* The list of characters which inhibit the expansion of text if found + immediately following history_expansion_char. */ +char *history_no_expand_chars = " \t\n\r="; + +/* If set to a non-zero value, single quotes inhibit history expansion. + The default is 0. */ +int history_quotes_inhibit_expansion = 0; + +/* **************************************************************** */ +/* */ +/* History Expansion */ +/* */ +/* **************************************************************** */ + +/* Hairy history expansion on text, not tokens. This is of general + use, and thus belongs in this library. */ + +/* The last string searched for by a !?string? search. */ +static char *search_string; + +/* The last string matched by a !?string? search. */ +static char *search_match; + +/* Return the event specified at TEXT + OFFSET modifying OFFSET to + point to after the event specifier. Just a pointer to the history + line is returned; NULL is returned in the event of a bad specifier. + You pass STRING with *INDEX equal to the history_expansion_char that + begins this specification. + DELIMITING_QUOTE is a character that is allowed to end the string + specification for what to search for in addition to the normal + characters `:', ` ', `\t', `\n', and sometimes `?'. + So you might call this function like: + line = get_history_event ("!echo:p", &index, 0); */ +char * +get_history_event (string, caller_index, delimiting_quote) + char *string; + int *caller_index; + int delimiting_quote; +{ + register int i; + register char c; + HIST_ENTRY *entry; + int which, sign, local_index, substring_okay; + Function *search_func; + char *temp; + + /* The event can be specified in a number of ways. + + !! the previous command + !n command line N + !-n current command-line minus N + !str the most recent command starting with STR + !?str[?] + the most recent command containing STR + + All values N are determined via HISTORY_BASE. */ + + i = *caller_index; + + if (string[i] != history_expansion_char) + return ((char *)NULL); + + /* Move on to the specification. */ + i++; + + sign = 1; + substring_okay = 0; + +#define RETURN_ENTRY(e, w) \ + return ((e = history_get (w)) ? e->line : (char *)NULL) + + /* Handle !! case. */ + if (string[i] == history_expansion_char) + { + i++; + which = history_base + (history_length - 1); + *caller_index = i; + RETURN_ENTRY (entry, which); + } + + /* Hack case of numeric line specification. */ + if (string[i] == '-') + { + sign = -1; + i++; + } + + if (_rl_digit_p (string[i])) + { + /* Get the extent of the digits and compute the value. */ + for (which = 0; _rl_digit_p (string[i]); i++) + which = (which * 10) + _rl_digit_value (string[i]); + + *caller_index = i; + + if (sign < 0) + which = (history_length + history_base) - which; + + RETURN_ENTRY (entry, which); + } + + /* This must be something to search for. If the spec begins with + a '?', then the string may be anywhere on the line. Otherwise, + the string must be found at the start of a line. */ + if (string[i] == '?') + { + substring_okay++; + i++; + } + + /* Only a closing `?' or a newline delimit a substring search string. */ + for (local_index = i; c = string[i]; i++) + if ((!substring_okay && (whitespace (c) || c == ':' || + (history_search_delimiter_chars && member (c, history_search_delimiter_chars)) || + string[i] == delimiting_quote)) || + string[i] == '\n' || + (substring_okay && string[i] == '?')) + break; + + which = i - local_index; + temp = xmalloc (1 + which); + if (which) + strncpy (temp, string + local_index, which); + temp[which] = '\0'; + + if (substring_okay && string[i] == '?') + i++; + + *caller_index = i; + +#define FAIL_SEARCH() \ + do { \ + history_offset = history_length; free (temp) ; return (char *)NULL; \ + } while (0) + + /* If there is no search string, try to use the previous search string, + if one exists. If not, fail immediately. */ + if (*temp == '\0' && substring_okay) + { + if (search_string) + { + free (temp); + temp = savestring (search_string); + } + else + FAIL_SEARCH (); + } + + search_func = substring_okay ? history_search : history_search_prefix; + while (1) + { + local_index = (*search_func) (temp, -1); + + if (local_index < 0) + FAIL_SEARCH (); + + if (local_index == 0 || substring_okay) + { + entry = current_history (); + history_offset = history_length; + + /* If this was a substring search, then remember the + string that we matched for word substitution. */ + if (substring_okay) + { + FREE (search_string); + search_string = temp; + + FREE (search_match); + search_match = history_find_word (entry->line, local_index); + } + else + free (temp); + + return (entry->line); + } + + if (history_offset) + history_offset--; + else + FAIL_SEARCH (); + } +#undef FAIL_SEARCH +#undef RETURN_ENTRY +} + +/* Function for extracting single-quoted strings. Used for inhibiting + history expansion within single quotes. */ + +/* Extract the contents of STRING as if it is enclosed in single quotes. + SINDEX, when passed in, is the offset of the character immediately + following the opening single quote; on exit, SINDEX is left pointing + to the closing single quote. */ +static void +hist_string_extract_single_quoted (string, sindex) + char *string; + int *sindex; +{ + register int i; + + for (i = *sindex; string[i] && string[i] != '\''; i++) + ; + + *sindex = i; +} + +#if !defined (SHELL) +/* Does shell-like quoting using single quotes. */ +static char * +single_quote (string) + char *string; +{ + register int c; + char *result, *r, *s; + + result = (char *)xmalloc (3 + (3 * strlen (string))); + r = result; + *r++ = '\''; + + for (s = string; s && (c = *s); s++) + { + *r++ = c; + + if (c == '\'') + { + *r++ = '\\'; /* insert escaped single quote */ + *r++ = '\''; + *r++ = '\''; /* start new quoted string */ + } + } + + *r++ = '\''; + *r = '\0'; + + return (result); +} +#endif /* !SHELL */ + +static char * +quote_breaks (s) + char *s; +{ + register char *p, *r; + char *ret; + int len = 3; + + for (p = s; p && *p; p++, len++) + { + if (*p == '\'') + len += 3; + else if (whitespace (*p) || *p == '\n') + len += 2; + } + + r = ret = xmalloc (len); + *r++ = '\''; + for (p = s; p && *p; ) + { + if (*p == '\'') + { + *r++ = '\''; + *r++ = '\\'; + *r++ = '\''; + *r++ = '\''; + p++; + } + else if (whitespace (*p) || *p == '\n') + { + *r++ = '\''; + *r++ = *p++; + *r++ = '\''; + } + else + *r++ = *p++; + } + *r++ = '\''; + *r = '\0'; + return ret; +} + +static char * +hist_error(s, start, current, errtype) + char *s; + int start, current, errtype; +{ + char *temp, *emsg; + int ll, elen; + + ll = current - start; + + switch (errtype) + { + case EVENT_NOT_FOUND: + emsg = "event not found"; + elen = 15; + break; + case BAD_WORD_SPEC: + emsg = "bad word specifier"; + elen = 18; + break; + case SUBST_FAILED: + emsg = "substitution failed"; + elen = 19; + break; + case BAD_MODIFIER: + emsg = "unrecognized history modifier"; + elen = 29; + break; + default: + emsg = "unknown expansion error"; + elen = 23; + break; + } + + temp = xmalloc (ll + elen + 3); + strncpy (temp, s + start, ll); + temp[ll] = ':'; + temp[ll + 1] = ' '; + strcpy (temp + ll + 2, emsg); + return (temp); +} + +/* Get a history substitution string from STR starting at *IPTR + and return it. The length is returned in LENPTR. + + A backslash can quote the delimiter. If the string is the + empty string, the previous pattern is used. If there is + no previous pattern for the lhs, the last history search + string is used. + + If IS_RHS is 1, we ignore empty strings and set the pattern + to "" anyway. subst_lhs is not changed if the lhs is empty; + subst_rhs is allowed to be set to the empty string. */ + +static char * +get_subst_pattern (str, iptr, delimiter, is_rhs, lenptr) + char *str; + int *iptr, delimiter, is_rhs, *lenptr; +{ + register int si, i, j, k; + char *s = (char *) NULL; + + i = *iptr; + + for (si = i; str[si] && str[si] != delimiter; si++) + if (str[si] == '\\' && str[si + 1] == delimiter) + si++; + + if (si > i || is_rhs) + { + s = xmalloc (si - i + 1); + for (j = 0, k = i; k < si; j++, k++) + { + /* Remove a backslash quoting the search string delimiter. */ + if (str[k] == '\\' && str[k + 1] == delimiter) + k++; + s[j] = str[k]; + } + s[j] = '\0'; + if (lenptr) + *lenptr = j; + } + + i = si; + if (str[i]) + i++; + *iptr = i; + + return s; +} + +static void +postproc_subst_rhs () +{ + char *new; + int i, j, new_size; + + new = xmalloc (new_size = subst_rhs_len + subst_lhs_len); + for (i = j = 0; i < subst_rhs_len; i++) + { + if (subst_rhs[i] == '&') + { + if (j + subst_lhs_len >= new_size) + new = xrealloc (new, (new_size = new_size * 2 + subst_lhs_len)); + strcpy (new + j, subst_lhs); + j += subst_lhs_len; + } + else + { + /* a single backslash protects the `&' from lhs interpolation */ + if (subst_rhs[i] == '\\' && subst_rhs[i + 1] == '&') + i++; + if (j >= new_size) + new = xrealloc (new, new_size *= 2); + new[j++] = subst_rhs[i]; + } + } + new[j] = '\0'; + free (subst_rhs); + subst_rhs = new; + subst_rhs_len = j; +} + +/* Expand the bulk of a history specifier starting at STRING[START]. + Returns 0 if everything is OK, -1 if an error occurred, and 1 + if the `p' modifier was supplied and the caller should just print + the returned string. Returns the new index into string in + *END_INDEX_PTR, and the expanded specifier in *RET_STRING. */ +static int +history_expand_internal (string, start, end_index_ptr, ret_string, current_line) + char *string; + int start, *end_index_ptr; + char **ret_string; + char *current_line; /* for !# */ +{ + int i, n, starting_index; + int substitute_globally, want_quotes, print_only; + char *event, *temp, *result, *tstr, *t, c, *word_spec; + int result_len; + + result = xmalloc (result_len = 128); + + i = start; + + /* If it is followed by something that starts a word specifier, + then !! is implied as the event specifier. */ + + if (member (string[i + 1], ":$*%^")) + { + char fake_s[3]; + int fake_i = 0; + i++; + fake_s[0] = fake_s[1] = history_expansion_char; + fake_s[2] = '\0'; + event = get_history_event (fake_s, &fake_i, 0); + } + else if (string[i + 1] == '#') + { + i += 2; + event = current_line; + } + else + { + int quoted_search_delimiter = 0; + + /* If the character before this `!' is a double or single + quote, then this expansion takes place inside of the + quoted string. If we have to search for some text ("!foo"), + allow the delimiter to end the search string. */ + if (i && (string[i - 1] == '\'' || string[i - 1] == '"')) + quoted_search_delimiter = string[i - 1]; + event = get_history_event (string, &i, quoted_search_delimiter); + } + + if (event == 0) + { + *ret_string = hist_error (string, start, i, EVENT_NOT_FOUND); + free (result); + return (-1); + } + + /* If a word specifier is found, then do what that requires. */ + starting_index = i; + word_spec = get_history_word_specifier (string, event, &i); + + /* There is no such thing as a `malformed word specifier'. However, + it is possible for a specifier that has no match. In that case, + we complain. */ + if (word_spec == (char *)&error_pointer) + { + *ret_string = hist_error (string, starting_index, i, BAD_WORD_SPEC); + free (result); + return (-1); + } + + /* If no word specifier, than the thing of interest was the event. */ + temp = word_spec ? savestring (word_spec) : savestring (event); + FREE (word_spec); + + /* Perhaps there are other modifiers involved. Do what they say. */ + want_quotes = substitute_globally = print_only = 0; + starting_index = i; + + while (string[i] == ':') + { + c = string[i + 1]; + + if (c == 'g') + { + substitute_globally = 1; + i++; + c = string[i + 1]; + } + + switch (c) + { + default: + *ret_string = hist_error (string, i+1, i+2, BAD_MODIFIER); + free (result); + free (temp); + return -1; + + case 'q': + want_quotes = 'q'; + break; + + case 'x': + want_quotes = 'x'; + break; + + /* :p means make this the last executed line. So we + return an error state after adding this line to the + history. */ + case 'p': + print_only++; + break; + + /* :t discards all but the last part of the pathname. */ + case 't': + tstr = strrchr (temp, '/'); + if (tstr) + { + tstr++; + t = savestring (tstr); + free (temp); + temp = t; + } + break; + + /* :h discards the last part of a pathname. */ + case 'h': + tstr = strrchr (temp, '/'); + if (tstr) + *tstr = '\0'; + break; + + /* :r discards the suffix. */ + case 'r': + tstr = strrchr (temp, '.'); + if (tstr) + *tstr = '\0'; + break; + + /* :e discards everything but the suffix. */ + case 'e': + tstr = strrchr (temp, '.'); + if (tstr) + { + t = savestring (tstr); + free (temp); + temp = t; + } + break; + + /* :s/this/that substitutes `that' for the first + occurrence of `this'. :gs/this/that substitutes `that' + for each occurrence of `this'. :& repeats the last + substitution. :g& repeats the last substitution + globally. */ + + case '&': + case 's': + { + char *new_event, *t; + int delimiter, failed, si, l_temp; + + if (c == 's') + { + if (i + 2 < (int)strlen (string)) + delimiter = string[i + 2]; + else + break; /* no search delimiter */ + + i += 3; + + t = get_subst_pattern (string, &i, delimiter, 0, &subst_lhs_len); + /* An empty substitution lhs with no previous substitution + uses the last search string as the lhs. */ + if (t) + { + FREE (subst_lhs); + subst_lhs = t; + } + else if (!subst_lhs) + { + if (search_string && *search_string) + { + subst_lhs = savestring (search_string); + subst_lhs_len = strlen (subst_lhs); + } + else + { + subst_lhs = (char *) NULL; + subst_lhs_len = 0; + } + } + + /* If there is no lhs, the substitution can't succeed. */ + if (subst_lhs_len == 0) + { + *ret_string = hist_error (string, starting_index, i, SUBST_FAILED); + free (result); + free (temp); + return -1; + } + + FREE (subst_rhs); + subst_rhs = get_subst_pattern (string, &i, delimiter, 1, &subst_rhs_len); + + /* If `&' appears in the rhs, it's supposed to be replaced + with the lhs. */ + if (member ('&', subst_rhs)) + postproc_subst_rhs (); + } + else + i += 2; + + l_temp = strlen (temp); + /* Ignore impossible cases. */ + if (subst_lhs_len > l_temp) + { + *ret_string = hist_error (string, starting_index, i, SUBST_FAILED); + free (result); + free (temp); + return (-1); + } + + /* Find the first occurrence of THIS in TEMP. */ + si = 0; + for (failed = 1; (si + subst_lhs_len) <= l_temp; si++) + if (STREQN (temp+si, subst_lhs, subst_lhs_len)) + { + int len = subst_rhs_len - subst_lhs_len + l_temp; + new_event = xmalloc (1 + len); + strncpy (new_event, temp, si); + strncpy (new_event + si, subst_rhs, subst_rhs_len); + strncpy (new_event + si + subst_rhs_len, + temp + si + subst_lhs_len, + l_temp - (si + subst_lhs_len)); + new_event[len] = '\0'; + free (temp); + temp = new_event; + + failed = 0; + + if (substitute_globally) + { + si += subst_rhs_len; + l_temp = strlen (temp); + substitute_globally++; + continue; + } + else + break; + } + + if (substitute_globally > 1) + { + substitute_globally = 0; + continue; /* don't want to increment i */ + } + + if (failed == 0) + continue; /* don't want to increment i */ + + *ret_string = hist_error (string, starting_index, i, SUBST_FAILED); + free (result); + free (temp); + return (-1); + } + } + i += 2; + } + /* Done with modfiers. */ + /* Believe it or not, we have to back the pointer up by one. */ + --i; + + if (want_quotes) + { + char *x; + + if (want_quotes == 'q') + x = single_quote (temp); + else if (want_quotes == 'x') + x = quote_breaks (temp); + else + x = savestring (temp); + + free (temp); + temp = x; + } + + n = strlen (temp); + if (n >= result_len) + result = xrealloc (result, n + 2); + strcpy (result, temp); + free (temp); + + *end_index_ptr = i; + *ret_string = result; + return (print_only); +} + +/* Expand the string STRING, placing the result into OUTPUT, a pointer + to a string. Returns: + + -1) If there was an error in expansion. + 0) If no expansions took place (or, if the only change in + the text was the de-slashifying of the history expansion + character) + 1) If expansions did take place + 2) If the `p' modifier was given and the caller should print the result + + If an error ocurred in expansion, then OUTPUT contains a descriptive + error message. */ + +#define ADD_STRING(s) \ + do \ + { \ + int sl = strlen (s); \ + j += sl; \ + if (j >= result_len) \ + { \ + while (j >= result_len) \ + result_len += 128; \ + result = xrealloc (result, result_len); \ + } \ + strcpy (result + j - sl, s); \ + } \ + while (0) + +#define ADD_CHAR(c) \ + do \ + { \ + if (j >= result_len - 1) \ + result = xrealloc (result, result_len += 64); \ + result[j++] = c; \ + result[j] = '\0'; \ + } \ + while (0) + +int +history_expand (hstring, output) + char *hstring; + char **output; +{ + register int j; + int i, r, l, passc, cc, modified, eindex, only_printing; + char *string; + + /* The output string, and its length. */ + int result_len; + char *result; + + /* Used when adding the string. */ + char *temp; + + /* Setting the history expansion character to 0 inhibits all + history expansion. */ + if (history_expansion_char == 0) + { + *output = savestring (hstring); + return (0); + } + + /* Prepare the buffer for printing error messages. */ + result = xmalloc (result_len = 256); + result[0] = '\0'; + + only_printing = modified = 0; + l = strlen (hstring); + + /* Grovel the string. Only backslash can quote the history escape + character. We also handle arg specifiers. */ + + /* Before we grovel forever, see if the history_expansion_char appears + anywhere within the text. */ + + /* The quick substitution character is a history expansion all right. That + is to say, "^this^that^" is equivalent to "!!:s^this^that^", and in fact, + that is the substitution that we do. */ + if (hstring[0] == history_subst_char) + { + string = xmalloc (l + 5); + + string[0] = string[1] = history_expansion_char; + string[2] = ':'; + string[3] = 's'; + strcpy (string + 4, hstring); + l += 4; + } + else + { + string = hstring; + /* If not quick substitution, still maybe have to do expansion. */ + + /* `!' followed by one of the characters in history_no_expand_chars + is NOT an expansion. */ + for (i = 0; string[i]; i++) + { + cc = string[i + 1]; + if (string[i] == history_expansion_char) + { + if (!cc || member (cc, history_no_expand_chars)) + continue; +#if defined (SHELL) + /* The shell uses ! as a pattern negation character + in globbing [...] expressions, so let those pass + without expansion. */ + else if (i > 0 && (string[i - 1] == '[') && + member (']', string + i + 1)) + continue; + /* The shell uses ! as the indirect expansion character, so + let those expansions pass as well. */ + else if (i > 1 && string[i - 1] == '{' && string[i - 2] == '$' && + member ('}', string + i + 1)) + continue; +#endif /* SHELL */ + else + break; + } + else if (history_quotes_inhibit_expansion && string[i] == '\'') + { + /* If this is bash, single quotes inhibit history expansion. */ + i++; + hist_string_extract_single_quoted (string, &i); + } + else if (history_quotes_inhibit_expansion && string[i] == '\\') + { + /* If this is bash, allow backslashes to quote single + quotes and the history expansion character. */ + if (cc == '\'' || cc == history_expansion_char) + i++; + } + } + + if (string[i] != history_expansion_char) + { + free (result); + *output = savestring (string); + return (0); + } + } + + /* Extract and perform the substitution. */ + for (passc = i = j = 0; i < l; i++) + { + int tchar = string[i]; + + if (passc) + { + passc = 0; + ADD_CHAR (tchar); + continue; + } + + if (tchar == history_expansion_char) + tchar = -3; + + switch (tchar) + { + default: + ADD_CHAR (string[i]); + break; + + case '\\': + passc++; + ADD_CHAR (tchar); + break; + + case '\'': + { + /* If history_quotes_inhibit_expansion is set, single quotes + inhibit history expansion. */ + if (history_quotes_inhibit_expansion) + { + int quote, slen; + + quote = i++; + hist_string_extract_single_quoted (string, &i); + + slen = i - quote + 2; + temp = xmalloc (slen); + strncpy (temp, string + quote, slen); + temp[slen - 1] = '\0'; + ADD_STRING (temp); + free (temp); + } + else + ADD_CHAR (string[i]); + break; + } + + case -3: /* history_expansion_char */ + cc = string[i + 1]; + + /* If the history_expansion_char is followed by one of the + characters in history_no_expand_chars, then it is not a + candidate for expansion of any kind. */ + if (member (cc, history_no_expand_chars)) + { + ADD_CHAR (string[i]); + break; + } + +#if defined (NO_BANG_HASH_MODIFIERS) + /* There is something that is listed as a `word specifier' in csh + documentation which means `the expanded text to this point'. + That is not a word specifier, it is an event specifier. If we + don't want to allow modifiers with `!#', just stick the current + output line in again. */ + if (cc == '#') + { + if (result) + { + temp = xmalloc (1 + strlen (result)); + strcpy (temp, result); + ADD_STRING (temp); + free (temp); + } + i++; + break; + } +#endif + + r = history_expand_internal (string, i, &eindex, &temp, result); + if (r < 0) + { + *output = temp; + free (result); + if (string != hstring) + free (string); + return -1; + } + else + { + if (temp) + { + modified++; + if (*temp) + ADD_STRING (temp); + free (temp); + } + only_printing = r == 1; + i = eindex; + } + break; + } + } + + *output = result; + if (string != hstring) + free (string); + + if (only_printing) + { + add_history (result); + return (2); + } + + return (modified != 0); +} + +/* Return a consed string which is the word specified in SPEC, and found + in FROM. NULL is returned if there is no spec. The address of + ERROR_POINTER is returned if the word specified cannot be found. + CALLER_INDEX is the offset in SPEC to start looking; it is updated + to point to just after the last character parsed. */ +static char * +get_history_word_specifier (spec, from, caller_index) + char *spec, *from; + int *caller_index; +{ + register int i = *caller_index; + int first, last; + int expecting_word_spec = 0; + char *result; + + /* The range of words to return doesn't exist yet. */ + first = last = 0; + result = (char *)NULL; + + /* If we found a colon, then this *must* be a word specification. If + it isn't, then it is an error. */ + if (spec[i] == ':') + { + i++; + expecting_word_spec++; + } + + /* Handle special cases first. */ + + /* `%' is the word last searched for. */ + if (spec[i] == '%') + { + *caller_index = i + 1; + return (search_match ? savestring (search_match) : savestring ("")); + } + + /* `*' matches all of the arguments, but not the command. */ + if (spec[i] == '*') + { + *caller_index = i + 1; + result = history_arg_extract (1, '$', from); + return (result ? result : savestring ("")); + } + + /* `$' is last arg. */ + if (spec[i] == '$') + { + *caller_index = i + 1; + return (history_arg_extract ('$', '$', from)); + } + + /* Try to get FIRST and LAST figured out. */ + + if (spec[i] == '-') + first = 0; + else if (spec[i] == '^') + first = 1; + else if (_rl_digit_p (spec[i]) && expecting_word_spec) + { + for (first = 0; _rl_digit_p (spec[i]); i++) + first = (first * 10) + _rl_digit_value (spec[i]); + } + else + return ((char *)NULL); /* no valid `first' for word specifier */ + + if (spec[i] == '^' || spec[i] == '*') + { + last = (spec[i] == '^') ? 1 : '$'; /* x* abbreviates x-$ */ + i++; + } + else if (spec[i] != '-') + last = first; + else + { + i++; + + if (_rl_digit_p (spec[i])) + { + for (last = 0; _rl_digit_p (spec[i]); i++) + last = (last * 10) + _rl_digit_value (spec[i]); + } + else if (spec[i] == '$') + { + i++; + last = '$'; + } + else if (!spec[i] || spec[i] == ':') /* could be modifier separator */ + last = -1; /* x- abbreviates x-$ omitting word `$' */ + } + + *caller_index = i; + + if (last >= first || last == '$' || last < 0) + result = history_arg_extract (first, last, from); + + return (result ? result : (char *)&error_pointer); +} + +/* Extract the args specified, starting at FIRST, and ending at LAST. + The args are taken from STRING. If either FIRST or LAST is < 0, + then make that arg count from the right (subtract from the number of + tokens, so that FIRST = -1 means the next to last token on the line). + If LAST is `$' the last arg from STRING is used. */ +char * +history_arg_extract (first, last, string) + int first, last; + char *string; +{ + register int i, len; + char *result; + int size, offset; + char **list; + + /* XXX - think about making history_tokenize return a struct array, + each struct in array being a string and a length to avoid the + calls to strlen below. */ + if ((list = history_tokenize (string)) == NULL) + return ((char *)NULL); + + for (len = 0; list[len]; len++) + ; + + if (last < 0) + last = len + last - 1; + + if (first < 0) + first = len + first - 1; + + if (last == '$') + last = len - 1; + + if (first == '$') + first = len - 1; + + last++; + + if (first >= len || last > len || first < 0 || last < 0 || first > last) + result = ((char *)NULL); + else + { + for (size = 0, i = first; i < last; i++) + size += strlen (list[i]) + 1; + result = xmalloc (size + 1); + result[0] = '\0'; + + for (i = first, offset = 0; i < last; i++) + { + strcpy (result + offset, list[i]); + offset += strlen (list[i]); + if (i + 1 < last) + { + result[offset++] = ' '; + result[offset] = 0; + } + } + } + + for (i = 0; i < len; i++) + free (list[i]); + free (list); + + return (result); +} + +#define slashify_in_quotes "\\`\"$" + +/* Parse STRING into tokens and return an array of strings. If WIND is + not -1 and INDP is not null, we also want the word surrounding index + WIND. The position in the returned array of strings is returned in + *INDP. */ +static char ** +history_tokenize_internal (string, wind, indp) + char *string; + int wind, *indp; +{ + char **result; + register int i, start, result_index, size; + int len, delimiter; + + /* Get a token, and stuff it into RESULT. The tokens are split + exactly where the shell would split them. */ + for (i = result_index = size = 0, result = (char **)NULL; string[i]; ) + { + delimiter = 0; + + /* Skip leading whitespace. */ + for (; string[i] && whitespace (string[i]); i++) + ; + if (string[i] == 0 || string[i] == history_comment_char) + return (result); + + start = i; + + if (member (string[i], "()\n")) + { + i++; + goto got_token; + } + + if (member (string[i], "<>;&|$")) + { + int peek = string[i + 1]; + + if (peek == string[i] && peek != '$') + { + if (peek == '<' && string[i + 2] == '-') + i++; + i += 2; + goto got_token; + } + else + { + if ((peek == '&' && (string[i] == '>' || string[i] == '<')) || + ((peek == '>') && (string[i] == '&')) || + ((peek == '(') && (string[i] == '$'))) + { + i += 2; + goto got_token; + } + } + if (string[i] != '$') + { + i++; + goto got_token; + } + } + + /* Get word from string + i; */ + + if (member (string[i], "\"'`")) + delimiter = string[i++]; + + for (; string[i]; i++) + { + if (string[i] == '\\' && string[i + 1] == '\n') + { + i++; + continue; + } + + if (string[i] == '\\' && delimiter != '\'' && + (delimiter != '"' || member (string[i], slashify_in_quotes))) + { + i++; + continue; + } + + if (delimiter && string[i] == delimiter) + { + delimiter = 0; + continue; + } + + if (!delimiter && (member (string[i], " \t\n;&()|<>"))) + break; + + if (!delimiter && member (string[i], "\"'`")) + delimiter = string[i]; + } + + got_token: + + /* If we are looking for the word in which the character at a + particular index falls, remember it. */ + if (indp && wind != -1 && wind >= start && wind < i) + *indp = result_index; + + len = i - start; + if (result_index + 2 >= size) + result = (char **)xrealloc (result, ((size += 10) * sizeof (char *))); + result[result_index] = xmalloc (1 + len); + strncpy (result[result_index], string + start, len); + result[result_index][len] = '\0'; + result[++result_index] = (char *)NULL; + } + + return (result); +} + +/* Return an array of tokens, much as the shell might. The tokens are + parsed out of STRING. */ +char ** +history_tokenize (string) + char *string; +{ + return (history_tokenize_internal (string, -1, (int *)NULL)); +} + +/* Find and return the word which contains the character at index IND + in the history line LINE. Used to save the word matched by the + last history !?string? search. */ +static char * +history_find_word (line, ind) + char *line; + int ind; +{ + char **words, *s; + int i, wind; + + words = history_tokenize_internal (line, ind, &wind); + if (wind == -1) + return ((char *)NULL); + s = words[wind]; + for (i = 0; i < wind; i++) + free (words[i]); + for (i = wind + 1; words[i]; i++) + free (words[i]); + free (words); + return s; +} diff --git a/lib/readline/histfile.c b/lib/readline/histfile.c new file mode 100644 index 0000000..355d46e --- /dev/null +++ b/lib/readline/histfile.c @@ -0,0 +1,324 @@ +/* histfile.c - functions to manipulate the history file. */ + +/* Copyright (C) 1989, 1992 Free Software Foundation, Inc. + + This file contains the GNU History Library (the Library), a set of + routines for managing the text of previously typed lines. + + The 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 1, or (at your option) + any later version. + + The 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, + 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* The goal is to make the implementation transparent, so that you + don't have to know what data types are used, just what functions + you can call. I think I have done that. */ +#define READLINE_LIBRARY + +#if defined (HAVE_CONFIG_H) +# include +#endif + +#include + +#include +#include +#include +#include + +#if defined (HAVE_STDLIB_H) +# include +#else +# include "ansi_stdlib.h" +#endif /* HAVE_STDLIB_H */ + +#if defined (HAVE_UNISTD_H) +# include +#endif + +#if defined (HAVE_STRING_H) +# include +#else +# include +#endif /* !HAVE_STRING_H */ + +#include +#if !defined (errno) +extern int errno; +#endif /* !errno */ + +#include "history.h" +#include "histlib.h" + +extern char *xmalloc (), *xrealloc (); + +/* Return the string that should be used in the place of this + filename. This only matters when you don't specify the + filename to read_history (), or write_history (). */ +static char * +history_filename (filename) + char *filename; +{ + char *return_val, *home; + int home_len; + + return_val = filename ? savestring (filename) : (char *)NULL; + + if (return_val) + return (return_val); + + home = getenv ("HOME"); + + if (home == 0) + { + home = "."; + home_len = 1; + } + else + home_len = strlen (home); + + return_val = xmalloc (2 + home_len + 8); /* strlen(".history") == 8 */ + strcpy (return_val, home); + return_val[home_len] = '/'; + strcpy (return_val + home_len + 1, ".history"); + + return (return_val); +} + +/* Add the contents of FILENAME to the history list, a line at a time. + If FILENAME is NULL, then read from ~/.history. Returns 0 if + successful, or errno if not. */ +int +read_history (filename) + char *filename; +{ + return (read_history_range (filename, 0, -1)); +} + +/* Read a range of lines from FILENAME, adding them to the history list. + Start reading at the FROM'th line and end at the TO'th. If FROM + is zero, start at the beginning. If TO is less than FROM, read + until the end of the file. If FILENAME is NULL, then read from + ~/.history. Returns 0 if successful, or errno if not. */ +int +read_history_range (filename, from, to) + char *filename; + int from, to; +{ + register int line_start, line_end; + char *input, *buffer = (char *)NULL; + int file, current_line; + struct stat finfo; + + input = history_filename (filename); + file = open (input, O_RDONLY, 0666); + + if ((file < 0) || (fstat (file, &finfo) == -1)) + goto error_and_exit; + + buffer = xmalloc ((int)finfo.st_size + 1); + + if (read (file, buffer, finfo.st_size) != finfo.st_size) + { + error_and_exit: + if (file >= 0) + close (file); + + FREE (input); + FREE (buffer); + + return (errno); + } + + close (file); + + /* Set TO to larger than end of file if negative. */ + if (to < 0) + to = finfo.st_size; + + /* Start at beginning of file, work to end. */ + line_start = line_end = current_line = 0; + + /* Skip lines until we are at FROM. */ + while (line_start < finfo.st_size && current_line < from) + { + for (line_end = line_start; line_end < finfo.st_size; line_end++) + if (buffer[line_end] == '\n') + { + current_line++; + line_start = line_end + 1; + if (current_line == from) + break; + } + } + + /* If there are lines left to gobble, then gobble them now. */ + for (line_end = line_start; line_end < finfo.st_size; line_end++) + if (buffer[line_end] == '\n') + { + buffer[line_end] = '\0'; + + if (buffer[line_start]) + add_history (buffer + line_start); + + current_line++; + + if (current_line >= to) + break; + + line_start = line_end + 1; + } + + FREE (input); + FREE (buffer); + + return (0); +} + +/* Truncate the history file FNAME, leaving only LINES trailing lines. + If FNAME is NULL, then use ~/.history. */ +int +history_truncate_file (fname, lines) + char *fname; + register int lines; +{ + register int i; + int file, chars_read; + char *buffer = (char *)NULL, *filename; + struct stat finfo; + + filename = history_filename (fname); + file = open (filename, O_RDONLY, 0666); + + if (file == -1 || fstat (file, &finfo) == -1) + goto truncate_exit; + + buffer = xmalloc ((int)finfo.st_size + 1); + chars_read = read (file, buffer, finfo.st_size); + close (file); + + if (chars_read <= 0) + goto truncate_exit; + + /* Count backwards from the end of buffer until we have passed + LINES lines. */ + for (i = chars_read - 1; lines && i; i--) + { + if (buffer[i] == '\n') + lines--; + } + + /* If this is the first line, then the file contains exactly the + number of lines we want to truncate to, so we don't need to do + anything. It's the first line if we don't find a newline between + the current value of i and 0. Otherwise, write from the start of + this line until the end of the buffer. */ + for ( ; i; i--) + if (buffer[i] == '\n') + { + i++; + break; + } + + /* Write only if there are more lines in the file than we want to + truncate to. */ + if (i && ((file = open (filename, O_WRONLY|O_TRUNC, 0666)) != -1)) + { + write (file, buffer + i, finfo.st_size - i); + close (file); + } + + truncate_exit: + + FREE (buffer); + + free (filename); + return 0; +} + +/* Workhorse function for writing history. Writes NELEMENT entries + from the history list to FILENAME. OVERWRITE is non-zero if you + wish to replace FILENAME with the entries. */ +static int +history_do_write (filename, nelements, overwrite) + char *filename; + int nelements, overwrite; +{ + register int i; + char *output = history_filename (filename); + int file, mode; + + mode = overwrite ? O_WRONLY | O_CREAT | O_TRUNC : O_WRONLY | O_APPEND; + + if ((file = open (output, mode, 0666)) == -1) + { + FREE (output); + return (errno); + } + + if (nelements > history_length) + nelements = history_length; + + /* Build a buffer of all the lines to write, and write them in one syscall. + Suggested by Peter Ho (peter@robosts.oxford.ac.uk). */ + { + HIST_ENTRY **the_history; /* local */ + register int j; + int buffer_size; + char *buffer; + + the_history = history_list (); + /* Calculate the total number of bytes to write. */ + for (buffer_size = 0, i = history_length - nelements; i < history_length; i++) + buffer_size += 1 + strlen (the_history[i]->line); + + /* Allocate the buffer, and fill it. */ + buffer = xmalloc (buffer_size); + + for (j = 0, i = history_length - nelements; i < history_length; i++) + { + strcpy (buffer + j, the_history[i]->line); + j += strlen (the_history[i]->line); + buffer[j++] = '\n'; + } + + write (file, buffer, buffer_size); + free (buffer); + } + + close (file); + + FREE (output); + + return (0); +} + +/* Append NELEMENT entries to FILENAME. The entries appended are from + the end of the list minus NELEMENTs up to the end of the list. */ +int +append_history (nelements, filename) + int nelements; + char *filename; +{ + return (history_do_write (filename, nelements, HISTORY_APPEND)); +} + +/* Overwrite FILENAME with the current history. If FILENAME is NULL, + then write the history list to ~/.history. Values returned + are as in read_history ().*/ +int +write_history (filename) + char *filename; +{ + return (history_do_write (filename, history_length, HISTORY_OVERWRITE)); +} diff --git a/lib/readline/histlib.h b/lib/readline/histlib.h new file mode 100644 index 0000000..10a40d7 --- /dev/null +++ b/lib/readline/histlib.h @@ -0,0 +1,81 @@ +/* histlib.h -- internal definitions for the history library. */ +/* Copyright (C) 1989, 1992 Free Software Foundation, Inc. + + This file contains the GNU History Library (the Library), a set of + routines for managing the text of previously typed lines. + + The 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 1, or (at your option) + any later version. + + The 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, + 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#if !defined (_HISTLIB_H_) +#define _HISTLIB_H_ + +/* Function pointers can be declared as (Function *)foo. */ +#if !defined (_FUNCTION_DEF) +# define _FUNCTION_DEF +typedef int Function (); +typedef void VFunction (); +typedef char *CPFunction (); +typedef char **CPPFunction (); +#endif /* _FUNCTION_DEF */ + +#define STREQ(a, b) (((a)[0] == (b)[0]) && (strcmp ((a), (b)) == 0)) +#define STREQN(a, b, n) (((a)[0] == (b)[0]) && (strncmp ((a), (b), (n)) == 0)) + +#ifndef savestring +# ifndef strcpy +extern char *strcpy (); +# endif +#define savestring(x) strcpy (xmalloc (1 + strlen (x)), (x)) +#endif + +#ifndef whitespace +#define whitespace(c) (((c) == ' ') || ((c) == '\t')) +#endif + +#ifndef _rl_digit_p +#define _rl_digit_p(c) ((c) >= '0' && (c) <= '9') +#endif + +#ifndef _rl_digit_value +#define _rl_digit_value(c) ((c) - '0') +#endif + +#ifndef member +# ifndef strchr +extern char *strchr (); +# endif +#define member(c, s) ((c) ? ((char *)strchr ((s), (c)) != (char *)NULL) : 0) +#endif + +#ifndef FREE +# define FREE(x) if (x) free (x) +#endif + +/* Possible history errors passed to hist_error. */ +#define EVENT_NOT_FOUND 0 +#define BAD_WORD_SPEC 1 +#define SUBST_FAILED 2 +#define BAD_MODIFIER 3 + +/* Possible definitions for history starting point specification. */ +#define ANCHORED_SEARCH 1 +#define NON_ANCHORED_SEARCH 0 + +/* Possible definitions for what style of writing the history file we want. */ +#define HISTORY_APPEND 0 +#define HISTORY_OVERWRITE 1 + +#endif /* !_HISTLIB_H_ */ diff --git a/lib/readline/history.c b/lib/readline/history.c index 9172755..fb9d68e 100644 --- a/lib/readline/history.c +++ b/lib/readline/history.c @@ -25,88 +25,35 @@ you can call. I think I have done that. */ #define READLINE_LIBRARY +#if defined (HAVE_CONFIG_H) +# include +#endif + #include -#include -#include -#include -#include + #if defined (HAVE_STDLIB_H) # include #else # include "ansi_stdlib.h" #endif /* HAVE_STDLIB_H */ + #if defined (HAVE_UNISTD_H) # include #endif + #if defined (HAVE_STRING_H) # include #else # include #endif /* !HAVE_STRING_H */ -#include - -/* Not all systems declare ERRNO in errno.h... and some systems #define it! */ -#if !defined (errno) -extern int errno; -#endif /* !errno */ -#include "memalloc.h" #include "history.h" +#include "histlib.h" -#if defined (STATIC_MALLOC) -static char *xmalloc (), *xrealloc (); -#else extern char *xmalloc (), *xrealloc (); -#endif /* STATIC_MALLOC */ - -#define STREQ(a, b) (((a)[0] == (b)[0]) && (strcmp ((a), (b)) == 0)) -#define STREQN(a, b, n) (((a)[0] == (b)[0]) && (strncmp ((a), (b), (n)) == 0)) - -#ifndef savestring -# ifndef strcpy -extern char *strcpy (); -# endif -#define savestring(x) strcpy (xmalloc (1 + strlen (x)), (x)) -#endif - -#ifndef whitespace -#define whitespace(c) (((c) == ' ') || ((c) == '\t')) -#endif - -#ifndef digit_p -#define digit_p(c) ((c) >= '0' && (c) <= '9') -#endif - -#ifndef digit_value -#define digit_value(c) ((c) - '0') -#endif -#ifndef member -# ifndef strchr -extern char *strchr (); -# endif -#define member(c, s) ((c) ? ((char *)strchr ((s), (c)) != (char *)NULL) : 0) -#endif - -/* Possible history errors passed to hist_error. */ -#define EVENT_NOT_FOUND 0 -#define BAD_WORD_SPEC 1 -#define SUBST_FAILED 2 -#define BAD_MODIFIER 3 - -static char error_pointer; - -static char *subst_lhs; -static char *subst_rhs; -static int subst_lhs_len = 0; -static int subst_rhs_len = 0; - -static char *get_history_word_specifier (); -static char *history_find_word (); - -#if defined (SHELL) -extern char *single_quote (); -#endif +/* The number of slots to increase the_history by. */ +#define DEFAULT_HISTORY_GROW_SIZE 50 /* **************************************************************** */ /* */ @@ -119,7 +66,7 @@ static HIST_ENTRY **the_history = (HIST_ENTRY **)NULL; /* Non-zero means that we have enforced a limit on the amount of history that we save. */ -static int history_stifled = 0; +static int history_stifled; /* If HISTORY_STIFLED is non-zero, then this is the maximum number of entries to remember. */ @@ -127,34 +74,13 @@ int max_input_history; /* The current location of the interactive history pointer. Just makes life easier for outside callers. */ -static int history_offset = 0; +int history_offset; -/* The number of strings currently stored in the input_history list. */ -int history_length = 0; +/* The number of strings currently stored in the history list. */ +int history_length; /* The current number of slots allocated to the input_history. */ -static int history_size = 0; - -/* The number of slots to increase the_history by. */ -#define DEFAULT_HISTORY_GROW_SIZE 50 - -/* The character that represents the start of a history expansion - request. This is usually `!'. */ -char history_expansion_char = '!'; - -/* The character that invokes word substitution if found at the start of - a line. This is usually `^'. */ -char history_subst_char = '^'; - -/* During tokenization, if this character is seen as the first character - of a word, then it, and all subsequent characters upto a newline are - ignored. For a Bourne shell, this should be '#'. Bash special cases - the interactive comment character to not be a comment delimiter. */ -char history_comment_char = '\0'; - -/* The list of characters which inhibit the expansion of text if found - immediately following history_expansion_char. */ -char *history_no_expand_chars = " \t\n\r="; +static int history_size; /* The logical `base' of the history array. It defaults to 1. */ int history_base = 1; @@ -213,6 +139,77 @@ history_total_bytes () return (result); } +/* Returns the magic number which says what history element we are + looking at now. In this implementation, it returns history_offset. */ +int +where_history () +{ + return (history_offset); +} + +/* Make the current history item be the one at POS, an absolute index. + Returns zero if POS is out of range, else non-zero. */ +int +history_set_pos (pos) + int pos; +{ + if (pos > history_length || pos < 0 || !the_history) + return (0); + history_offset = pos; + return (1); +} + +/* Return the current history array. The caller has to be carefull, since this + is the actual array of data, and could be bashed or made corrupt easily. + The array is terminated with a NULL pointer. */ +HIST_ENTRY ** +history_list () +{ + return (the_history); +} + +/* Return the history entry at the current position, as determined by + history_offset. If there is no entry there, return a NULL pointer. */ +HIST_ENTRY * +current_history () +{ + return ((history_offset == history_length) || the_history == 0) + ? (HIST_ENTRY *)NULL + : the_history[history_offset]; +} + +/* Back up history_offset to the previous history entry, and return + a pointer to that entry. If there is no previous entry then return + a NULL pointer. */ +HIST_ENTRY * +previous_history () +{ + return history_offset ? the_history[--history_offset] : (HIST_ENTRY *)NULL; +} + +/* Move history_offset forward to the next history entry, and return + a pointer to that entry. If there is no next entry then return a + NULL pointer. */ +HIST_ENTRY * +next_history () +{ + return (history_offset == history_length) ? (HIST_ENTRY *)NULL : the_history[++history_offset]; +} + +/* Return the history entry which is logically at OFFSET in the history array. + OFFSET is relative to history_base. */ +HIST_ENTRY * +history_get (offset) + int offset; +{ + int local_index; + + local_index = offset - history_base; + return (local_index >= history_length || local_index < 0 || !the_history) + ? (HIST_ENTRY *)NULL + : the_history[local_index]; +} + /* Place STRING at the end of the history list. The data field is set to NULL. */ void @@ -242,16 +239,14 @@ add_history (string) the_history[i] = the_history[i + 1]; history_base++; - } else { - if (!history_size) + if (history_size == 0) { history_size = DEFAULT_HISTORY_GROW_SIZE; the_history = (HIST_ENTRY **)xmalloc (history_size * sizeof (HIST_ENTRY *)); history_length = 1; - } else { @@ -297,136 +292,6 @@ replace_history_entry (which, line, data) return (old_value); } -/* Returns the magic number which says what history element we are - looking at now. In this implementation, it returns history_offset. */ -int -where_history () -{ - return (history_offset); -} - -/* Search the history for STRING, starting at history_offset. - If DIRECTION < 0, then the search is through previous entries, else - through subsequent. If ANCHORED is non-zero, the string must - appear at the beginning of a history line, otherwise, the string - may appear anywhere in the line. If the string is found, then - current_history () is the history entry, and the value of this - function is the offset in the line of that history entry that the - string was found in. Otherwise, nothing is changed, and a -1 is - returned. */ - -#define ANCHORED_SEARCH 1 -#define NON_ANCHORED_SEARCH 0 - -static int -history_search_internal (string, direction, anchored) - char *string; - int direction, anchored; -{ - register int i, reverse; - register char *line; - register int line_index; - int string_len; - - i = history_offset; - reverse = (direction < 0); - - /* Take care of trivial cases first. */ - if (string == 0 || *string == '\0') - return (-1); - - if (!history_length || ((i == history_length) && !reverse)) - return (-1); - - if (reverse && (i == history_length)) - i--; - -#define NEXT_LINE() do { if (reverse) i--; else i++; } while (0) - - string_len = strlen (string); - while (1) - { - /* Search each line in the history list for STRING. */ - - /* At limit for direction? */ - if ((reverse && i < 0) || (!reverse && i == history_length)) - return (-1); - - line = the_history[i]->line; - line_index = strlen (line); - - /* If STRING is longer than line, no match. */ - if (string_len > line_index) - { - NEXT_LINE (); - continue; - } - - /* Handle anchored searches first. */ - if (anchored == ANCHORED_SEARCH) - { - if (STREQN (string, line, string_len)) - { - history_offset = i; - return (0); - } - - NEXT_LINE (); - continue; - } - - /* Do substring search. */ - if (reverse) - { - line_index -= string_len; - - while (line_index >= 0) - { - if (STREQN (string, line + line_index, string_len)) - { - history_offset = i; - return (line_index); - } - line_index--; - } - } - else - { - register int limit = line_index - string_len + 1; - line_index = 0; - - while (line_index < limit) - { - if (STREQN (string, line + line_index, string_len)) - { - history_offset = i; - return (line_index); - } - line_index++; - } - } - NEXT_LINE (); - } -} - -/* Do a non-anchored search for STRING through the history in DIRECTION. */ -int -history_search (string, direction) - char *string; - int direction; -{ - return (history_search_internal (string, direction, NON_ANCHORED_SEARCH)); -} - -/* Do an anchored search for string through the history in DIRECTION. */ -int -history_search_prefix (string, direction) - char *string; - int direction; -{ - return (history_search_internal (string, direction, ANCHORED_SEARCH)); -} - /* Remove history element WHICH from the history. The removed element is returned to you so you can free the line, data, and containing structure. */ @@ -465,7 +330,7 @@ stifle_history (max) register int i, j; /* This loses because we cannot free the data. */ - for (i = 0; i < (history_length - max); i++) + for (i = 0, j = history_length - max; i < j; i++) { free (the_history[i]->line); free (the_history[i]); @@ -482,21 +347,19 @@ stifle_history (max) max_input_history = max; } -/* Stop stifling the history. This returns the previous amount the history - was stifled by. The value is positive if the history was stifled, negative - if it wasn't. */ +/* Stop stifling the history. This returns the previous amount the + history was stifled by. The value is positive if the history was + stifled, negative if it wasn't. */ int unstifle_history () { - int result = max_input_history; - if (history_stifled) { - result = -result; history_stifled = 0; + return (-max_input_history); } - return (result); + return (max_input_history); } int @@ -505,1714 +368,18 @@ history_is_stifled () return (history_stifled); } -/* Return the string that should be used in the place of this - filename. This only matters when you don't specify the - filename to read_history (), or write_history (). */ -static char * -history_filename (filename) - char *filename; -{ - char *return_val = filename ? savestring (filename) : (char *)NULL; - - if (!return_val) - { - char *home; - int home_len; - - home = getenv ("HOME"); - - if (!home) - home = "."; - - home_len = strlen (home); - /* strlen(".history") == 8 */ - return_val = xmalloc (2 + home_len + 8); - - strcpy (return_val, home); - return_val[home_len] = '/'; - strcpy (return_val + home_len + 1, ".history"); - } - - return (return_val); -} - -/* Add the contents of FILENAME to the history list, a line at a time. - If FILENAME is NULL, then read from ~/.history. Returns 0 if - successful, or errno if not. */ -int -read_history (filename) - char *filename; -{ - return (read_history_range (filename, 0, -1)); -} - -/* Read a range of lines from FILENAME, adding them to the history list. - Start reading at the FROM'th line and end at the TO'th. If FROM - is zero, start at the beginning. If TO is less than FROM, read - until the end of the file. If FILENAME is NULL, then read from - ~/.history. Returns 0 if successful, or errno if not. */ -int -read_history_range (filename, from, to) - char *filename; - int from, to; -{ - register int line_start, line_end; - char *input, *buffer = (char *)NULL; - int file, current_line; - struct stat finfo; - - input = history_filename (filename); - file = open (input, O_RDONLY, 0666); - - if ((file < 0) || (fstat (file, &finfo) == -1)) - goto error_and_exit; - - buffer = xmalloc ((int)finfo.st_size + 1); - - if (read (file, buffer, finfo.st_size) != finfo.st_size) - { - error_and_exit: - if (file >= 0) - close (file); - - if (input) - free (input); - - if (buffer) - free (buffer); - - return (errno); - } - - close (file); - - /* Set TO to larger than end of file if negative. */ - if (to < 0) - to = finfo.st_size; - - /* Start at beginning of file, work to end. */ - line_start = line_end = current_line = 0; - - /* Skip lines until we are at FROM. */ - while (line_start < finfo.st_size && current_line < from) - { - for (line_end = line_start; line_end < finfo.st_size; line_end++) - if (buffer[line_end] == '\n') - { - current_line++; - line_start = line_end + 1; - if (current_line == from) - break; - } - } - - /* If there are lines left to gobble, then gobble them now. */ - for (line_end = line_start; line_end < finfo.st_size; line_end++) - if (buffer[line_end] == '\n') - { - buffer[line_end] = '\0'; - - if (buffer[line_start]) - add_history (buffer + line_start); - - current_line++; - - if (current_line >= to) - break; - - line_start = line_end + 1; - } - - if (input) - free (input); - - if (buffer) - free (buffer); - - return (0); -} - -/* Truncate the history file FNAME, leaving only LINES trailing lines. - If FNAME is NULL, then use ~/.history. */ -int -history_truncate_file (fname, lines) - char *fname; - register int lines; -{ - register int i; - int file, chars_read; - char *buffer = (char *)NULL, *filename; - struct stat finfo; - - filename = history_filename (fname); - file = open (filename, O_RDONLY, 0666); - - if (file == -1 || fstat (file, &finfo) == -1) - goto truncate_exit; - - buffer = xmalloc ((int)finfo.st_size + 1); - chars_read = read (file, buffer, finfo.st_size); - close (file); - - if (chars_read <= 0) - goto truncate_exit; - - /* Count backwards from the end of buffer until we have passed - LINES lines. */ - for (i = chars_read - 1; lines && i; i--) - { - if (buffer[i] == '\n') - lines--; - } - - /* If this is the first line, then the file contains exactly the - number of lines we want to truncate to, so we don't need to do - anything. It's the first line if we don't find a newline between - the current value of i and 0. Otherwise, write from the start of - this line until the end of the buffer. */ - for ( ; i; i--) - if (buffer[i] == '\n') - { - i++; - break; - } - - /* Write only if there are more lines in the file than we want to - truncate to. */ - if (i && ((file = open (filename, O_WRONLY|O_TRUNC, 0666)) != -1)) - { - write (file, buffer + i, finfo.st_size - i); - close (file); - } - - truncate_exit: - if (buffer) - free (buffer); - - free (filename); - return 0; -} - -#define HISTORY_APPEND 0 -#define HISTORY_OVERWRITE 1 - -/* Workhorse function for writing history. Writes NELEMENT entries - from the history list to FILENAME. OVERWRITE is non-zero if you - wish to replace FILENAME with the entries. */ -static int -history_do_write (filename, nelements, overwrite) - char *filename; - int nelements, overwrite; +void +clear_history () { register int i; - char *output = history_filename (filename); - int file, mode; - - mode = overwrite ? O_WRONLY | O_CREAT | O_TRUNC : O_WRONLY | O_APPEND; - if ((file = open (output, mode, 0666)) == -1) + /* This loses because we cannot free the data. */ + for (i = 0; i < history_length; i++) { - if (output) - free (output); - - return (errno); + free (the_history[i]->line); + free (the_history[i]); + the_history[i] = (HIST_ENTRY *)NULL; } - if (nelements > history_length) - nelements = history_length; - - /* Build a buffer of all the lines to write, and write them in one syscall. - Suggested by Peter Ho (peter@robosts.oxford.ac.uk). */ - { - register int j = 0; - int buffer_size = 0; - char *buffer; - - /* Calculate the total number of bytes to write. */ - for (i = history_length - nelements; i < history_length; i++) - buffer_size += 1 + strlen (the_history[i]->line); - - /* Allocate the buffer, and fill it. */ - buffer = xmalloc (buffer_size); - - for (i = history_length - nelements; i < history_length; i++) - { - strcpy (buffer + j, the_history[i]->line); - j += strlen (the_history[i]->line); - buffer[j++] = '\n'; - } - - write (file, buffer, buffer_size); - free (buffer); - } - - close (file); - - if (output) - free (output); - - return (0); -} - -/* Append NELEMENT entries to FILENAME. The entries appended are from - the end of the list minus NELEMENTs up to the end of the list. */ -int -append_history (nelements, filename) - int nelements; - char *filename; -{ - return (history_do_write (filename, nelements, HISTORY_APPEND)); -} - -/* Overwrite FILENAME with the current history. If FILENAME is NULL, - then write the history list to ~/.history. Values returned - are as in read_history ().*/ -int -write_history (filename) - char *filename; -{ - return (history_do_write (filename, history_length, HISTORY_OVERWRITE)); -} - -/* Return the history entry at the current position, as determined by - history_offset. If there is no entry there, return a NULL pointer. */ -HIST_ENTRY * -current_history () -{ - if ((history_offset == history_length) || !the_history) - return ((HIST_ENTRY *)NULL); - else - return (the_history[history_offset]); -} - -/* Back up history_offset to the previous history entry, and return - a pointer to that entry. If there is no previous entry then return - a NULL pointer. */ -HIST_ENTRY * -previous_history () -{ - if (!history_offset) - return ((HIST_ENTRY *)NULL); - else - return (the_history[--history_offset]); + history_offset = history_length = 0; } - -/* Move history_offset forward to the next history entry, and return - a pointer to that entry. If there is no next entry then return a - NULL pointer. */ -HIST_ENTRY * -next_history () -{ - if (history_offset == history_length) - return ((HIST_ENTRY *)NULL); - else - return (the_history[++history_offset]); -} - -/* Return the current history array. The caller has to be carefull, since this - is the actual array of data, and could be bashed or made corrupt easily. - The array is terminated with a NULL pointer. */ -HIST_ENTRY ** -history_list () -{ - return (the_history); -} - -/* Return the history entry which is logically at OFFSET in the history array. - OFFSET is relative to history_base. */ -HIST_ENTRY * -history_get (offset) - int offset; -{ - int local_index = offset - history_base; - - if (local_index >= history_length || - local_index < 0 || - !the_history) - return ((HIST_ENTRY *)NULL); - return (the_history[local_index]); -} - -/* Search for STRING in the history list. DIR is < 0 for searching - backwards. POS is an absolute index into the history list at - which point to begin searching. */ -int -history_search_pos (string, dir, pos) - char *string; - int dir, pos; -{ - int ret, old = where_history (); - history_set_pos (pos); - if (history_search (string, dir) == -1) - { - history_set_pos (old); - return (-1); - } - ret = where_history (); - history_set_pos (old); - return ret; -} - -/* Make the current history item be the one at POS, an absolute index. - Returns zero if POS is out of range, else non-zero. */ -int -history_set_pos (pos) - int pos; -{ - if (pos > history_length || pos < 0 || !the_history) - return (0); - history_offset = pos; - return (1); -} - - -/* **************************************************************** */ -/* */ -/* History Expansion */ -/* */ -/* **************************************************************** */ - -/* Hairy history expansion on text, not tokens. This is of general - use, and thus belongs in this library. */ - -/* The last string searched for in a !?string? search. */ -static char *search_string = (char *)NULL; - -/* The last string matched by a !?string? search. */ -static char *search_match = (char *)NULL; - -/* Return the event specified at TEXT + OFFSET modifying OFFSET to - point to after the event specifier. Just a pointer to the history - line is returned; NULL is returned in the event of a bad specifier. - You pass STRING with *INDEX equal to the history_expansion_char that - begins this specification. - DELIMITING_QUOTE is a character that is allowed to end the string - specification for what to search for in addition to the normal - characters `:', ` ', `\t', `\n', and sometimes `?'. - So you might call this function like: - line = get_history_event ("!echo:p", &index, 0); */ -char * -get_history_event (string, caller_index, delimiting_quote) - char *string; - int *caller_index; - int delimiting_quote; -{ - register int i = *caller_index; - register char c; - HIST_ENTRY *entry; - int which, sign = 1; - int local_index, search_mode, substring_okay = 0; - char *temp; - - /* The event can be specified in a number of ways. - - !! the previous command - !n command line N - !-n current command-line minus N - !str the most recent command starting with STR - !?str[?] - the most recent command containing STR - - All values N are determined via HISTORY_BASE. */ - - if (string[i] != history_expansion_char) - return ((char *)NULL); - - /* Move on to the specification. */ - i++; - -#define RETURN_ENTRY(e, w) \ - return ((e = history_get (w)) ? e->line : (char *)NULL) - - /* Handle !! case. */ - if (string[i] == history_expansion_char) - { - i++; - which = history_base + (history_length - 1); - *caller_index = i; - RETURN_ENTRY (entry, which); - } - - /* Hack case of numeric line specification. */ - if (string[i] == '-') - { - sign = -1; - i++; - } - - if (digit_p (string[i])) - { - /* Get the extent of the digits and compute the value. */ - for (which = 0; digit_p (string[i]); i++) - which = (which * 10) + digit_value (string[i]); - - *caller_index = i; - - if (sign < 0) - which = (history_length + history_base) - which; - - RETURN_ENTRY (entry, which); - } - - /* This must be something to search for. If the spec begins with - a '?', then the string may be anywhere on the line. Otherwise, - the string must be found at the start of a line. */ - if (string[i] == '?') - { - substring_okay++; - i++; - } - - /* Only a closing `?' or a newline delimit a substring search string. */ - for (local_index = i; c = string[i]; i++) - if ((!substring_okay && (whitespace (c) || c == ':' || -#if defined (SHELL) - member (c, ";&()|<>") || -#endif /* SHELL */ - string[i] == delimiting_quote)) || - string[i] == '\n' || - (substring_okay && string[i] == '?')) - break; - - temp = xmalloc (1 + (i - local_index)); - strncpy (temp, &string[local_index], (i - local_index)); - temp[i - local_index] = '\0'; - - if (substring_okay && string[i] == '?') - i++; - - *caller_index = i; - -#define FAIL_SEARCH() \ - do { history_offset = history_length; free (temp) ; return (char *)NULL; } while (0) - - search_mode = substring_okay ? NON_ANCHORED_SEARCH : ANCHORED_SEARCH; - while (1) - { - local_index = history_search_internal (temp, -1, search_mode); - - if (local_index < 0) - FAIL_SEARCH (); - - if (local_index == 0 || substring_okay) - { - entry = current_history (); - history_offset = history_length; - - /* If this was a substring search, then remember the - string that we matched for word substitution. */ - if (substring_okay) - { - if (search_string) - free (search_string); - search_string = temp; - - if (search_match) - free (search_match); - search_match = history_find_word (entry->line, local_index); - } - else - free (temp); - return (entry->line); - } - - if (history_offset) - history_offset--; - else - FAIL_SEARCH (); - } -#undef FAIL_SEARCH -#undef RETURN_ENTRY -} -#if defined (SHELL) -/* Function for extracting single-quoted strings. Used for inhibiting - history expansion within single quotes. */ - -/* Extract the contents of STRING as if it is enclosed in single quotes. - SINDEX, when passed in, is the offset of the character immediately - following the opening single quote; on exit, SINDEX is left pointing - to the closing single quote. */ -static void -rl_string_extract_single_quoted (string, sindex) - char *string; - int *sindex; -{ - register int i = *sindex; - - while (string[i] && string[i] != '\'') - i++; - - *sindex = i; -} - -static char * -quote_breaks (s) - char *s; -{ - register char *p, *r; - char *ret; - int len = 3; - - for (p = s; p && *p; p++, len++) - { - if (*p == '\'') - len += 3; - else if (whitespace (*p) || *p == '\n') - len += 2; - } - - r = ret = xmalloc (len); - *r++ = '\''; - for (p = s; p && *p; ) - { - if (*p == '\'') - { - *r++ = '\''; - *r++ = '\\'; - *r++ = '\''; - *r++ = '\''; - p++; - } - else if (whitespace (*p) || *p == '\n') - { - *r++ = '\''; - *r++ = *p++; - *r++ = '\''; - } - else - *r++ = *p++; - } - *r++ = '\''; - *r = '\0'; - return ret; -} -#endif /* SHELL */ - -static char * -hist_error(s, start, current, errtype) - char *s; - int start, current, errtype; -{ - char *temp, *emsg; - int ll, elen; - - ll = current - start; - - switch (errtype) - { - case EVENT_NOT_FOUND: - emsg = "event not found"; - elen = 15; - break; - case BAD_WORD_SPEC: - emsg = "bad word specifier"; - elen = 18; - break; - case SUBST_FAILED: - emsg = "substitution failed"; - elen = 19; - break; - case BAD_MODIFIER: - emsg = "unrecognized history modifier"; - elen = 29; - break; - default: - emsg = "unknown expansion error"; - elen = 23; - break; - } - - temp = xmalloc (ll + elen + 3); - strncpy (temp, s + start, ll); - temp[ll] = ':'; - temp[ll + 1] = ' '; - strcpy (temp + ll + 2, emsg); - return (temp); -} - -/* Get a history substitution string from STR starting at *IPTR - and return it. The length is returned in LENPTR. - - A backslash can quote the delimiter. If the string is the - empty string, the previous pattern is used. If there is - no previous pattern for the lhs, the last history search - string is used. - - If IS_RHS is 1, we ignore empty strings and set the pattern - to "" anyway. subst_lhs is not changed if the lhs is empty; - subst_rhs is allowed to be set to the empty string. */ - -static char * -get_subst_pattern (str, iptr, delimiter, is_rhs, lenptr) - char *str; - int *iptr, delimiter, is_rhs, *lenptr; -{ - register int si, i, j, k; - char *s = (char *) NULL; - - i = *iptr; - - for (si = i; str[si] && str[si] != delimiter; si++) - if (str[si] == '\\' && str[si + 1] == delimiter) - si++; - - if (si > i || is_rhs) - { - s = xmalloc (si - i + 1); - for (j = 0, k = i; k < si; j++, k++) - { - /* Remove a backslash quoting the search string delimiter. */ - if (str[k] == '\\' && str[k + 1] == delimiter) - k++; - s[j] = str[k]; - } - s[j] = '\0'; - if (lenptr) - *lenptr = j; - } - - i = si; - if (str[i]) - i++; - *iptr = i; - - return s; -} - -static void -postproc_subst_rhs () -{ - char *new; - int i, j, new_size; - - new = xmalloc (new_size = subst_rhs_len + subst_lhs_len); - for (i = j = 0; i < subst_rhs_len; i++) - { - if (subst_rhs[i] == '&') - { - if (j + subst_lhs_len >= new_size) - new = xrealloc (new, (new_size = new_size * 2 + subst_lhs_len)); - strcpy (new + j, subst_lhs); - j += subst_lhs_len; - } - else - { - /* a single backslash protects the `&' from lhs interpolation */ - if (subst_rhs[i] == '\\' && subst_rhs[i + 1] == '&') - i++; - if (j >= new_size) - new = xrealloc (new, new_size *= 2); - new[j++] = subst_rhs[i]; - } - } - new[j] = '\0'; - free (subst_rhs); - subst_rhs = new; - subst_rhs_len = j; -} - -/* Expand the bulk of a history specifier starting at STRING[START]. - Returns 0 if everything is OK, -1 if an error occurred, and 1 - if the `p' modifier was supplied and the caller should just print - the returned string. Returns the new index into string in - *END_INDEX_PTR, and the expanded specifier in *RET_STRING. */ -static int -history_expand_internal (string, start, end_index_ptr, ret_string, current_line) - char *string; - int start, *end_index_ptr; - char **ret_string; - char *current_line; /* for !# */ -{ - int i, n, starting_index; - int substitute_globally, want_quotes, print_only; - char *event, *temp, *result, *tstr, *t, c, *word_spec; - int result_len; - - result = xmalloc (result_len = 128); - - i = start; - - /* If it is followed by something that starts a word specifier, - then !! is implied as the event specifier. */ - - if (member (string[i + 1], ":$*%^")) - { - char fake_s[3]; - int fake_i = 0; - i++; - fake_s[0] = fake_s[1] = history_expansion_char; - fake_s[2] = '\0'; - event = get_history_event (fake_s, &fake_i, 0); - } - else if (string[i + 1] == '#') - { - i += 2; - event = current_line; - } - else - { - int quoted_search_delimiter = 0; - - /* If the character before this `!' is a double or single - quote, then this expansion takes place inside of the - quoted string. If we have to search for some text ("!foo"), - allow the delimiter to end the search string. */ - if (i && (string[i - 1] == '\'' || string[i - 1] == '"')) - quoted_search_delimiter = string[i - 1]; - event = get_history_event (string, &i, quoted_search_delimiter); - } - - if (!event) - { - *ret_string = hist_error (string, start, i, EVENT_NOT_FOUND); - free (result); - return (-1); - } - - /* If a word specifier is found, then do what that requires. */ - starting_index = i; - word_spec = get_history_word_specifier (string, event, &i); - - /* There is no such thing as a `malformed word specifier'. However, - it is possible for a specifier that has no match. In that case, - we complain. */ - if (word_spec == (char *)&error_pointer) - { - *ret_string = hist_error (string, starting_index, i, BAD_WORD_SPEC); - free (result); - return (-1); - } - - /* If no word specifier, than the thing of interest was the event. */ - if (!word_spec) - temp = savestring (event); - else - { - temp = savestring (word_spec); - free (word_spec); - } - - /* Perhaps there are other modifiers involved. Do what they say. */ - want_quotes = substitute_globally = print_only = 0; - starting_index = i; - - while (string[i] == ':') - { - c = string[i + 1]; - - if (c == 'g') - { - substitute_globally = 1; - i++; - c = string[i + 1]; - } - - switch (c) - { - default: - *ret_string = hist_error (string, i+1, i+2, BAD_MODIFIER); - free (result); - free (temp); - return -1; - -#if defined (SHELL) - case 'q': - want_quotes = 'q'; - break; - - case 'x': - want_quotes = 'x'; - break; -#endif /* SHELL */ - - /* :p means make this the last executed line. So we - return an error state after adding this line to the - history. */ - case 'p': - print_only++; - break; - - /* :t discards all but the last part of the pathname. */ - case 't': - tstr = strrchr (temp, '/'); - if (tstr) - { - tstr++; - t = savestring (tstr); - free (temp); - temp = t; - } - break; - - /* :h discards the last part of a pathname. */ - case 'h': - tstr = strrchr (temp, '/'); - if (tstr) - *tstr = '\0'; - break; - - /* :r discards the suffix. */ - case 'r': - tstr = strrchr (temp, '.'); - if (tstr) - *tstr = '\0'; - break; - - /* :e discards everything but the suffix. */ - case 'e': - tstr = strrchr (temp, '.'); - if (tstr) - { - t = savestring (tstr); - free (temp); - temp = t; - } - break; - - /* :s/this/that substitutes `that' for the first - occurrence of `this'. :gs/this/that substitutes `that' - for each occurrence of `this'. :& repeats the last - substitution. :g& repeats the last substitution - globally. */ - - case '&': - case 's': - { - char *new_event, *t; - int delimiter, failed, si, l_temp; - - if (c == 's') - { - if (i + 2 < (int)strlen (string)) - delimiter = string[i + 2]; - else - break; /* no search delimiter */ - - i += 3; - - t = get_subst_pattern (string, &i, delimiter, 0, &subst_lhs_len); - /* An empty substitution lhs with no previous substitution - uses the last search string as the lhs. */ - if (t) - { - if (subst_lhs) - free (subst_lhs); - subst_lhs = t; - } - else if (!subst_lhs) - { - if (search_string && *search_string) - { - subst_lhs = savestring (search_string); - subst_lhs_len = strlen (subst_lhs); - } - else - { - subst_lhs = (char *) NULL; - subst_lhs_len = 0; - } - } - - /* If there is no lhs, the substitution can't succeed. */ - if (subst_lhs_len == 0) - { - *ret_string = hist_error (string, starting_index, i, SUBST_FAILED); - free (result); - free (temp); - return -1; - } - - if (subst_rhs) - free (subst_rhs); - subst_rhs = get_subst_pattern (string, &i, delimiter, 1, &subst_rhs_len); - - /* If `&' appears in the rhs, it's supposed to be replaced - with the lhs. */ - if (member ('&', subst_rhs)) - postproc_subst_rhs (); - } - else - i += 2; - - l_temp = strlen (temp); - /* Ignore impossible cases. */ - if (subst_lhs_len > l_temp) - { - *ret_string = hist_error (string, starting_index, i, SUBST_FAILED); - free (result); - free (temp); - return (-1); - } - - /* Find the first occurrence of THIS in TEMP. */ - si = 0; - for (failed = 1; (si + subst_lhs_len) <= l_temp; si++) - if (STREQN (temp+si, subst_lhs, subst_lhs_len)) - { - int len = subst_rhs_len - subst_lhs_len + l_temp; - new_event = xmalloc (1 + len); - strncpy (new_event, temp, si); - strncpy (new_event + si, subst_rhs, subst_rhs_len); - strncpy (new_event + si + subst_rhs_len, - temp + si + subst_lhs_len, - l_temp - (si + subst_lhs_len)); - new_event[len] = '\0'; - free (temp); - temp = new_event; - - failed = 0; - - if (substitute_globally) - { - si += subst_rhs_len; - l_temp = strlen (temp); - substitute_globally++; - continue; - } - else - break; - } - - if (substitute_globally > 1) - { - substitute_globally = 0; - continue; /* don't want to increment i */ - } - - if (failed == 0) - continue; /* don't want to increment i */ - - *ret_string = hist_error (string, starting_index, i, SUBST_FAILED); - free (result); - free (temp); - return (-1); - } - } - i += 2; - } - /* Done with modfiers. */ - /* Believe it or not, we have to back the pointer up by one. */ - --i; - -#if defined (SHELL) - if (want_quotes) - { - char *x; - - if (want_quotes == 'q') - x = single_quote (temp); - else if (want_quotes == 'x') - x = quote_breaks (temp); - else - x = savestring (temp); - - free (temp); - temp = x; - } -#endif /* SHELL */ - - n = strlen (temp); - if (n > result_len) - result = xrealloc (result, n + 2); - strcpy (result, temp); - free (temp); - - *end_index_ptr = i; - *ret_string = result; - return (print_only); -} - -/* Expand the string STRING, placing the result into OUTPUT, a pointer - to a string. Returns: - - -1) If there was an error in expansion. - 0) If no expansions took place (or, if the only change in - the text was the de-slashifying of the history expansion - character) - 1) If expansions did take place - 2) If the `p' modifier was given and the caller should print the result - - If an error ocurred in expansion, then OUTPUT contains a descriptive - error message. */ - -#define ADD_STRING(s) \ - do \ - { \ - int sl = strlen (s); \ - j += sl; \ - if (j >= result_len) \ - { \ - while (j >= result_len) \ - result_len += 128; \ - result = xrealloc (result, result_len); \ - } \ - strcpy (result + j - sl, s); \ - } \ - while (0) - -#define ADD_CHAR(c) \ - do \ - { \ - if (j >= result_len - 1) \ - result = xrealloc (result, result_len += 64); \ - result[j++] = c; \ - result[j] = '\0'; \ - } \ - while (0) - -int -history_expand (hstring, output) - char *hstring; - char **output; -{ - register int j; - int i, r, l, passc, cc, modified, eindex, only_printing; - char *string; - - /* The output string, and its length. */ - int result_len; - char *result; - - /* Used when adding the string. */ - char *temp; - - /* Setting the history expansion character to 0 inhibits all - history expansion. */ - if (history_expansion_char == 0) - { - *output = savestring (hstring); - return (0); - } - - /* Prepare the buffer for printing error messages. */ - result = xmalloc (result_len = 256); - result[0] = '\0'; - - only_printing = modified = 0; - l = strlen (hstring); - - /* Grovel the string. Only backslash can quote the history escape - character. We also handle arg specifiers. */ - - /* Before we grovel forever, see if the history_expansion_char appears - anywhere within the text. */ - - /* The quick substitution character is a history expansion all right. That - is to say, "^this^that^" is equivalent to "!!:s^this^that^", and in fact, - that is the substitution that we do. */ - if (hstring[0] == history_subst_char) - { - string = xmalloc (l + 5); - - string[0] = string[1] = history_expansion_char; - string[2] = ':'; - string[3] = 's'; - strcpy (string + 4, hstring); - l += 4; - } - else - { - string = hstring; - /* If not quick substitution, still maybe have to do expansion. */ - - /* `!' followed by one of the characters in history_no_expand_chars - is NOT an expansion. */ - for (i = 0; string[i]; i++) - { - cc = string[i + 1]; - if (string[i] == history_expansion_char) - { - if (!cc || member (cc, history_no_expand_chars)) - continue; -#if defined (SHELL) - /* The shell uses ! as a pattern negation character - in globbing [...] expressions, so let those pass - without expansion. */ - else if (i > 0 && (string[i - 1] == '[') && - member (']', string + i + 1)) - continue; -#endif /* SHELL */ - else - break; - } -#if defined (SHELL) - else if (string[i] == '\'') - { - /* If this is bash, single quotes inhibit history expansion. */ - i++; - rl_string_extract_single_quoted (string, &i); - } - else if (string[i] == '\\') - { - /* If this is bash, allow backslashes to quote single - quotes and - the history expansion character. */ - if (cc == '\'' || cc == history_expansion_char) - i++; - } -#endif /* SHELL */ - } - - if (string[i] != history_expansion_char) - { - free (result); - *output = savestring (string); - return (0); - } - } - - /* Extract and perform the substitution. */ - for (passc = i = j = 0; i < l; i++) - { - int tchar = string[i]; - - if (passc) - { - passc = 0; - ADD_CHAR (tchar); - continue; - } - - if (tchar == history_expansion_char) - tchar = -3; - - switch (tchar) - { - default: - ADD_CHAR (string[i]); - break; - - case '\\': - passc++; - ADD_CHAR (tchar); - break; - -#if defined (SHELL) - case '\'': - { - /* If this is bash, single quotes inhibit history expansion. */ - int quote, slen; - - quote = i++; - rl_string_extract_single_quoted (string, &i); - - slen = i - quote + 2; - temp = xmalloc (slen); - strncpy (temp, string + quote, slen); - temp[slen - 1] = '\0'; - ADD_STRING (temp); - free (temp); - break; - } -#endif /* SHELL */ - - case -3: /* history_expansion_char */ - cc = string[i + 1]; - - /* If the history_expansion_char is followed by one of the - characters in history_no_expand_chars, then it is not a - candidate for expansion of any kind. */ - if (member (cc, history_no_expand_chars)) - { - ADD_CHAR (string[i]); - break; - } - -#if defined (NO_BANG_HASH_MODIFIERS) - /* There is something that is listed as a `word specifier' in csh - documentation which means `the expanded text to this point'. - That is not a word specifier, it is an event specifier. If we - don't want to allow modifiers with `!#', just stick the current - output line in again. */ - if (cc == '#') - { - if (result) - { - temp = xmalloc (1 + strlen (result)); - strcpy (temp, result); - ADD_STRING (temp); - free (temp); - } - i++; - break; - } -#endif - - r = history_expand_internal (string, i, &eindex, &temp, result); - if (r < 0) - { - *output = temp; - free (result); - if (string != hstring) - free (string); - return -1; - } - else - { - if (temp) - { - modified++; - if (*temp) - ADD_STRING (temp); - free (temp); - } - only_printing = r == 1; - i = eindex; - } - break; - } - } - - *output = result; - if (string != hstring) - free (string); - - if (only_printing) - { - add_history (result); - return (2); - } - - return (modified != 0); -} - -/* Return a consed string which is the word specified in SPEC, and found - in FROM. NULL is returned if there is no spec. The address of - ERROR_POINTER is returned if the word specified cannot be found. - CALLER_INDEX is the offset in SPEC to start looking; it is updated - to point to just after the last character parsed. */ -static char * -get_history_word_specifier (spec, from, caller_index) - char *spec, *from; - int *caller_index; -{ - register int i = *caller_index; - int first, last; - int expecting_word_spec = 0; - char *result; - - /* The range of words to return doesn't exist yet. */ - first = last = 0; - result = (char *)NULL; - - /* If we found a colon, then this *must* be a word specification. If - it isn't, then it is an error. */ - if (spec[i] == ':') - { - i++; - expecting_word_spec++; - } - - /* Handle special cases first. */ - - /* `%' is the word last searched for. */ - if (spec[i] == '%') - { - *caller_index = i + 1; - return (search_match ? savestring (search_match) : savestring ("")); - } - - /* `*' matches all of the arguments, but not the command. */ - if (spec[i] == '*') - { - *caller_index = i + 1; - result = history_arg_extract (1, '$', from); - return (result ? result : savestring ("")); - } - - /* `$' is last arg. */ - if (spec[i] == '$') - { - *caller_index = i + 1; - return (history_arg_extract ('$', '$', from)); - } - - /* Try to get FIRST and LAST figured out. */ - - if (spec[i] == '-') - first = 0; - else if (spec[i] == '^') - first = 1; - else if (digit_p (spec[i]) && expecting_word_spec) - { - for (first = 0; digit_p (spec[i]); i++) - first = (first * 10) + digit_value (spec[i]); - } - else - return ((char *)NULL); /* no valid `first' for word specifier */ - - if (spec[i] == '^' || spec[i] == '*') - { - last = (spec[i] == '^') ? 1 : '$'; /* x* abbreviates x-$ */ - i++; - } - else if (spec[i] != '-') - last = first; - else - { - i++; - - if (digit_p (spec[i])) - { - for (last = 0; digit_p (spec[i]); i++) - last = (last * 10) + digit_value (spec[i]); - } - else if (spec[i] == '$') - { - i++; - last = '$'; - } - else if (!spec[i] || spec[i] == ':') /* could be modifier separator */ - last = -1; /* x- abbreviates x-$ omitting word `$' */ - } - - *caller_index = i; - - if (last >= first || last == '$' || last < 0) - result = history_arg_extract (first, last, from); - - return (result ? result : (char *)&error_pointer); -} - -/* Extract the args specified, starting at FIRST, and ending at LAST. - The args are taken from STRING. If either FIRST or LAST is < 0, - then make that arg count from the right (subtract from the number of - tokens, so that FIRST = -1 means the next to last token on the line). - If LAST is `$' the last arg from STRING is used. */ -char * -history_arg_extract (first, last, string) - int first, last; - char *string; -{ - register int i, len; - char *result = (char *)NULL; - int size = 0, offset = 0; - char **list; - - /* XXX - think about making history_tokenize return a struct array, - each struct in array being a string and a length to avoid the - calls to strlen below. */ - if ((list = history_tokenize (string)) == NULL) - return ((char *)NULL); - - for (len = 0; list[len]; len++) - ; - - if (last < 0) - last = len + last - 1; - - if (first < 0) - first = len + first - 1; - - if (last == '$') - last = len - 1; - - if (first == '$') - first = len - 1; - - last++; - - if (first >= len || last > len || first < 0 || last < 0 || first > last) - result = ((char *)NULL); - else - { - for (size = 0, i = first; i < last; i++) - size += strlen (list[i]) + 1; - result = xmalloc (size + 1); - result[0] = '\0'; - - for (i = first; i < last; i++) - { - strcpy (result + offset, list[i]); - offset += strlen (list[i]); - if (i + 1 < last) - { - result[offset++] = ' '; - result[offset] = 0; - } - } - } - - for (i = 0; i < len; i++) - free (list[i]); - free (list); - - return (result); -} - -#define slashify_in_quotes "\\`\"$" - -/* Parse STRING into tokens and return an array of strings. If WIND is - not -1 and INDP is not null, we also want the word surrounding index - WIND. The position in the returned array of strings is returned in - *INDP. */ -static char ** -history_tokenize_internal (string, wind, indp) - char *string; - int wind, *indp; -{ - char **result = (char **)NULL; - register int i, start, result_index, size; - int len; - - i = result_index = size = 0; - - /* Get a token, and stuff it into RESULT. The tokens are split - exactly where the shell would split them. */ - while (string[i]) - { - int delimiter = 0; - - /* Skip leading whitespace. */ - for (; string[i] && whitespace (string[i]); i++) - ; - if (!string[i] || string[i] == history_comment_char) - return (result); - - start = i; - - if (member (string[i], "()\n")) - { - i++; - goto got_token; - } - - if (member (string[i], "<>;&|$")) - { - int peek = string[i + 1]; - - if (peek == string[i] && peek != '$') - { - if (peek == '<' && string[i + 2] == '-') - i++; - i += 2; - goto got_token; - } - else - { - if ((peek == '&' && (string[i] == '>' || string[i] == '<')) || - ((peek == '>') && (string[i] == '&')) || - ((peek == '(') && (string[i] == '$'))) - { - i += 2; - goto got_token; - } - } - if (string[i] != '$') - { - i++; - goto got_token; - } - } - - /* Get word from string + i; */ - - if (member (string[i], "\"'`")) - delimiter = string[i++]; - - for (; string[i]; i++) - { - if (string[i] == '\\' && string[i + 1] == '\n') - { - i++; - continue; - } - - if (string[i] == '\\' && delimiter != '\'' && - (delimiter != '"' || member (string[i], slashify_in_quotes))) - { - i++; - continue; - } - - if (delimiter && string[i] == delimiter) - { - delimiter = 0; - continue; - } - - if (!delimiter && (member (string[i], " \t\n;&()|<>"))) - break; - - if (!delimiter && member (string[i], "\"'`")) - delimiter = string[i]; - } - got_token: - - /* If we are looking for the word in which the character at a - particular index falls, remember it. */ - if (indp && wind >= 0 && wind >= start && wind < i) - *indp = result_index; - - len = i - start; - if (result_index + 2 >= size) - result = (char **)xrealloc (result, ((size += 10) * sizeof (char *))); - result[result_index] = xmalloc (1 + len); - strncpy (result[result_index], string + start, len); - result[result_index][len] = '\0'; - result[++result_index] = (char *)NULL; - } - - return (result); -} - -/* Return an array of tokens, much as the shell might. The tokens are - parsed out of STRING. */ -char ** -history_tokenize (string) - char *string; -{ - return (history_tokenize_internal (string, -1, (int *)NULL)); -} - -/* Find and return the word which contains the character at index IND - in the history line LINE. Used to save the word matched by the - last history !?string? search. */ -static char * -history_find_word (line, ind) - char *line; - int ind; -{ - char **words, *s; - int i, wind; - - words = history_tokenize_internal (line, ind, &wind); - if (wind == -1) - return ((char *)NULL); - s = words[wind]; - for (i = 0; i < wind; i++) - free (words[i]); - for (i = wind + 1; words[i]; i++) - free (words[i]); - free (words); - return s; -} - -#if defined (STATIC_MALLOC) - -/* **************************************************************** */ -/* */ -/* xmalloc and xrealloc () */ -/* */ -/* **************************************************************** */ - -static void memory_error_and_abort (); - -static char * -xmalloc (bytes) - int bytes; -{ - char *temp = (char *)malloc (bytes); - - if (!temp) - memory_error_and_abort (); - return (temp); -} - -static char * -xrealloc (pointer, bytes) - char *pointer; - int bytes; -{ - char *temp; - - if (!pointer) - temp = (char *)xmalloc (bytes); - else - temp = (char *)realloc (pointer, bytes); - - if (!temp) - memory_error_and_abort (); - - return (temp); -} - -static void -memory_error_and_abort () -{ - fprintf (stderr, "history: Out of virtual memory!\n"); - abort (); -} -#endif /* STATIC_MALLOC */ - -/* **************************************************************** */ -/* */ -/* Test Code */ -/* */ -/* **************************************************************** */ -#ifdef TEST -main () -{ - char line[1024], *t; - int done = 0; - - line[0] = 0; - - while (!done) - { - fprintf (stdout, "history%% "); - t = gets (line); - - if (!t) - strcpy (line, "quit"); - - if (line[0]) - { - char *expansion; - int result; - - using_history (); - - result = history_expand (line, &expansion); - strcpy (line, expansion); - free (expansion); - if (result) - fprintf (stderr, "%s\n", line); - - if (result < 0) - continue; - - add_history (line); - } - - if (strcmp (line, "quit") == 0) done = 1; - if (strcmp (line, "save") == 0) write_history (0); - if (strcmp (line, "read") == 0) read_history (0); - if (strcmp (line, "list") == 0) - { - register HIST_ENTRY **the_list = history_list (); - register int i; - - if (the_list) - for (i = 0; the_list[i]; i++) - fprintf (stdout, "%d: %s\n", i + history_base, the_list[i]->line); - } - if (strncmp (line, "delete", strlen ("delete")) == 0) - { - int which; - if ((sscanf (line + strlen ("delete"), "%d", &which)) == 1) - { - HIST_ENTRY *entry = remove_history (which); - if (!entry) - fprintf (stderr, "No such entry %d\n", which); - else - { - free (entry->line); - free (entry); - } - } - else - { - fprintf (stderr, "non-numeric arg given to `delete'\n"); - } - } - } -} - -#endif /* TEST */ - -/* -* Local variables: -* compile-command: "gcc -g -DTEST -o history history.c" -* end: -*/ diff --git a/lib/readline/history.h b/lib/readline/history.h index 6935efd..17ec877 100644 --- a/lib/readline/history.h +++ b/lib/readline/history.h @@ -1,4 +1,26 @@ /* History.h -- the names of functions that you can call in history. */ +/* Copyright (C) 1989, 1992 Free Software Foundation, Inc. + + This file contains the GNU History Library (the Library), a set of + routines for managing the text of previously typed lines. + + The 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 1, or (at your option) + any later version. + + The 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, + 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#ifndef _HISTORY_H_ +#define _HISTORY_H_ /* The structure used to store a history entry. */ typedef struct _hist_entry { @@ -46,6 +68,9 @@ extern HIST_ENTRY *remove_history (); invalid WHICH, a NULL pointer is returned. */ extern HIST_ENTRY *replace_history_entry (); +/* Clear the history list and start over. */ +extern void clear_history (); + /* Stifle the history list, remembering only MAX number of entries. */ extern void stifle_history (); @@ -179,3 +204,7 @@ extern char history_expansion_char; extern char history_subst_char; extern char history_comment_char; extern char *history_no_expand_chars; +extern char *history_search_delimiter_chars; +extern int history_quotes_inhibit_expansion; + +#endif /* !_HISTORY_H_ */ diff --git a/lib/readline/histsearch.c b/lib/readline/histsearch.c new file mode 100644 index 0000000..a72a68b --- /dev/null +++ b/lib/readline/histsearch.c @@ -0,0 +1,197 @@ +/* histsearch.c -- searching the history list. */ + +/* Copyright (C) 1989, 1992 Free Software Foundation, Inc. + + This file contains the GNU History Library (the Library), a set of + routines for managing the text of previously typed lines. + + The 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 1, or (at your option) + any later version. + + The 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, + 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#define READLINE_LIBRARY + +#if defined (HAVE_CONFIG_H) +# include +#endif + +#include +#if defined (HAVE_STDLIB_H) +# include +#else +# include "ansi_stdlib.h" +#endif /* HAVE_STDLIB_H */ +#if defined (HAVE_UNISTD_H) +# include +#endif +#if defined (HAVE_STRING_H) +# include +#else +# include +#endif /* !HAVE_STRING_H */ + +#include "history.h" +#include "histlib.h" + +/* Variables imported from other history library files. */ +extern int history_offset; + +/* The list of alternate characters that can delimit a history search + string. */ +char *history_search_delimiter_chars = (char *)NULL; + +/* Search the history for STRING, starting at history_offset. + If DIRECTION < 0, then the search is through previous entries, else + through subsequent. If ANCHORED is non-zero, the string must + appear at the beginning of a history line, otherwise, the string + may appear anywhere in the line. If the string is found, then + current_history () is the history entry, and the value of this + function is the offset in the line of that history entry that the + string was found in. Otherwise, nothing is changed, and a -1 is + returned. */ + +static int +history_search_internal (string, direction, anchored) + char *string; + int direction, anchored; +{ + register int i, reverse; + register char *line; + register int line_index; + int string_len; + HIST_ENTRY **the_history; /* local */ + + i = history_offset; + reverse = (direction < 0); + + /* Take care of trivial cases first. */ + if (string == 0 || *string == '\0') + return (-1); + + if (!history_length || ((i == history_length) && !reverse)) + return (-1); + + if (reverse && (i == history_length)) + i--; + +#define NEXT_LINE() do { if (reverse) i--; else i++; } while (0) + + the_history = history_list (); + string_len = strlen (string); + while (1) + { + /* Search each line in the history list for STRING. */ + + /* At limit for direction? */ + if ((reverse && i < 0) || (!reverse && i == history_length)) + return (-1); + + line = the_history[i]->line; + line_index = strlen (line); + + /* If STRING is longer than line, no match. */ + if (string_len > line_index) + { + NEXT_LINE (); + continue; + } + + /* Handle anchored searches first. */ + if (anchored == ANCHORED_SEARCH) + { + if (STREQN (string, line, string_len)) + { + history_offset = i; + return (0); + } + + NEXT_LINE (); + continue; + } + + /* Do substring search. */ + if (reverse) + { + line_index -= string_len; + + while (line_index >= 0) + { + if (STREQN (string, line + line_index, string_len)) + { + history_offset = i; + return (line_index); + } + line_index--; + } + } + else + { + register int limit; + + limit = line_index - string_len + 1; + line_index = 0; + + while (line_index < limit) + { + if (STREQN (string, line + line_index, string_len)) + { + history_offset = i; + return (line_index); + } + line_index++; + } + } + NEXT_LINE (); + } +} + +/* Do a non-anchored search for STRING through the history in DIRECTION. */ +int +history_search (string, direction) + char *string; + int direction; +{ + return (history_search_internal (string, direction, NON_ANCHORED_SEARCH)); +} + +/* Do an anchored search for string through the history in DIRECTION. */ +int +history_search_prefix (string, direction) + char *string; + int direction; +{ + return (history_search_internal (string, direction, ANCHORED_SEARCH)); +} + +/* Search for STRING in the history list. DIR is < 0 for searching + backwards. POS is an absolute index into the history list at + which point to begin searching. */ +int +history_search_pos (string, dir, pos) + char *string; + int dir, pos; +{ + int ret, old; + + old = where_history (); + history_set_pos (pos); + if (history_search (string, dir) == -1) + { + history_set_pos (old); + return (-1); + } + ret = where_history (); + history_set_pos (old); + return ret; +} diff --git a/lib/readline/input.c b/lib/readline/input.c new file mode 100644 index 0000000..7e3c0fe --- /dev/null +++ b/lib/readline/input.c @@ -0,0 +1,449 @@ +/* input.c -- character input functions for readline. */ + +/* Copyright (C) 1994 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, + 675 Mass Ave, Cambridge, MA 02139, USA. */ +#define READLINE_LIBRARY + +#if defined (HAVE_CONFIG_H) +# include +#endif + +#include +#include +#if defined (HAVE_SYS_FILE_H) +# include +#endif /* HAVE_SYS_FILE_H */ + +#if defined (HAVE_UNISTD_H) +# include +#endif /* HAVE_UNISTD_H */ + +#if defined (HAVE_STDLIB_H) +# include +#else +# include "ansi_stdlib.h" +#endif /* HAVE_STDLIB_H */ + +#if defined (HAVE_SELECT) +# if !defined (HAVE_SYS_SELECT_H) || !defined (M_UNIX) +# include +# endif +#endif /* HAVE_SELECT */ +#if defined (HAVE_SYS_SELECT_H) +# include +#endif + +#if defined (FIONREAD_IN_SYS_IOCTL) +# include +#endif + +#include +#include + +#if !defined (errno) +extern int errno; +#endif /* !errno */ + +/* System-specific feature definitions and include files. */ +#include "rldefs.h" + +/* Some standard library routines. */ +#include "readline.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 + +/* Functions imported from other files in the library. */ +extern char *xmalloc (), *xrealloc (); + +/* Variables and functions from macro.c. */ +extern void _rl_add_macro_char (); +extern void _rl_with_macro_input (); +extern int _rl_next_macro_key (); +extern int _rl_defining_kbd_macro; + +#if defined (VI_MODE) +extern void _rl_vi_set_last (); +extern int _rl_vi_textmod_command (); +#endif /* VI_MODE */ + +extern FILE *rl_instream, *rl_outstream; +extern Function *rl_last_func; +extern int rl_key_sequence_length; +extern int rl_pending_input; +extern int rl_editing_mode; + +extern Keymap _rl_keymap; + +extern int _rl_convert_meta_chars_to_ascii; + +#if defined (__GO32__) +# include +#endif /* __GO32__ */ + +/* Non-null means it is a pointer to a function to run while waiting for + character input. */ +Function *rl_event_hook = (Function *)NULL; + +Function *rl_getc_function = rl_getc; + +/* **************************************************************** */ +/* */ +/* 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; +} + +/* Add KEY to the buffer of characters to be read. */ +int +rl_stuff_char (key) + int key; +{ + if (key == EOF) + { + key = NEWLINE; + rl_pending_input = EOF; + } + ibuffer[push_index++] = key; + if (push_index >= ibuffer_len) + push_index = 0; + return push_index; +} + +/* Make C be the next command to be executed. */ +int +rl_execute_next (c) + int c; +{ + rl_pending_input = c; + return 0; +} + +/* 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); + 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. */ +static 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); +} + +/* If a character is available to be read, then read it + and stuff it into IBUFFER. Otherwise, just return. */ +static void +rl_gather_tyi () +{ +#if defined (__GO32__) + char input; + + if (isatty (0) && kbhit () && ibuffer_space ()) + { + int i; + i = (*rl_getc_function) (rl_instream); + rl_stuff_char (i); + } +#else /* !__GO32__ */ + + int tty; + register int tem, result; + int chars_avail; + 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 = 100000; /* 0.1 seconds */ + if (select (tty + 1, &readfds, (fd_set *)NULL, &exceptfds, &timeout) <= 0) + return; /* Nothing to read. */ +#endif + + result = -1; +#if defined (FIONREAD) + result = ioctl (tty, FIONREAD, &chars_avail); +#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; + } +#endif /* O_NDELAY */ + + /* If there's nothing available, don't waste time trying to read + something. */ + if (chars_avail <= 0) + return; + + 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--) + rl_stuff_char ((*rl_getc_function) (rl_instream)); + } + else + { + if (chars_avail) + rl_stuff_char (input); + } +#endif /* !__GO32__ */ +} + +/* Is there input available to be read on the readline input file + descriptor? Only works if the system has select(2) or FIONREAD. */ +int +_rl_input_available () +{ +#if defined(HAVE_SELECT) + fd_set readfds, exceptfds; + struct timeval timeout; +#endif +#if 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 = 100000; /* 0.1 seconds */ + return (select (tty + 1, &readfds, (fd_set *)NULL, &exceptfds, &timeout) > 0); +#endif + +#if defined (FIONREAD) + if (ioctl (tty, FIONREAD, &chars_avail) == 0) + return (chars_avail); +#endif + + return 0; +} + +void +_rl_insert_typein (c) + int c; +{ + int key, t, i; + char *string; + + i = key = 0; + string = 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); +} + +/* **************************************************************** */ +/* */ +/* 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_pending_input = 0; + } + 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) (); + rl_gather_tyi (); + } + } + else + { + if (rl_get_char (&c) == 0) + c = (*rl_getc_function) (rl_instream); + } + } + + return (c); +} + +int +rl_getc (stream) + FILE *stream; +{ + int result, flags; + unsigned char c; + +#if defined (__GO32__) + if (isatty (0)) + return (getkey () & 0x7F); +#endif /* __GO32__ */ + + while (1) + { + 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 (EWOULDBLOCK) + if (errno == EWOULDBLOCK) + { + if ((flags = fcntl (fileno (stream), F_GETFL, 0)) < 0) + return (EOF); + if (flags & O_NDELAY) + { + flags &= ~O_NDELAY; + fcntl (fileno (stream), F_SETFL, flags); + continue; + } + continue; + } +#endif /* EWOULDBLOCK */ + +#if defined (_POSIX_VERSION) && defined (EAGAIN) && defined (O_NONBLOCK) + if (errno == EAGAIN) + { + if ((flags = fcntl (fileno (stream), F_GETFL, 0)) < 0) + return (EOF); + if (flags & O_NONBLOCK) + { + flags &= ~O_NONBLOCK; + fcntl (fileno (stream), F_SETFL, flags); + continue; + } + } +#endif /* _POSIX_VERSION && EAGAIN && O_NONBLOCK */ + +#if !defined (__GO32__) + /* 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); +#endif /* !__GO32__ */ + } +} diff --git a/lib/readline/isearch.c b/lib/readline/isearch.c index 1a0193f..fa60fa4 100644 --- a/lib/readline/isearch.c +++ b/lib/readline/isearch.c @@ -26,19 +26,22 @@ 675 Mass Ave, Cambridge, MA 02139, USA. */ #define READLINE_LIBRARY +#if defined (HAVE_CONFIG_H) +# include +#endif + #include #if defined (HAVE_UNISTD_H) # include #endif -#include "memalloc.h" +#include + +#include "rldefs.h" #include "readline.h" #include "history.h" -#define STREQ(a, b) (((a)[0] == (b)[0]) && (strcmp ((a), (b)) == 0)) -#define STREQN(a, b, n) (((a)[0] == (b)[0]) && (strncmp ((a), (b), (n)) == 0)) - /* Variables imported from other files in the readline library. */ extern Keymap _rl_keymap; extern HIST_ENTRY *saved_line_for_history; @@ -46,6 +49,14 @@ extern int rl_line_buffer_len; extern int rl_point, rl_end; extern char *rl_line_buffer; +extern void _rl_save_prompt (); +extern void _rl_restore_prompt (); + +extern int rl_execute_next (); +extern void rl_extend_line_buffer (); + +extern int _rl_input_available (); + extern char *xmalloc (), *xrealloc (); static int rl_search_history (); @@ -56,18 +67,18 @@ static char *prev_line_found; /* Search backwards through the history looking for a string which is typed interactively. Start with the current line. */ +int rl_reverse_search_history (sign, key) - int sign; - int key; + int sign, key; { return (rl_search_history (-sign, key)); } /* Search forwards through the history looking for a string which is typed interactively. Start with the current line. */ +int rl_forward_search_history (sign, key) - int sign; - int key; + int sign, key; { return (rl_search_history (sign, key)); } @@ -83,29 +94,43 @@ rl_display_search (search_string, reverse_p, where) int reverse_p, where; { char *message; + int msglen, searchlen; + + searchlen = (search_string && *search_string) ? strlen (search_string) : 0; - message = xmalloc (1 + (search_string ? strlen (search_string) : 0) + 30); - *message = '\0'; + message = xmalloc (searchlen + 33); + msglen = 0; #if defined (NOTDEF) if (where != -1) - sprintf (message, "[%d]", where + history_base); + { + sprintf (message, "[%d]", where + history_base); + msglen = strlen (message); + } #endif /* NOTDEF */ - strcat (message, "("); + message[msglen++] = '('; if (reverse_p) - strcat (message, "reverse-"); + { + strcpy (message + msglen, "reverse-"); + msglen += 8; + } - strcat (message, "i-search)`"); + strcpy (message + msglen, "i-search)`"); + msglen += 10; if (search_string) - strcat (message, search_string); + { + strcpy (message + msglen, search_string); + msglen += searchlen; + } + + strcpy (message + msglen, "': "); - strcat (message, "': "); rl_message ("%s", message, 0); free (message); - rl_redisplay (); + (*rl_redisplay_function) (); } /* Search through the history looking for an interactively typed string. @@ -114,8 +139,7 @@ rl_display_search (search_string, reverse_p, where) backwards. */ static int rl_search_history (direction, invoking_key) - int direction; - int invoking_key; + int direction, invoking_key; { /* The string that the user types in to search for. */ char *search_string; @@ -127,19 +151,17 @@ rl_search_history (direction, invoking_key) int search_string_size; /* The list of lines to search through. */ - char **lines, *allocated_line = (char *)NULL; + char **lines, *allocated_line; /* The length of LINES. */ int hlen; /* Where we get LINES from. */ - HIST_ENTRY **hlist = history_list (); + HIST_ENTRY **hlist; - register int i = 0; - int orig_point = rl_point; - int orig_line = where_history (); - int last_found_line = orig_line; - int c, done = 0, found, failed, sline_len; + register int i; + int orig_point, orig_line, last_found_line; + int c, found, failed, sline_len; /* The line currently being searched. */ char *sline; @@ -148,10 +170,17 @@ rl_search_history (direction, invoking_key) int line_index; /* Non-zero if we are doing a reverse search. */ - int reverse = (direction < 0); + int reverse; + + orig_point = rl_point; + last_found_line = orig_line = where_history (); + reverse = direction < 0; + hlist = history_list (); + allocated_line = (char *)NULL; /* Create an arrary of pointers to the lines that we want to search. */ maybe_replace_line (); + i = 0; if (hlist) for (i = 0; hlist[i]; i++); @@ -176,6 +205,8 @@ rl_search_history (direction, invoking_key) /* The line where we start the search. */ i = orig_line; + _rl_save_prompt (); + /* Initialize search parameters. */ search_string = xmalloc (search_string_size = 128); *search_string = '\0'; @@ -192,14 +223,13 @@ rl_search_history (direction, invoking_key) line_index = rl_point; found = failed = 0; - while (!done) + for (;;) { Function *f = (Function *)NULL; /* Read a key and decide how to proceed. */ c = rl_read_key (); - /* Hack C to Do What I Mean. */ if (_rl_keymap[c].type == ISFUNC) { f = _rl_keymap[c].function; @@ -210,78 +240,81 @@ rl_search_history (direction, invoking_key) c = !reverse ? -1 : -2; } - switch (c) + /* Let NEWLINE (^J) terminate the search for people who don't like + using ESC. ^M can still be used to terminate the search and + immediately execute the command. */ + if (c == ESC || c == NEWLINE) + { + /* ESC still terminates the search, but if there is pending + input or if input arrives within 0.1 seconds (on systems + with select(2)) it is used as a prefix character + with rl_execute_next. WATCH OUT FOR THIS! This is intended + to allow the arrow keys to be used like ^F and ^B are used + to terminate the search and execute the movement command. */ + if (c == ESC && _rl_input_available ()) /* XXX */ + rl_execute_next (ESC); + break; + } + + if (c >= 0 && (CTRL_CHAR (c) || META_CHAR (c) || c == RUBOUT)) { - case ESC: - done = 1; - continue; + rl_execute_next (c); + break; + } + switch (c) + { case -1: - if (!search_string_index) + if (search_string_index == 0) continue; + else if (reverse) + --line_index; + else if (line_index != sline_len) + ++line_index; else - { - if (reverse) - --line_index; - else - { - if (line_index != sline_len) - ++line_index; - else - ding (); - } - } + ding (); break; /* switch directions */ case -2: direction = -direction; - reverse = (direction < 0); + reverse = direction < 0; break; case CTRL ('G'): strcpy (rl_line_buffer, lines[orig_line]); rl_point = orig_point; rl_end = strlen (rl_line_buffer); + _rl_restore_prompt(); rl_clear_message (); free (allocated_line); free (lines); return 0; default: - if (CTRL_CHAR (c) || META_CHAR (c) || c == RUBOUT) + /* Add character to search string and continue search. */ + if (search_string_index + 2 >= search_string_size) { - rl_execute_next (c); - done = 1; - continue; - } - else - { - /* Add character to search string and continue search. */ - if (search_string_index + 2 >= search_string_size) - { - search_string_size += 128; - search_string = xrealloc (search_string, search_string_size); - } - search_string[search_string_index++] = c; - search_string[search_string_index] = '\0'; - break; + search_string_size += 128; + search_string = xrealloc (search_string, search_string_size); } + search_string[search_string_index++] = c; + search_string[search_string_index] = '\0'; + break; } - found = failed = 0; - while (1) + for (found = failed = 0;;) { int limit = sline_len - search_string_index + 1; /* Search the current line. */ while (reverse ? (line_index >= 0) : (line_index < limit)) { - if (STREQN(search_string, sline + line_index, search_string_index)) - { - found++; - break; - } + if (STREQN (search_string, sline + line_index, search_string_index)) + { + found++; + break; + } else line_index += direction; } @@ -314,10 +347,7 @@ rl_search_history (direction, invoking_key) break; /* Now set up the line for searching... */ - if (reverse) - line_index = sline_len - search_string_index; - else - line_index = 0; + line_index = reverse ? sline_len - search_string_index : 0; } if (failed) @@ -357,6 +387,8 @@ rl_search_history (direction, invoking_key) /* First put back the original state. */ strcpy (rl_line_buffer, lines[orig_line]); + _rl_restore_prompt (); + /* Free the search string. */ free (search_string); diff --git a/lib/readline/keymaps.c b/lib/readline/keymaps.c index e1be552..9359749 100644 --- a/lib/readline/keymaps.c +++ b/lib/readline/keymaps.c @@ -21,7 +21,7 @@ #define READLINE_LIBRARY #if defined (HAVE_CONFIG_H) -# include "config.h" +# include #endif #if defined (HAVE_STDLIB_H) @@ -41,11 +41,7 @@ extern int rl_do_lowercase_version (); extern int rl_rubout (), rl_insert (); -#if defined (STATIC_MALLOC) -static char *xmalloc (), *xrealloc (); -#else extern char *xmalloc (), *xrealloc (); -#endif /* STATIC_MALLOC */ /* **************************************************************** */ /* */ @@ -109,7 +105,7 @@ rl_make_keymap () newmap[i].function = rl_insert; newmap[TAB].function = rl_insert; - newmap[RUBOUT].function = rl_rubout; + newmap[RUBOUT].function = rl_rubout; /* RUBOUT == 127 */ newmap[CTRL('H')].function = rl_rubout; #if KEYMAP_SIZE > 128 @@ -152,49 +148,3 @@ rl_discard_keymap (map) } } } - -#if defined (STATIC_MALLOC) - -/* **************************************************************** */ -/* */ -/* xmalloc and xrealloc () */ -/* */ -/* **************************************************************** */ - -static void memory_error_and_abort (); - -static char * -xmalloc (bytes) - int bytes; -{ - char *temp = (char *)malloc (bytes); - - if (!temp) - memory_error_and_abort (); - return (temp); -} - -static char * -xrealloc (pointer, bytes) - char *pointer; - int bytes; -{ - char *temp; - - if (!pointer) - temp = (char *)malloc (bytes); - else - temp = (char *)realloc (pointer, bytes); - - if (!temp) - memory_error_and_abort (); - return (temp); -} - -static void -memory_error_and_abort () -{ - fprintf (stderr, "readline: Out of virtual memory!\n"); - abort (); -} -#endif /* STATIC_MALLOC */ diff --git a/lib/readline/keymaps.h b/lib/readline/keymaps.h index f0eda3d..f8d0e2e 100644 --- a/lib/readline/keymaps.h +++ b/lib/readline/keymaps.h @@ -29,8 +29,8 @@ # include #endif -#if !defined (__FUNCTION_DEF) -# define __FUNCTION_DEF +#if !defined (_FUNCTION_DEF) +# define _FUNCTION_DEF typedef int Function (); typedef void VFunction (); typedef char *CPFunction (); diff --git a/lib/readline/kill.c b/lib/readline/kill.c new file mode 100644 index 0000000..89f6b55 --- /dev/null +++ b/lib/readline/kill.c @@ -0,0 +1,547 @@ +/* kill.c -- kill ring management. */ + +/* Copyright (C) 1994 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 1, 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, + 675 Mass Ave, Cambridge, MA 02139, USA. */ +#define READLINE_LIBRARY + +#if defined (HAVE_CONFIG_H) +# include +#endif + +#include + +#if defined (HAVE_UNISTD_H) +# include /* for _POSIX_VERSION */ +#endif /* HAVE_UNISTD_H */ + +#if defined (HAVE_STDLIB_H) +# include +#else +# include "ansi_stdlib.h" +#endif /* HAVE_STDLIB_H */ + +#include + +/* System-specific feature definitions and include files. */ +#include "rldefs.h" + +/* Some standard library routines. */ +#include "readline.h" +#include "history.h" + +extern int _rl_last_command_was_kill; +extern int rl_editing_mode; +extern int rl_explicit_arg; +extern Function *rl_last_func; + +extern void _rl_init_argument (); +extern int _rl_set_mark_at_pos (); +extern void _rl_abort_internal (); + +extern char *xmalloc (), *xrealloc (); + +/* **************************************************************** */ +/* */ +/* Killing Mechanism */ +/* */ +/* **************************************************************** */ + +/* What we assume for a max number of kills. */ +#define DEFAULT_MAX_KILLS 10 + +/* The real variable to look at to find out when to flush kills. */ +static int rl_max_kills = DEFAULT_MAX_KILLS; + +/* Where to store killed text. */ +static char **rl_kill_ring = (char **)NULL; + +/* Where we are in the kill ring. */ +static int rl_kill_index; + +/* How many slots we have in the kill ring. */ +static int rl_kill_ring_length; + +/* How to say that you only want to save a certain amount + of kill material. */ +int +rl_set_retained_kills (num) + int num; +{ + return 0; +} + +/* Add TEXT to the kill ring, allocating a new kill ring slot as necessary. + This uses TEXT directly, so the caller must not free it. If APPEND is + non-zero, and the last command was a kill, the text is appended to the + current kill ring slot, otherwise prepended. */ +static int +_rl_copy_to_kill_ring (text, append) + char *text; + int append; +{ + char *old, *new; + int slot; + + /* First, find the slot to work with. */ + if (_rl_last_command_was_kill == 0) + { + /* Get a new slot. */ + if (rl_kill_ring == 0) + { + /* If we don't have any defined, then make one. */ + rl_kill_ring = (char **) + xmalloc (((rl_kill_ring_length = 1) + 1) * sizeof (char *)); + rl_kill_ring[slot = 0] = (char *)NULL; + } + else + { + /* We have to add a new slot on the end, unless we have + exceeded the max limit for remembering kills. */ + slot = rl_kill_ring_length; + if (slot == rl_max_kills) + { + register int i; + free (rl_kill_ring[0]); + for (i = 0; i < slot; i++) + rl_kill_ring[i] = rl_kill_ring[i + 1]; + } + else + { + slot = rl_kill_ring_length += 1; + rl_kill_ring = (char **)xrealloc (rl_kill_ring, slot * sizeof (char *)); + } + rl_kill_ring[--slot] = (char *)NULL; + } + } + else + slot = rl_kill_ring_length - 1; + + /* If the last command was a kill, prepend or append. */ + if (_rl_last_command_was_kill && rl_editing_mode != vi_mode) + { + old = rl_kill_ring[slot]; + new = xmalloc (1 + strlen (old) + strlen (text)); + + if (append) + { + strcpy (new, old); + strcat (new, text); + } + else + { + strcpy (new, text); + strcat (new, old); + } + free (old); + free (text); + rl_kill_ring[slot] = new; + } + else + rl_kill_ring[slot] = text; + + rl_kill_index = slot; + return 0; +} + +/* The way to kill something. This appends or prepends to the last + kill, if the last command was a kill command. if FROM is less + than TO, then the text is appended, otherwise prepended. If the + last command was not a kill command, then a new slot is made for + this kill. */ +int +rl_kill_text (from, to) + int from, to; +{ + char *text; + + /* Is there anything to kill? */ + if (from == to) + { + _rl_last_command_was_kill++; + return 0; + } + + text = rl_copy_text (from, to); + + /* Delete the copied text from the line. */ + rl_delete_text (from, to); + + _rl_copy_to_kill_ring (text, from < to); + + _rl_last_command_was_kill++; + return 0; +} + +/* Now REMEMBER! In order to do prepending or appending correctly, kill + commands always make rl_point's original position be the FROM argument, + and rl_point's extent be the TO argument. */ + +/* **************************************************************** */ +/* */ +/* Killing Commands */ +/* */ +/* **************************************************************** */ + +/* Delete the word at point, saving the text in the kill ring. */ +int +rl_kill_word (count, key) + int count, key; +{ + int orig_point = rl_point; + + if (count < 0) + return (rl_backward_kill_word (-count, key)); + else + { + rl_forward_word (count, key); + + if (rl_point != orig_point) + rl_kill_text (orig_point, rl_point); + + rl_point = orig_point; + } + return 0; +} + +/* Rubout the word before point, placing it on the kill ring. */ +int +rl_backward_kill_word (count, ignore) + int count, ignore; +{ + int orig_point = rl_point; + + if (count < 0) + return (rl_kill_word (-count, ignore)); + else + { + rl_backward_word (count, ignore); + + if (rl_point != orig_point) + rl_kill_text (orig_point, rl_point); + } + return 0; +} + +/* Kill from here to the end of the line. If DIRECTION is negative, kill + back to the line start instead. */ +int +rl_kill_line (direction, ignore) + int direction, ignore; +{ + int orig_point = rl_point; + + if (direction < 0) + return (rl_backward_kill_line (1, ignore)); + else + { + rl_end_of_line (1, ignore); + if (orig_point != rl_point) + rl_kill_text (orig_point, rl_point); + rl_point = orig_point; + } + return 0; +} + +/* Kill backwards to the start of the line. If DIRECTION is negative, kill + forwards to the line end instead. */ +int +rl_backward_kill_line (direction, ignore) + int direction, ignore; +{ + int orig_point = rl_point; + + if (direction < 0) + return (rl_kill_line (1, ignore)); + else + { + if (!rl_point) + ding (); + else + { + rl_beg_of_line (1, ignore); + rl_kill_text (orig_point, rl_point); + } + } + return 0; +} + +/* Kill the whole line, no matter where point is. */ +int +rl_kill_full_line (count, ignore) + int count, ignore; +{ + rl_begin_undo_group (); + rl_point = 0; + rl_kill_text (rl_point, rl_end); + rl_end_undo_group (); + return 0; +} + +/* The next two functions mimic unix line editing behaviour, except they + save the deleted text on the kill ring. This is safer than not saving + it, and since we have a ring, nobody should get screwed. */ + +/* This does what C-w does in Unix. We can't prevent people from + using behaviour that they expect. */ +int +rl_unix_word_rubout (count, key) + int count, key; +{ + int orig_point; + + if (rl_point == 0) + ding (); + else + { + orig_point = rl_point; + if (count <= 0) + count = 1; + + while (count--) + { + while (rl_point && whitespace (rl_line_buffer[rl_point - 1])) + rl_point--; + + while (rl_point && (whitespace (rl_line_buffer[rl_point - 1]) == 0)) + rl_point--; + } + + rl_kill_text (orig_point, rl_point); + } + return 0; +} + +/* Here is C-u doing what Unix does. You don't *have* to use these + key-bindings. We have a choice of killing the entire line, or + killing from where we are to the start of the line. We choose the + latter, because if you are a Unix weenie, then you haven't backspaced + into the line at all, and if you aren't, then you know what you are + doing. */ +int +rl_unix_line_discard (count, key) + int count, key; +{ + if (rl_point == 0) + ding (); + else + { + rl_kill_text (rl_point, 0); + rl_point = 0; + } + return 0; +} + +/* Copy the text in the `region' to the kill ring. If DELETE is non-zero, + delete the text from the line as well. */ +static int +region_kill_internal (delete) + int delete; +{ + char *text; + + if (rl_mark == rl_point) + { + _rl_last_command_was_kill++; + return 0; + } + + text = rl_copy_text (rl_point, rl_mark); + if (delete) + rl_delete_text (rl_point, rl_mark); + _rl_copy_to_kill_ring (text, rl_point < rl_mark); + + _rl_last_command_was_kill++; + return 0; +} + +/* Copy the text in the region to the kill ring. */ +int +rl_copy_region_to_kill (count, ignore) + int count, ignore; +{ + return (region_kill_internal (0)); +} + +/* Kill the text between the point and mark. */ +int +rl_kill_region (count, ignore) + int count, ignore; +{ + return (region_kill_internal (1)); +} + +/* Copy COUNT words to the kill ring. DIR says which direction we look + to find the words. */ +static int +_rl_copy_word_as_kill (count, dir) + int count, dir; +{ + int om, op, r; + + om = rl_mark; + op = rl_point; + + if (dir > 0) + rl_forward_word (count, 0); + else + rl_backward_word (count, 0); + + rl_mark = rl_point; + + if (dir > 0) + rl_backward_word (count, 0); + else + rl_forward_word (count, 0); + + r = region_kill_internal (0); + + rl_mark = om; + rl_point = op; + + return r; +} + +int +rl_copy_forward_word (count, key) + int count, key; +{ + if (count < 0) + return (rl_copy_backward_word (-count, key)); + + return (_rl_copy_word_as_kill (count, 1)); +} + +int +rl_copy_backward_word (count, key) + int count, key; +{ + if (count < 0) + return (rl_copy_forward_word (-count, key)); + + return (_rl_copy_word_as_kill (count, -1)); +} + +/* Yank back the last killed text. This ignores arguments. */ +int +rl_yank (count, ignore) + int count, ignore; +{ + if (rl_kill_ring == 0) + { + _rl_abort_internal (); + return -1; + } + + _rl_set_mark_at_pos (rl_point); + rl_insert_text (rl_kill_ring[rl_kill_index]); + return 0; +} + +/* If the last command was yank, or yank_pop, and the text just + before point is identical to the current kill item, then + delete that text from the line, rotate the index down, and + yank back some other text. */ +int +rl_yank_pop (count, key) + int count, key; +{ + int l, n; + + if (((rl_last_func != rl_yank_pop) && (rl_last_func != rl_yank)) || + !rl_kill_ring) + { + _rl_abort_internal (); + return -1; + } + + l = strlen (rl_kill_ring[rl_kill_index]); + n = rl_point - l; + if (n >= 0 && STREQN (rl_line_buffer + n, rl_kill_ring[rl_kill_index], l)) + { + rl_delete_text (n, rl_point); + rl_point = n; + rl_kill_index--; + if (rl_kill_index < 0) + rl_kill_index = rl_kill_ring_length - 1; + rl_yank (1, 0); + return 0; + } + else + { + _rl_abort_internal (); + return -1; + } +} + +/* Yank the COUNTth argument from the previous history line. */ +int +rl_yank_nth_arg (count, ignore) + int count, ignore; +{ + register HIST_ENTRY *entry; + char *arg; + + entry = previous_history (); + if (entry) + next_history (); + else + { + ding (); + return -1; + } + + arg = history_arg_extract (count, count, entry->line); + if (!arg || !*arg) + { + ding (); + return -1; + } + + rl_begin_undo_group (); + +#if defined (VI_MODE) + /* Vi mode always inserts a space before yanking the argument, and it + inserts it right *after* rl_point. */ + if (rl_editing_mode == vi_mode) + { + rl_vi_append_mode (); + rl_insert_text (" "); + } +#endif /* VI_MODE */ + + rl_insert_text (arg); + free (arg); + + rl_end_undo_group (); + return 0; +} + +/* Yank the last argument from the previous history line. This `knows' + how rl_yank_nth_arg treats a count of `$'. With an argument, this + behaves the same as rl_yank_nth_arg. */ +int +rl_yank_last_arg (count, key) + int count, key; +{ + if (rl_explicit_arg) + return (rl_yank_nth_arg (count, key)); + else + return (rl_yank_nth_arg ('$', key)); +} diff --git a/lib/readline/macro.c b/lib/readline/macro.c new file mode 100644 index 0000000..f3c442b --- /dev/null +++ b/lib/readline/macro.c @@ -0,0 +1,277 @@ +/* macro.c -- keyboard macros for readline. */ + +/* Copyright (C) 1994 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 1, 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, + 675 Mass Ave, Cambridge, MA 02139, USA. */ +#define READLINE_LIBRARY + +#if defined (HAVE_CONFIG_H) +# include +#endif + +#include + +#if defined (HAVE_UNISTD_H) +# include /* for _POSIX_VERSION */ +#endif /* HAVE_UNISTD_H */ + +#if defined (HAVE_STDLIB_H) +# include +#else +# include "ansi_stdlib.h" +#endif /* HAVE_STDLIB_H */ + +#include + +/* System-specific feature definitions and include files. */ +#include "rldefs.h" + +/* Some standard library routines. */ +#include "readline.h" +#include "history.h" + +#define SWAP(s, e) do { int t; t = s; s = e; e = t; } while (0) + +/* Forward definitions. */ +void _rl_push_executing_macro (), _rl_pop_executing_macro (); +void _rl_add_macro_char (); + +/* Extern declarations. */ +extern int rl_explicit_arg; +extern int rl_key_sequence_length; + +extern void _rl_abort_internal (); + +extern char *xmalloc (), *xrealloc (); + +/* **************************************************************** */ +/* */ +/* Hacking Keyboard Macros */ +/* */ +/* **************************************************************** */ + +/* Non-zero means to save keys that we dispatch on in a kbd macro. */ +int _rl_defining_kbd_macro = 0; + +/* The currently executing macro string. If this is non-zero, + then it is a malloc ()'ed string where input is coming from. */ +char *_rl_executing_macro = (char *)NULL; + +/* The offset in the above string to the next character to be read. */ +static int executing_macro_index; + +/* The current macro string being built. Characters get stuffed + in here by add_macro_char (). */ +static char *current_macro = (char *)NULL; + +/* The size of the buffer allocated to current_macro. */ +static int current_macro_size; + +/* The index at which characters are being added to current_macro. */ +static int current_macro_index; + +/* A structure used to save nested macro strings. + It is a linked list of string/index for each saved macro. */ +struct saved_macro { + struct saved_macro *next; + char *string; + int sindex; +}; + +/* The list of saved macros. */ +static struct saved_macro *macro_list = (struct saved_macro *)NULL; + +/* Set up to read subsequent input from STRING. + STRING is free ()'ed when we are done with it. */ +void +_rl_with_macro_input (string) + char *string; +{ + _rl_push_executing_macro (); + _rl_executing_macro = string; + executing_macro_index = 0; +} + +/* Return the next character available from a macro, or 0 if + there are no macro characters. */ +int +_rl_next_macro_key () +{ + if (_rl_executing_macro == 0) + return (0); + + if (_rl_executing_macro[executing_macro_index] == 0) + { + _rl_pop_executing_macro (); + return (_rl_next_macro_key ()); + } + + return (_rl_executing_macro[executing_macro_index++]); +} + +/* Save the currently executing macro on a stack of saved macros. */ +void +_rl_push_executing_macro () +{ + struct saved_macro *saver; + + saver = (struct saved_macro *)xmalloc (sizeof (struct saved_macro)); + saver->next = macro_list; + saver->sindex = executing_macro_index; + saver->string = _rl_executing_macro; + + macro_list = saver; +} + +/* Discard the current macro, replacing it with the one + on the top of the stack of saved macros. */ +void +_rl_pop_executing_macro () +{ + struct saved_macro *macro; + + if (_rl_executing_macro) + free (_rl_executing_macro); + + _rl_executing_macro = (char *)NULL; + executing_macro_index = 0; + + if (macro_list) + { + macro = macro_list; + _rl_executing_macro = macro_list->string; + executing_macro_index = macro_list->sindex; + macro_list = macro_list->next; + free (macro); + } +} + +/* Add a character to the macro being built. */ +void +_rl_add_macro_char (c) + int c; +{ + if (current_macro_index + 1 >= current_macro_size) + { + if (current_macro == 0) + current_macro = xmalloc (current_macro_size = 25); + else + current_macro = xrealloc (current_macro, current_macro_size += 25); + } + + current_macro[current_macro_index++] = c; + current_macro[current_macro_index] = '\0'; +} + +void +_rl_kill_kbd_macro () +{ + if (current_macro) + { + free (current_macro); + current_macro = (char *) NULL; + } + current_macro_size = current_macro_index = 0; + + if (_rl_executing_macro) + { + free (_rl_executing_macro); + _rl_executing_macro = (char *) NULL; + } + executing_macro_index = 0; + + _rl_defining_kbd_macro = 0; +} + +/* Begin defining a keyboard macro. + Keystrokes are recorded as they are executed. + End the definition with rl_end_kbd_macro (). + If a numeric argument was explicitly typed, then append this + definition to the end of the existing macro, and start by + re-executing the existing macro. */ +int +rl_start_kbd_macro (ignore1, ignore2) + int ignore1, ignore2; +{ + if (_rl_defining_kbd_macro) + { + _rl_abort_internal (); + return -1; + } + + if (rl_explicit_arg) + { + if (current_macro) + _rl_with_macro_input (savestring (current_macro)); + } + else + current_macro_index = 0; + + _rl_defining_kbd_macro = 1; + return 0; +} + +/* Stop defining a keyboard macro. + A numeric argument says to execute the macro right now, + that many times, counting the definition as the first time. */ +int +rl_end_kbd_macro (count, ignore) + int count, ignore; +{ + if (_rl_defining_kbd_macro == 0) + { + _rl_abort_internal (); + return -1; + } + + current_macro_index -= rl_key_sequence_length - 1; + current_macro[current_macro_index] = '\0'; + + _rl_defining_kbd_macro = 0; + + return (rl_call_last_kbd_macro (--count, 0)); +} + +/* Execute the most recently defined keyboard macro. + COUNT says how many times to execute it. */ +int +rl_call_last_kbd_macro (count, ignore) + int count, ignore; +{ + if (current_macro == 0) + _rl_abort_internal (); + + if (_rl_defining_kbd_macro) + { + ding (); /* no recursive macros */ + current_macro[--current_macro_index] = '\0'; /* erase this char */ + return 0; + } + + while (count--) + _rl_with_macro_input (savestring (current_macro)); + return 0; +} + +void +rl_push_macro_input (macro) + char *macro; +{ + _rl_with_macro_input (macro); +} diff --git a/lib/readline/memalloc.h b/lib/readline/memalloc.h deleted file mode 100644 index 750d53d..0000000 --- a/lib/readline/memalloc.h +++ /dev/null @@ -1,56 +0,0 @@ -/* memalloc.h -- consolidate code for including alloca.h or malloc.h and - defining alloca. */ - -/* Copyright (C) 1993 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, 675 Mass Ave, Cambridge, MA 02139, USA. */ - -#if !defined (__MEMALLOC_H__) -# define __MEMALLOC_H__ - -#if defined (sparc) && defined (sun) && !defined (HAVE_ALLOCA_H) -# define HAVE_ALLOCA_H -#endif - -#if defined (__GNUC__) && !defined (HAVE_ALLOCA) -# define HAVE_ALLOCA -#endif - -#if defined (HAVE_ALLOCA_H) && !defined (HAVE_ALLOCA) -# define HAVE_ALLOCA -#endif /* HAVE_ALLOCA_H && !HAVE_ALLOCA */ - -#if !defined (BUILDING_MAKEFILE) - -#if defined (__GNUC__) -# undef alloca -# define alloca __builtin_alloca -#else /* !__GNUC__ */ -# if defined (HAVE_ALLOCA_H) -# if defined (IBMESA) -# include -# else /* !IBMESA */ -# include -# endif /* !IBMESA */ -# else -extern char *alloca (); -# endif /* !HAVE_ALLOCA_H */ -#endif /* !__GNUC__ */ - -#endif /* !BUILDING_MAKEFILE */ - -#endif /* __MEMALLOC_H__ */ diff --git a/lib/readline/nls.c b/lib/readline/nls.c new file mode 100644 index 0000000..fad5201 --- /dev/null +++ b/lib/readline/nls.c @@ -0,0 +1,198 @@ +/* nls.c -- skeletal internationalization code. */ + +/* Copyright (C) 1996 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 1, 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, + 675 Mass Ave, Cambridge, MA 02139, USA. */ +#define READLINE_LIBRARY + +#if defined (HAVE_CONFIG_H) +# include +#endif + +#if defined (HAVE_UNISTD_H) +# include +#endif /* HAVE_UNISTD_H */ + +#if defined (HAVE_STDLIB_H) +# include +#else +# include "ansi_stdlib.h" +#endif /* HAVE_STDLIB_H */ + +#if defined (HAVE_LOCALE_H) +# include +#endif + +#include + +#include "rldefs.h" + +extern int _rl_convert_meta_chars_to_ascii; +extern int _rl_output_meta_chars; +extern int _rl_meta_flag; + +/* A list of legal values for the LANG or LC_CTYPE environment variables. + If a locale name in this list is the value for the LC_ALL, LC_CTYPE, + or LANG environment variable (using the first of those with a value), + readline eight-bit mode is enabled. */ +static char *legal_lang_values[] = +{ + "iso88591", + "iso88592", + "iso88593", + "iso88594", + "iso88595", + "iso88596", + "iso88597", + "iso88598", + "iso88599", + "iso885910", + "koi8r", + 0 +}; + +static char *normalize_codeset (); +static char *find_codeset (); + +/* Check for LC_ALL, LC_CTYPE, and LANG and use the first with a value + to decide the defaults for 8-bit character input and output. Returns + 1 if we set eight-bit mode. */ +int +_rl_init_eightbit () +{ + char *lspec, *t; + int i; + + lspec = getenv ("LC_ALL"); + if (lspec == 0) lspec = getenv ("LC_CTYPE"); + if (lspec == 0) lspec = getenv ("LANG"); + if (lspec == 0 || (t = normalize_codeset (lspec)) == 0) + return (0); + for (i = 0; t && legal_lang_values[i]; i++) + if (STREQ (t, legal_lang_values[i])) + { + _rl_meta_flag = 1; + _rl_convert_meta_chars_to_ascii = 0; + _rl_output_meta_chars = 1; +#if defined (HAVE_SETLOCALE) + setlocale (LC_CTYPE, lspec); +#endif + break; + } + free (t); + return (legal_lang_values[i] ? 1 : 0); +} + +static char * +normalize_codeset (codeset) + char *codeset; +{ + size_t namelen, i; + int len, all_digits; + char *wp, *retval; + + codeset = find_codeset (codeset, &namelen); + + if (codeset == 0) + return (codeset); + + all_digits = 1; + for (len = 0, i = 0; i < namelen; i++) + { + if (isalnum (codeset[i])) + { + len++; + all_digits &= isdigit (codeset[i]); + } + } + + retval = (char *)malloc ((all_digits ? 3 : 0) + len + 1); + if (retval == 0) + return ((char *)0); + + wp = retval; + /* Add `iso' to beginning of an all-digit codeset */ + if (all_digits) + { + *wp++ = 'i'; + *wp++ = 's'; + *wp++ = 'o'; + } + + for (i = 0; i < namelen; i++) + if (isalpha (codeset[i])) + *wp++ = (isupper (codeset[i])) ? tolower (codeset[i]) : codeset[i]; + else if (isdigit (codeset[i])) + *wp++ = codeset[i]; + *wp = '\0'; + + return retval; +} + +/* Isolate codeset portion of locale specification. */ +static char * +find_codeset (name, lenp) + char *name; + size_t *lenp; +{ + char *cp, *language, *result; + + cp = language = name; + result = (char *)0; + + while (*cp && *cp != '_' && *cp != '@' && *cp != '+' && *cp != ',') + cp++; + + /* This does not make sense: language has to be specified. As + an exception we allow the variable to contain only the codeset + name. Perhaps there are funny codeset names. */ + if (language == cp) + { + *lenp = strlen (language); + result = language; + } + else + { + /* Next is the territory. */ + if (*cp == '_') + do + ++cp; + while (*cp && *cp != '.' && *cp != '@' && *cp != '+' && *cp != ',' && *cp != '_'); + + /* Now, finally, is the codeset. */ + result = cp; + if (*cp == '.') + do + ++cp; + while (*cp && *cp != '@'); + + if (cp - result > 2) + { + result++; + *lenp = cp - result; + } + else + { + *lenp = strlen (language); + result = language; + } + } + + return result; +} diff --git a/lib/readline/parens.c b/lib/readline/parens.c index 57a9777..50683f9 100644 --- a/lib/readline/parens.c +++ b/lib/readline/parens.c @@ -1,4 +1,4 @@ -/* parens.c -- Implemenation of matching parenthesis feature. */ +/* parens.c -- Implementation of matching parentheses feature. */ /* Copyright (C) 1987, 1989, 1992 Free Software Foundation, Inc. @@ -24,7 +24,9 @@ #include "rlconf.h" #if !defined (PAREN_MATCHING) +extern int rl_insert (); +int rl_insert_close (count, invoking_key) int count, invoking_key; { @@ -33,25 +35,49 @@ rl_insert_close (count, invoking_key) #else /* PAREN_MATCHING */ +#if defined (HAVE_CONFIG_H) +# include +#endif + #include #include -#if defined (FD_SET) + +#if defined (FD_SET) && !defined (HAVE_SELECT) +# define HAVE_SELECT +#endif + +#if defined (HAVE_SELECT) # include -#endif /* FD_SET */ +#endif /* HAVE_SELECT */ +#if defined (HAVE_SYS_SELECT_H) +# include +#endif + +#if defined (HAVE_STRING_H) +# include +#else /* !HAVE_STRING_H */ +# include +#endif /* !HAVE_STRING_H */ + +#if !defined (strchr) && !defined (__STDC__) +extern char *strchr (), *strrchr (); +#endif /* !strchr && !__STDC__ */ + #include "readline.h" extern int rl_explicit_arg; /* Non-zero means try to blink the matching open parenthesis when the close parenthesis is inserted. */ -#if defined (FD_SET) +#if defined (HAVE_SELECT) int rl_blink_matching_paren = 1; -#else /* !FD_SET */ +#else /* !HAVE_SELECT */ int rl_blink_matching_paren = 0; -#endif /* !FD_SET */ +#endif /* !HAVE_SELECT */ static int find_matching_open (); +int rl_insert_close (count, invoking_key) int count, invoking_key; { @@ -59,13 +85,13 @@ rl_insert_close (count, invoking_key) rl_insert (count, invoking_key); else { -#if defined (FD_SET) +#if defined (HAVE_SELECT) int orig_point, match_point, ready; struct timeval timer; fd_set readfds; rl_insert (1, invoking_key); - rl_redisplay (); + (*rl_redisplay_function) (); match_point = find_matching_open (rl_line_buffer, rl_point - 2, invoking_key); @@ -80,12 +106,12 @@ rl_insert_close (count, invoking_key) orig_point = rl_point; rl_point = match_point; - rl_redisplay (); + (*rl_redisplay_function) (); ready = select (1, &readfds, (fd_set *)NULL, (fd_set *)NULL, &timer); rl_point = orig_point; -#else /* !FD_SET */ +#else /* !HAVE_SELECT */ rl_insert (count, invoking_key); -#endif /* !FD_SET */ +#endif /* !HAVE_SELECT */ } return 0; } @@ -114,8 +140,8 @@ find_matching_open (string, from, closer) { if (delimiter && (string[i] == delimiter)) delimiter = 0; - else if ((string[i] == '\'') || (string[i] == '"')) - delimiter = rl_line_buffer[i]; + else if (rl_basic_quote_characters && strchr (rl_basic_quote_characters, string[i])) + delimiter = string[i]; else if (!delimiter && (string[i] == closer)) level++; else if (!delimiter && (string[i] == opener)) diff --git a/lib/readline/posixdir.h b/lib/readline/posixdir.h new file mode 100644 index 0000000..8b0e5bc --- /dev/null +++ b/lib/readline/posixdir.h @@ -0,0 +1,49 @@ +/* posixdir.h -- Posix directory reading includes and defines. */ + +/* Copyright (C) 1987,1991 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 1, 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, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* This file should be included instead of or . */ + +#if !defined (_POSIXDIR_H_) +#define _POSIXDIR_H_ + +#if defined (HAVE_DIRENT_H) +# include +# define D_NAMLEN(d) (strlen ((d)->d_name)) +#else +# if defined (HAVE_SYS_NDIR_H) +# include +# endif +# if defined (HAVE_SYS_DIR_H) +# include +# endif +# if defined (HAVE_NDIR_H) +# include +# endif +# if !defined (dirent) +# define dirent direct +# endif /* !dirent */ +# define D_NAMLEN(d) ((d)->d_namlen) +#endif /* !HAVE_DIRENT_H */ + +#if defined (STRUCT_DIRENT_HAS_D_INO) +# define d_fileno d_ino +#endif + +#endif /* !_POSIXDIR_H_ */ diff --git a/lib/readline/posixstat.h b/lib/readline/posixstat.h index 7d1cece..bfce8c0 100644 --- a/lib/readline/posixstat.h +++ b/lib/readline/posixstat.h @@ -21,34 +21,27 @@ /* This file should be included instead of . It relies on the local sys/stat.h to work though. */ -#if !defined (_POSIXSTAT_H) -#define _POSIXSTAT_H +#if !defined (_POSIXSTAT_H_) +#define _POSIXSTAT_H_ #include -#if defined (isc386) -# if !defined (S_IFDIR) -# define S_IFDIR 0040000 -# endif /* !S_IFDIR */ -# if !defined (S_IFMT) -# define S_IFMT 0170000 -# endif /* !S_IFMT */ -#endif /* isc386 */ - -/* This text is taken directly from the Cadmus I was trying to - compile on: - the following MACROs are defined for X/OPEN compatibility - however, is the param correct ?? - #define S_ISBLK(s) ((s.st_mode & S_IFMT) == S_IFBLK) - - Well, the answer is no. Thus... */ -#if defined (BrainDeath) +#if defined (STAT_MACROS_BROKEN) # undef S_ISBLK # undef S_ISCHR # undef S_ISDIR # undef S_ISFIFO # undef S_ISREG -#endif /* BrainDeath */ +# undef S_ISLNK +#endif /* STAT_MACROS_BROKEN */ + +/* These are guaranteed to work only on isc386 */ +#if !defined (S_IFDIR) && !defined (S_ISDIR) +# define S_IFDIR 0040000 +#endif /* !S_IFDIR && !S_ISDIR */ +#if !defined (S_IFMT) +# define S_IFMT 0170000 +#endif /* !S_IFMT */ /* Posix 1003.1 5.6.1.1 file types */ @@ -114,7 +107,7 @@ /* * POSIX 1003.1 5.6.1.2 File Modes */ - + #if !defined (S_IRWXU) # if !defined (S_IREAD) # define S_IREAD 00400 @@ -146,4 +139,4 @@ #define S_IWUGO (S_IWUSR | S_IWGRP | S_IWOTH) #define S_IXUGO (S_IXUSR | S_IXGRP | S_IXOTH) -#endif /* _POSIXSTAT_H */ +#endif /* _POSIXSTAT_H_ */ diff --git a/lib/readline/readline.c b/lib/readline/readline.c index 6040cbb..d85789d 100644 --- a/lib/readline/readline.c +++ b/lib/readline/readline.c @@ -22,13 +22,16 @@ 675 Mass Ave, Cambridge, MA 02139, USA. */ #define READLINE_LIBRARY -#include +#if defined (HAVE_CONFIG_H) +# include +#endif + #include +#include "posixstat.h" #include -#if !defined (NO_SYS_FILE) +#if defined (HAVE_SYS_FILE_H) # include -#endif /* !NO_SYS_FILE */ -#include +#endif /* HAVE_SYS_FILE_H */ #if defined (HAVE_UNISTD_H) # include @@ -40,37 +43,61 @@ # include "ansi_stdlib.h" #endif /* HAVE_STDLIB_H */ -#include -/* Not all systems declare ERRNO in errno.h... and some systems #define it! */ -#if !defined (errno) -extern int errno; -#endif /* !errno */ +#if defined (HAVE_LOCALE_H) +# include +#endif +#include +#include #include -#include "posixstat.h" - /* System-specific feature definitions and include files. */ #include "rldefs.h" -#if defined (GWINSZ_IN_SYS_IOCTL) || (defined (VSTATUS) && !defined (SunOS4)) -# include -#endif /* GWINSZ_IN_SYS_IOCTL || VSTATUS */ +#include "tcap.h" /* Some standard library routines. */ #include "readline.h" #include "history.h" +#define SWAP(s, e) do { int t; t = s; s = e; e = t; } while (0) + /* NOTE: Functions and variables prefixed with `_rl_' are pseudo-global: they are global so they can be shared between files in the readline library, but are not intended to be visible to readline callers. */ -/* Functions imported from other files in the library. */ -extern char *tgetstr (); +/* Variables and functions imported from terminal.c */ +extern int _rl_init_terminal_io (); +extern void _rl_enable_meta_key (); +extern int _rl_output_character_function (); +extern void _rl_get_screen_size (); + +extern int _rl_enable_meta; +extern int _rl_term_autowrap; +extern char *term_backspace, *term_clreol, *term_clrpag; +extern int screenwidth, screenheight, screenchars; + +/* Variables and functions imported from rltty.c. */ extern void rl_prep_terminal (), rl_deprep_terminal (); +extern void rltty_set_default_bindings (); + +/* Functions imported from util.c. */ +extern void _rl_abort_internal (); +extern void rl_extend_line_buffer (); +extern int alphabetic (); +/* Functions imported from bind.c. */ extern void _rl_bind_if_unbound (); +extern int rl_set_keymap_from_edit_mode (); + +/* Functions imported from input.c. */ +extern int _rl_any_typein (); +extern void _rl_insert_typein (); +extern int rl_read_key (); + +/* Functions imported from nls.c */ +extern int _rl_init_eightbit (); /* External redisplay functions and variables from display.c */ extern void _rl_move_vert (); @@ -83,6 +110,7 @@ extern int _rl_vis_botlin; extern int _rl_last_c_pos; extern int _rl_horizontal_scroll_mode; extern int rl_display_fixed; +extern int _rl_suppress_redisplay; extern char *rl_display_prompt; /* Variables imported from complete.c. */ @@ -91,22 +119,32 @@ extern char *rl_basic_word_break_characters; extern int rl_completion_query_items; extern int rl_complete_with_tilde_expansion; +/* Variables and functions from macro.c. */ +extern void _rl_add_macro_char (); +extern void _rl_with_macro_input (); +extern int _rl_next_macro_key (); +extern int _rl_defining_kbd_macro; + #if defined (VI_MODE) +/* Functions imported from vi_mode.c. */ extern void _rl_vi_set_last (); extern void _rl_vi_reset_last (); extern void _rl_vi_done_inserting (); +extern int _rl_vi_textmod_command (); +extern void _rl_vi_initialize_line (); #endif /* VI_MODE */ +extern UNDO_LIST *rl_undo_list; +extern int _rl_doing_an_undo; + /* Forward declarations used in this file. */ void _rl_free_history_entry (); int _rl_dispatch (); -void _rl_set_screen_size (); -int _rl_output_character_function (); +int _rl_init_argument (); static char *readline_internal (); static void readline_initialize_everything (); -static int init_terminal_io (); static void start_using_history (); static void bind_arrow_keys (); @@ -115,24 +153,19 @@ static void readline_default_bindings (); #endif /* !__GO32__ */ #if defined (__GO32__) -# include +# include # undef HANDLE_SIGNALS #endif /* __GO32__ */ -#if defined (STATIC_MALLOC) -static char *xmalloc (), *xrealloc (); -#else extern char *xmalloc (), *xrealloc (); -#endif /* STATIC_MALLOC */ - /* **************************************************************** */ /* */ /* Line editing input utility */ /* */ /* **************************************************************** */ -static char *LibraryVersion = "2.0"; +char *rl_library_version = "2.1"; /* A pointer to the keymap that is currently in use. By default, it is the standard emacs keymap. */ @@ -142,7 +175,7 @@ Keymap _rl_keymap = emacs_standard_keymap; int rl_editing_mode = emacs_mode; /* Non-zero if the previous command was a kill command. */ -static int last_command_was_kill = 0; +int _rl_last_command_was_kill = 0; /* The current value of the numeric argument specified by the user. */ int rl_numeric_arg = 1; @@ -154,10 +187,10 @@ int rl_explicit_arg = 0; int rl_arg_sign = 1; /* Non-zero means we have been called at least once before. */ -static int rl_initialized = 0; +static int rl_initialized; /* If non-zero, this program is running in an EMACS buffer. */ -static int running_in_emacs = 0; +static int running_in_emacs; /* The current offset in the current input line. */ int rl_point; @@ -175,10 +208,10 @@ int rl_done; Function *rl_last_func = (Function *)NULL; /* Top level environment for readline_internal (). */ -static jmp_buf readline_top_level; +jmp_buf readline_top_level; /* The streams we interact with. */ -static FILE *in_stream, *out_stream; +FILE *_rl_in_stream, *_rl_out_stream; /* The names of the streams that we do input and output to. */ FILE *rl_instream = (FILE *)NULL; @@ -222,16 +255,18 @@ int _rl_mark_modified_lines = 0; AUDIBLE_BELL, or VISIBLE_BELL. */ int _rl_bell_preference = AUDIBLE_BELL; +/* String inserted into the line by rl_insert_comment (). */ +char *_rl_comment_begin; + +/* Keymap holding the function currently being executed. */ +Keymap rl_executing_keymap; + /* Line buffer and maintenence. */ char *rl_line_buffer = (char *)NULL; int rl_line_buffer_len = 0; -#define DEFAULT_BUFFER_SIZE 256 /* Forward declarations used by the display and termcap code. */ -int term_xn; -int screenwidth, screenheight, screenchars; - /* **************************************************************** */ /* */ /* `Forward' declarations */ @@ -242,9 +277,6 @@ int screenwidth, screenheight, screenchars; parser directives. */ unsigned char _rl_parsing_conditionalized_out = 0; -/* Non-zero means to save keys that we dispatch on in a kbd macro. */ -static int defining_kbd_macro = 0; - /* Non-zero means to convert characters with the meta bit set to escape-prefixed characters so we can indirect through emacs_meta_keymap or vi_escape_keymap. */ @@ -254,10 +286,6 @@ int _rl_convert_meta_chars_to_ascii = 1; rather than as a meta-prefixed escape sequence. */ int _rl_output_meta_chars = 0; -/* Non-zero tells rl_delete_text and rl_insert_text to not add to - the undo list. */ -static int doing_an_undo = 0; - /* **************************************************************** */ /* */ /* Top Level Functions */ @@ -267,7 +295,7 @@ static int doing_an_undo = 0; /* Non-zero means treat 0200 bit in terminal input as Meta bit. */ int _rl_meta_flag = 0; /* Forward declaration */ -/* Read a line of input. Prompt with PROMPT. A NULL PROMPT means +/* Read a line of input. Prompt with PROMPT. An empty PROMPT means none. A return value of NULL means that EOF was encountered. */ char * readline (prompt) @@ -287,14 +315,14 @@ readline (prompt) rl_visible_prompt_length = rl_expand_prompt (rl_prompt); rl_initialize (); - rl_prep_terminal (_rl_meta_flag); + (*rl_prep_term_function) (_rl_meta_flag); #if defined (HANDLE_SIGNALS) rl_set_signals (); #endif value = readline_internal (); - rl_deprep_terminal (); + (*rl_deprep_term_function) (); #if defined (HANDLE_SIGNALS) rl_clear_signals (); @@ -303,55 +331,98 @@ readline (prompt) return (value); } -/* Read a line of input from the global rl_instream, doing output on - the global rl_outstream. - If rl_prompt is non-null, then that is our prompt. */ -static char * -readline_internal () -{ - int lastc, c, eof_found; - - in_stream = rl_instream; - out_stream = rl_outstream; +#if defined (READLINE_CALLBACKS) +# define STATIC_CALLBACK +#else +# define STATIC_CALLBACK static +#endif - lastc = -1; - eof_found = 0; +STATIC_CALLBACK void +readline_internal_setup () +{ + _rl_in_stream = rl_instream; + _rl_out_stream = rl_outstream; if (rl_startup_hook) (*rl_startup_hook) (); - if (!readline_echoing_p) + if (readline_echoing_p == 0) { if (rl_prompt) { - fprintf (out_stream, "%s", rl_prompt); - fflush (out_stream); + fprintf (_rl_out_stream, "%s", rl_prompt); + fflush (_rl_out_stream); } } else { rl_on_new_line (); - rl_redisplay (); + (*rl_redisplay_function) (); #if defined (VI_MODE) if (rl_editing_mode == vi_mode) rl_vi_insertion_mode (); #endif /* VI_MODE */ } +} + +STATIC_CALLBACK char * +readline_internal_teardown (eof) + int eof; +{ + char *temp; + HIST_ENTRY *entry; + + /* Restore the original of this history line, iff the line that we + are editing was originally in the history, AND the line has changed. */ + entry = current_history (); + + if (entry && rl_undo_list) + { + temp = savestring (the_line); + rl_revert_line (1, 0); + entry = replace_history_entry (where_history (), the_line, (HIST_ENTRY *)NULL); + _rl_free_history_entry (entry); + + strcpy (the_line, temp); + free (temp); + } + + /* At any rate, it is highly likely that this line has an undo list. Get + rid of it now. */ + if (rl_undo_list) + free_undo_list (); + + return (eof ? (char *)NULL : savestring (the_line)); +} - while (!rl_done) +STATIC_CALLBACK int +#if defined (READLINE_CALLBACKS) +readline_internal_char () +#else +readline_internal_charloop () +#endif +{ + static int lastc, eof_found; + int c, code, lk; + + lastc = -1; + eof_found = 0; + +#if !defined (READLINE_CALLBACKS) + while (rl_done == 0) { - int lk = last_command_was_kill; - int code; +#endif + lk = _rl_last_command_was_kill; code = setjmp (readline_top_level); if (code) - rl_redisplay (); + (*rl_redisplay_function) (); - if (!rl_pending_input) + if (rl_pending_input == 0) { /* Then initialize the argument and number of keys read. */ - rl_init_argument (); + _rl_init_argument (); rl_key_sequence_length = 0; } @@ -365,21 +436,22 @@ readline_internal () previous character is interpreted as EOF. */ if (((c == _rl_eof_char && lastc != c) || c == EOF) && !rl_end) { +#if defined (READLINE_CALLBACKS) + return (rl_done = 1); +#else eof_found = 1; break; +#endif } lastc = c; _rl_dispatch (c, _rl_keymap); - /* If there was no change in last_command_was_kill, then no kill + /* If there was no change in _rl_last_command_was_kill, then no kill has taken place. Note that if input is pending we are reading a prefix command, so nothing has changed yet. */ - if (!rl_pending_input) - { - if (lk == last_command_was_kill) - last_command_was_kill = 0; - } + if (rl_pending_input == 0 && lk == _rl_last_command_was_kill) + _rl_last_command_was_kill = 0; #if defined (VI_MODE) /* In vi mode, when you exit insert mode, the cursor moves back @@ -388,232 +460,49 @@ readline_internal () rl_vi_check (); #endif /* VI_MODE */ - if (!rl_done) - rl_redisplay (); - } - - /* Restore the original of this history line, iff the line that we - are editing was originally in the history, AND the line has changed. */ - { - HIST_ENTRY *entry = current_history (); - - if (entry && rl_undo_list) - { - char *temp = savestring (the_line); - rl_revert_line (); - entry = replace_history_entry (where_history (), the_line, - (HIST_ENTRY *)NULL); - _rl_free_history_entry (entry); - - strcpy (the_line, temp); - free (temp); - } - } - - /* At any rate, it is highly likely that this line has an undo list. Get - rid of it now. */ - if (rl_undo_list) - free_undo_list (); - - if (eof_found) - return (char *)NULL; - else - return (savestring (the_line)); -} - -/* **************************************************************** */ -/* */ -/* Character Input Buffering */ -/* */ -/* **************************************************************** */ - -static int pop_index = 0, push_index = 0, ibuffer_len = 511; -static unsigned char ibuffer[512]; + if (rl_done == 0) + (*rl_redisplay_function) (); -/* Non-null means it is a pointer to a function to run while waiting for - character input. */ -Function *rl_event_hook = (Function *)NULL; - -#define any_typein (push_index != pop_index) - -/* Add KEY to the buffer of characters to be read. */ -rl_stuff_char (key) - int key; -{ - if (key == EOF) - { - key = NEWLINE; - rl_pending_input = EOF; +#if defined (READLINE_CALLBACKS) + return 0; +#else } - ibuffer[push_index++] = key; - if (push_index >= ibuffer_len) - push_index = 0; - return push_index; -} -/* Return the amount of space available in the - buffer for stuffing characters. */ -int -ibuffer_space () -{ - if (pop_index > push_index) - return (pop_index - push_index); - else - return (ibuffer_len - (push_index - pop_index)); + return (eof_found); +#endif } -/* 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. */ -int -rl_get_char (key) - int *key; +#if defined (READLINE_CALLBACKS) +static int +readline_internal_charloop () { - if (push_index == pop_index) - return (0); - - *key = ibuffer[pop_index++]; - - if (pop_index >= ibuffer_len) - pop_index = 0; - - return (1); -} + int eof; -/* 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); + while (rl_done == 0) + eof = readline_internal_char (); + return (eof); } +#endif /* READLINE_CALLBACKS */ -/* If a character is available to be read, then read it - and stuff it into IBUFFER. Otherwise, just return. */ -void -rl_gather_tyi () +/* Read a line of input from the global rl_instream, doing output on + the global rl_outstream. + If rl_prompt is non-null, then that is our prompt. */ +static char * +readline_internal () { -#if defined (__GO32__) - char input; - - if (isatty (0)) - { - int i = rl_getc (); - - if (i != EOF) - rl_stuff_char (i); - } - else if (kbhit () && ibuffer_space ()) - rl_stuff_char (getkey ()); -#else /* !__GO32__ */ - - int tty = fileno (in_stream); - register int tem, result = -1; - int chars_avail; - char input; - -#if defined (FIONREAD) - result = ioctl (tty, FIONREAD, &chars_avail); -#endif - -#if defined (O_NDELAY) - if (result == -1) - { - int flags; - - flags = fcntl (tty, F_GETFL, 0); + int eof; - fcntl (tty, F_SETFL, (flags | O_NDELAY)); - chars_avail = read (tty, &input, 1); - - fcntl (tty, F_SETFL, flags); - if (chars_avail == -1 && errno == EAGAIN) - return; - } -#endif /* O_NDELAY */ - - /* If there's nothing available, don't waste time trying to read - something. */ - if (chars_avail == 0) - return; - - 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--) - rl_stuff_char (rl_getc (in_stream)); - } - else - { - if (chars_avail) - rl_stuff_char (input); - } -#endif /* !__GO32__ */ + readline_internal_setup (); + eof = readline_internal_charloop (); + return (readline_internal_teardown (eof)); } -static int next_macro_key (); -/* Read a key, including pending input. */ -int -rl_read_key () +void +_rl_set_the_line () { - int c; - - rl_key_sequence_length++; - - if (rl_pending_input) - { - c = rl_pending_input; - rl_pending_input = 0; - } - else - { - /* If input is coming from a macro, then use that. */ - if (c = 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)) - { - (*rl_event_hook) (); - rl_gather_tyi (); - } - } - else - { - if (!rl_get_char (&c)) - c = rl_getc (in_stream); - } - } - - return (c); + the_line = rl_line_buffer; } -/* Found later in this file. */ -static void add_macro_char (), with_macro_input (); - /* Do the command associated with KEY in MAP. If the associated command is really a keymap, then read another key, and dispatch into that map. */ @@ -622,14 +511,16 @@ _rl_dispatch (key, map) register int key; Keymap map; { - int r = 0; + int r, newkey; + char *macro; + Function *func; if (META_CHAR (key) && _rl_convert_meta_chars_to_ascii) { if (map[ESC].type == ISKMAP) { - if (defining_kbd_macro) - add_macro_char (ESC); + if (_rl_defining_kbd_macro) + _rl_add_macro_char (ESC); map = FUNCTION_TO_KEYMAP (map, ESC); key = UNMETA (key); rl_key_sequence_length += 2; @@ -640,49 +531,51 @@ _rl_dispatch (key, map) return 0; } - if (defining_kbd_macro) - add_macro_char (key); + if (_rl_defining_kbd_macro) + _rl_add_macro_char (key); + r = 0; switch (map[key].type) { case ISFUNC: - { - Function *func = map[key].function; - - if (func != (Function *)NULL) - { - /* Special case rl_do_lowercase_version (). */ - if (func == rl_do_lowercase_version) - return (_rl_dispatch (to_lower (key), map)); - - r = (*map[key].function)(rl_numeric_arg * rl_arg_sign, key); - - /* If we have input pending, then the last command was a prefix - command. Don't change the state of rl_last_func. Otherwise, - remember the last command executed in this variable. */ - if (!rl_pending_input) - rl_last_func = map[key].function; - } - else - { - rl_abort (); - return -1; - } - } + func = map[key].function; + if (func != (Function *)NULL) + { + /* Special case rl_do_lowercase_version (). */ + if (func == rl_do_lowercase_version) + return (_rl_dispatch (_rl_to_lower (key), map)); + + rl_executing_keymap = map; + +#if 0 + _rl_suppress_redisplay = (map[key].function == rl_insert) && _rl_input_available (); +#endif + + r = (*map[key].function)(rl_numeric_arg * rl_arg_sign, key); + + /* If we have input pending, then the last command was a prefix + command. Don't change the state of rl_last_func. Otherwise, + remember the last command executed in this variable. */ + if (!rl_pending_input) + rl_last_func = map[key].function; + } + else + { + _rl_abort_internal (); + return -1; + } break; case ISKMAP: if (map[key].function != (Function *)NULL) { - int newkey; - rl_key_sequence_length++; newkey = rl_read_key (); r = _rl_dispatch (newkey, FUNCTION_TO_KEYMAP (map, key)); } else { - rl_abort (); + _rl_abort_internal (); return -1; } break; @@ -690,334 +583,125 @@ _rl_dispatch (key, map) case ISMACR: if (map[key].function != (Function *)NULL) { - char *macro; - macro = savestring ((char *)map[key].function); - with_macro_input (macro); + _rl_with_macro_input (macro); return 0; } break; } #if defined (VI_MODE) if (rl_editing_mode == vi_mode && _rl_keymap == vi_movement_keymap && - rl_vi_textmod_command (key)) + _rl_vi_textmod_command (key)) _rl_vi_set_last (key, rl_numeric_arg, rl_arg_sign); #endif return (r); } - /* **************************************************************** */ /* */ -/* Hacking Keyboard Macros */ +/* Initializations */ /* */ /* **************************************************************** */ -/* The currently executing macro string. If this is non-zero, - then it is a malloc ()'ed string where input is coming from. */ -static char *executing_macro = (char *)NULL; +/* Initliaze readline (and terminal if not already). */ +int +rl_initialize () +{ + /* If we have never been called before, initialize the + terminal and data structures. */ + if (!rl_initialized) + { + readline_initialize_everything (); + rl_initialized++; + } -/* The offset in the above string to the next character to be read. */ -static int executing_macro_index = 0; + /* Initalize the current line information. */ + rl_point = rl_end = 0; + the_line = rl_line_buffer; + the_line[0] = 0; -/* The current macro string being built. Characters get stuffed - in here by add_macro_char (). */ -static char *current_macro = (char *)NULL; + /* We aren't done yet. We haven't even gotten started yet! */ + rl_done = 0; -/* The size of the buffer allocated to current_macro. */ -static int current_macro_size = 0; + /* Tell the history routines what is going on. */ + start_using_history (); -/* The index at which characters are being added to current_macro. */ -static int current_macro_index = 0; + /* Make the display buffer match the state of the line. */ + rl_reset_line_state (); -/* A structure used to save nested macro strings. - It is a linked list of string/index for each saved macro. */ -struct saved_macro { - struct saved_macro *next; - char *string; - int sindex; -}; + /* No such function typed yet. */ + rl_last_func = (Function *)NULL; -/* The list of saved macros. */ -struct saved_macro *macro_list = (struct saved_macro *)NULL; + /* Parsing of key-bindings begins in an enabled state. */ + _rl_parsing_conditionalized_out = 0; -/* Forward declarations of static functions. Thank you C. */ -static void push_executing_macro (), pop_executing_macro (); +#if defined (VI_MODE) + if (rl_editing_mode == vi_mode) + _rl_vi_initialize_line (); +#endif -/* This one has to be declared earlier in the file. */ -/* static void add_macro_char (); */ + return 0; +} -/* Set up to read subsequent input from STRING. - STRING is free ()'ed when we are done with it. */ +/* Initialize the entire state of the world. */ static void -with_macro_input (string) - char *string; +readline_initialize_everything () { - push_executing_macro (); - executing_macro = string; - executing_macro_index = 0; -} + /* Find out if we are running in Emacs. */ + running_in_emacs = getenv ("EMACS") != (char *)0; -/* Return the next character available from a macro, or 0 if - there are no macro characters. */ -static int -next_macro_key () -{ - if (!executing_macro) - return (0); + /* Set up input and output if they are not already set up. */ + if (!rl_instream) + rl_instream = stdin; - if (!executing_macro[executing_macro_index]) - { - pop_executing_macro (); - return (next_macro_key ()); - } + if (!rl_outstream) + rl_outstream = stdout; - return (executing_macro[executing_macro_index++]); -} + /* Bind _rl_in_stream and _rl_out_stream immediately. These values + may change, but they may also be used before readline_internal () + is called. */ + _rl_in_stream = rl_instream; + _rl_out_stream = rl_outstream; -/* Save the currently executing macro on a stack of saved macros. */ -static void -push_executing_macro () -{ - struct saved_macro *saver; + /* Allocate data structures. */ + if (!rl_line_buffer) + rl_line_buffer = xmalloc (rl_line_buffer_len = DEFAULT_BUFFER_SIZE); - saver = (struct saved_macro *)xmalloc (sizeof (struct saved_macro)); - saver->next = macro_list; - saver->sindex = executing_macro_index; - saver->string = executing_macro; + /* Initialize the terminal interface. */ + _rl_init_terminal_io ((char *)NULL); - macro_list = saver; -} +#if !defined (__GO32__) + /* Bind tty characters to readline functions. */ + readline_default_bindings (); +#endif /* !__GO32__ */ -/* Discard the current macro, replacing it with the one - on the top of the stack of saved macros. */ -static void -pop_executing_macro () -{ - if (executing_macro) - free (executing_macro); + /* Initialize the function names. */ + rl_initialize_funmap (); - executing_macro = (char *)NULL; - executing_macro_index = 0; + /* Decide whether we should automatically go into eight-bit mode. */ + _rl_init_eightbit (); + + /* Read in the init file. */ + rl_read_init_file ((char *)NULL); - if (macro_list) + /* XXX */ + if (_rl_horizontal_scroll_mode && _rl_term_autowrap) { - struct saved_macro *disposer = macro_list; - executing_macro = macro_list->string; - executing_macro_index = macro_list->sindex; - macro_list = macro_list->next; - free (disposer); + screenwidth--; + screenchars -= screenheight; } -} -/* Add a character to the macro being built. */ -static void -add_macro_char (c) - int c; -{ - if (current_macro_index + 1 >= current_macro_size) - { - if (!current_macro) - current_macro = xmalloc (current_macro_size = 25); - else - current_macro = xrealloc (current_macro, current_macro_size += 25); - } - - current_macro[current_macro_index++] = c; - current_macro[current_macro_index] = '\0'; -} - -/* Begin defining a keyboard macro. - Keystrokes are recorded as they are executed. - End the definition with rl_end_kbd_macro (). - If a numeric argument was explicitly typed, then append this - definition to the end of the existing macro, and start by - re-executing the existing macro. */ -rl_start_kbd_macro (ignore1, ignore2) - int ignore1, ignore2; -{ - if (defining_kbd_macro) - { - rl_abort (); - return -1; - } - - if (rl_explicit_arg) - { - if (current_macro) - with_macro_input (savestring (current_macro)); - } - else - current_macro_index = 0; - - defining_kbd_macro = 1; - return 0; -} - -/* Stop defining a keyboard macro. - A numeric argument says to execute the macro right now, - that many times, counting the definition as the first time. */ -rl_end_kbd_macro (count, ignore) - int count, ignore; -{ - if (!defining_kbd_macro) - { - rl_abort (); - return -1; - } - - current_macro_index -= (rl_key_sequence_length - 1); - current_macro[current_macro_index] = '\0'; - - defining_kbd_macro = 0; - - return (rl_call_last_kbd_macro (--count, 0)); -} - -/* Execute the most recently defined keyboard macro. - COUNT says how many times to execute it. */ -rl_call_last_kbd_macro (count, ignore) - int count, ignore; -{ - if (!current_macro) - rl_abort (); - - if (defining_kbd_macro) - { - ding (); /* no recursive macros */ - current_macro[--current_macro_index] = '\0'; /* erase this char */ - return 0; - } - - while (count--) - with_macro_input (savestring (current_macro)); - return 0; -} - -void -_rl_kill_kbd_macro () -{ - if (current_macro) - { - free (current_macro); - current_macro = (char *) NULL; - } - current_macro_size = current_macro_index = 0; - - if (executing_macro) - { - free (executing_macro); - executing_macro = (char *) NULL; - } - executing_macro_index = 0; - - defining_kbd_macro = 0; -} - -/* **************************************************************** */ -/* */ -/* Initializations */ -/* */ -/* **************************************************************** */ - -/* Initliaze readline (and terminal if not already). */ -rl_initialize () -{ - /* If we have never been called before, initialize the - terminal and data structures. */ - if (!rl_initialized) - { - readline_initialize_everything (); - rl_initialized++; - } - - /* Initalize the current line information. */ - rl_point = rl_end = 0; - the_line = rl_line_buffer; - the_line[0] = 0; - - /* We aren't done yet. We haven't even gotten started yet! */ - rl_done = 0; - - /* Tell the history routines what is going on. */ - start_using_history (); - - /* Make the display buffer match the state of the line. */ - rl_reset_line_state (); - - /* No such function typed yet. */ - rl_last_func = (Function *)NULL; - - /* Parsing of key-bindings begins in an enabled state. */ - _rl_parsing_conditionalized_out = 0; - - return 0; -} - -/* Initialize the entire state of the world. */ -static void -readline_initialize_everything () -{ - char *t; - - /* Find out if we are running in Emacs. */ - running_in_emacs = getenv ("EMACS") != (char *)0; - - /* Set up input and output if they are not already set up. */ - if (!rl_instream) - rl_instream = stdin; - - if (!rl_outstream) - rl_outstream = stdout; - - /* Bind in_stream and out_stream immediately. These values may change, - but they may also be used before readline_internal () is called. */ - in_stream = rl_instream; - out_stream = rl_outstream; - - /* Allocate data structures. */ - if (!rl_line_buffer) - rl_line_buffer = xmalloc (rl_line_buffer_len = DEFAULT_BUFFER_SIZE); - - /* Initialize the terminal interface. */ - init_terminal_io ((char *)NULL); - -#if !defined (__GO32__) - /* Bind tty characters to readline functions. */ - readline_default_bindings (); -#endif /* !__GO32__ */ - - /* Initialize the function names. */ - rl_initialize_funmap (); - - /* Check for LC_CTYPE and use its value to decide the defaults for - 8-bit character input and output. */ - t = getenv ("LC_CTYPE"); - if (t && (strcmp (t, "iso-8859-1") == 0 || strcmp (t, "iso_8859_1") == 0 || - strcmp (t, "ISO-8859-1") == 0)) - { - _rl_meta_flag = 1; - _rl_convert_meta_chars_to_ascii = 0; - _rl_output_meta_chars = 1; - } - - /* Read in the init file. */ - rl_read_init_file ((char *)NULL); - - /* XXX */ - if (_rl_horizontal_scroll_mode && term_xn) - { - screenwidth--; - screenchars -= screenheight; - } - - /* Override the effect of any `set keymap' assignments in the - inputrc file. */ - rl_set_keymap_from_edit_mode (); + /* Override the effect of any `set keymap' assignments in the + inputrc file. */ + rl_set_keymap_from_edit_mode (); /* Try to bind a common arrow key prefix, if not already bound. */ bind_arrow_keys (); + /* Enable the meta key, if this terminal has one. */ + if (_rl_enable_meta) + _rl_enable_meta_key (); + /* If the completion parser's default word break characters haven't been set yet, then do so now. */ if (rl_completer_word_break_characters == (char *)NULL) @@ -1089,8 +773,11 @@ bind_arrow_keys () static int rl_digit_loop () { - int key, c; + int key, c, sawminus; + + _rl_save_prompt (); + sawminus = 0; while (1) { rl_message ("(arg: %d) ", rl_arg_sign * rl_numeric_arg); @@ -1103,32 +790,35 @@ rl_digit_loop () continue; } c = UNMETA (c); - if (digit_p (c)) + if (_rl_digit_p (c)) { - if (rl_explicit_arg) - rl_numeric_arg = (rl_numeric_arg * 10) + (c - '0'); - else - rl_numeric_arg = (c - '0'); + rl_numeric_arg = rl_explicit_arg ? (rl_numeric_arg * 10) + c - '0' : c - '0'; rl_explicit_arg = 1; } else { - if (c == '-' && !rl_explicit_arg) + if (c == '-' && rl_explicit_arg == 0) { - rl_numeric_arg = 1; + rl_numeric_arg = sawminus = 1; rl_arg_sign = -1; } else { + /* Make M-- command equivalent to M--1 command. */ + if (sawminus && rl_numeric_arg == 1 && rl_explicit_arg == 0) + rl_explicit_arg = 1; + _rl_restore_prompt (); rl_clear_message (); return (_rl_dispatch (key, _rl_keymap)); } } } + return 0; } /* Add the current digit to the argument in progress. */ +int rl_digit_argument (ignore, key) int ignore, key; { @@ -1137,16 +827,18 @@ rl_digit_argument (ignore, key) } /* What to do when you abort reading an argument. */ +int rl_discard_argument () { ding (); rl_clear_message (); - rl_init_argument (); + _rl_init_argument (); return 0; } /* Create a default argument. */ -rl_init_argument () +int +_rl_init_argument () { rl_numeric_arg = rl_arg_sign = 1; rl_explicit_arg = 0; @@ -1156,2078 +848,770 @@ rl_init_argument () /* C-u, universal argument. Multiply the current argument by 4. Read a key. If the key has nothing to do with arguments, then dispatch on it. If the key is the abort character then abort. */ -rl_universal_argument () +int +rl_universal_argument (count, key) + int count, key; { rl_numeric_arg *= 4; return (rl_digit_loop ()); } - + /* **************************************************************** */ /* */ -/* Terminal and Termcap */ +/* Insert and Delete */ /* */ /* **************************************************************** */ -static char *term_buffer = (char *)NULL; -static char *term_string_buffer = (char *)NULL; - -static int tcap_initialized = 0; - -/* Non-zero means this terminal can't really do anything. */ -int dumb_term = 0; -/* On Solaris2, sys/types.h #includes sys/reg.h, which #defines PC. - Unfortunately, PC is a global variable used by the termcap library. */ -#undef PC - -#if !defined (__linux__) -/* If this causes problems, add back the `extern'. */ -/*extern*/ char PC, *BC, *UP; -#endif /* __linux__ */ - -/* Some strings to control terminal actions. These are output by tputs (). */ -char *term_goto, *term_clreol, *term_cr, *term_clrpag, *term_backspace; -char *term_pc; - -/* Non-zero if we determine that the terminal can do character insertion. */ -int terminal_can_insert = 0; - -/* How to insert characters. */ -char *term_im, *term_ei, *term_ic, *term_ip, *term_IC; - -/* How to delete characters. */ -char *term_dc, *term_DC; - -#if defined (HACK_TERMCAP_MOTION) -char *term_forward_char; -#endif /* HACK_TERMCAP_MOTION */ - -/* How to go up a line. */ -char *term_up; - -/* A visible bell, if the terminal can be made to flash the screen. */ -char *visible_bell; - -/* Non-zero means that this terminal has a meta key. */ -int term_has_meta; - -/* The string to write to turn on the meta key, if this term has one. */ -char *term_mm; - -/* The string to write to turn off the meta key, if this term has one. */ -char *term_mo; +/* Insert a string of text into the line at point. This is the only + way that you should do insertion. rl_insert () calls this + function. */ +int +rl_insert_text (string) + char *string; +{ + register int i, l = strlen (string); -/* The key sequences output by the arrow keys, if this terminal has any. */ -char *term_ku, *term_kd, *term_kr, *term_kl; + if (rl_end + l >= rl_line_buffer_len) + rl_extend_line_buffer (rl_end + l); -/* How to initialize and reset the arrow keys, if this terminal has any. */ -char *term_ks, *term_ke; + for (i = rl_end; i >= rl_point; i--) + the_line[i + l] = the_line[i]; + strncpy (the_line + rl_point, string, l); -/* Re-initialize the terminal considering that the TERM/TERMCAP variable - has changed. */ -rl_reset_terminal (terminal_name) - char *terminal_name; -{ - init_terminal_io (terminal_name); - return 0; + /* Remember how to undo this if we aren't undoing something. */ + if (!_rl_doing_an_undo) + { + /* If possible and desirable, concatenate the undos. */ + if ((l == 1) && + rl_undo_list && + (rl_undo_list->what == UNDO_INSERT) && + (rl_undo_list->end == rl_point) && + (rl_undo_list->end - rl_undo_list->start < 20)) + rl_undo_list->end++; + else + rl_add_undo (UNDO_INSERT, rl_point, rl_point + l, (char *)NULL); + } + rl_point += l; + rl_end += l; + the_line[rl_end] = '\0'; + return l; } -/* Set 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_set_screen_size (tty, ignore_env) - int tty, ignore_env; +/* Delete the string between FROM and TO. FROM is + inclusive, TO is not. */ +int +rl_delete_text (from, to) + int from, to; { -#if defined (TIOCGWINSZ) - struct winsize window_size; -#endif /* TIOCGWINSZ */ + register char *text; + register int diff, i; -#if defined (TIOCGWINSZ) - if (ioctl (tty, TIOCGWINSZ, &window_size) == 0) + /* Fix it if the caller is confused. */ + if (from > to) + SWAP (from, to); + + /* fix boundaries */ + if (to > rl_end) { - screenwidth = (int) window_size.ws_col; - screenheight = (int) window_size.ws_row; + to = rl_end; + if (from > to) + from = to; } -#endif /* TIOCGWINSZ */ - /* Environment variable COLUMNS overrides setting of "co" if IGNORE_ENV - is unset. */ - if (screenwidth <= 0) - { - char *sw; + text = rl_copy_text (from, to); - if (!ignore_env && (sw = getenv ("COLUMNS"))) - screenwidth = atoi (sw); + /* Some versions of strncpy() can't handle overlapping arguments. */ + diff = to - from; + for (i = from; i < rl_end - diff; i++) + the_line[i] = the_line[i + diff]; - if (screenwidth <= 0 && term_string_buffer) - screenwidth = tgetnum ("co"); - } + /* Remember how to undo this delete. */ + if (_rl_doing_an_undo == 0) + rl_add_undo (UNDO_DELETE, from, to, text); + else + free (text); - /* Environment variable LINES overrides setting of "li" if IGNORE_ENV - is unset. */ - if (screenheight <= 0) - { - char *sh; + rl_end -= diff; + the_line[rl_end] = '\0'; + return (diff); +} - if (!ignore_env && (sh = getenv ("LINES"))) - screenheight = atoi (sh); +/* **************************************************************** */ +/* */ +/* Readline character functions */ +/* */ +/* **************************************************************** */ - if (screenheight <= 0 && term_string_buffer) - screenheight = tgetnum ("li"); - } +/* This is not a gap editor, just a stupid line input routine. No hair + is involved in writing any of the functions, and none should be. */ - /* If all else fails, default to 80x24 terminal. */ - if (screenwidth <= 1) - screenwidth = 80; +/* Note that: - if (screenheight <= 0) - screenheight = 24; + rl_end is the place in the string that we would place '\0'; + i.e., it is always safe to place '\0' there. -#if defined (SHELL) - /* If we're being compiled as part of bash, set the environment - variables $LINES and $COLUMNS to new values. */ - set_lines_and_columns (screenheight, screenwidth); -#endif + rl_point is the place in the string where the cursor is. Sometimes + this is the same as rl_end. - if (!term_xn) - screenwidth--; + Any command that is called interactively receives two arguments. + The first is a count: the numeric arg pased to this command. + The second is the key which invoked this command. +*/ - screenchars = screenwidth * screenheight; -} +/* **************************************************************** */ +/* */ +/* Movement Commands */ +/* */ +/* **************************************************************** */ -struct _tc_string { - char *tc_var; - char **tc_value; -}; +/* Note that if you `optimize' the display for these functions, you cannot + use said functions in other functions which do not do optimizing display. + I.e., you will have to update the data base for rl_redisplay, and you + might as well let rl_redisplay do that job. */ -/* This should be kept sorted, just in case we decide to change the - search algorithm to something smarter. */ -static struct _tc_string tc_strings[] = +/* Move forward COUNT characters. */ +int +rl_forward (count, key) + int count, key; { - "DC", &term_DC, - "IC", &term_IC, - "ce", &term_clreol, - "cl", &term_clrpag, - "cr", &term_cr, - "dc", &term_dc, - "ei", &term_ei, - "ic", &term_ic, - "im", &term_im, - "kd", &term_kd, - "kl", &term_kl, - "kr", &term_kr, - "ku", &term_ku, - "ks", &term_ks, - "ke", &term_ke, - "le", &term_backspace, - "mm", &term_mm, - "mo", &term_mo, -#if defined (HACK_TERMCAP_MOTION) - "nd", &term_forward_char, + if (count < 0) + rl_backward (-count, key); + else if (count > 0) + { + int end = rl_point + count; +#if defined (VI_MODE) + int lend = rl_end - (rl_editing_mode == vi_mode); +#else + int lend = rl_end; #endif - "pc", &term_pc, - "up", &term_up, - "vb", &visible_bell, -}; -#define NUM_TC_STRINGS (sizeof (tc_strings) / sizeof (struct _tc_string)) + if (end > lend) + { + rl_point = lend; + ding (); + } + else + rl_point = end; + } + return 0; +} -/* 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; +/* Move backward COUNT characters. */ +int +rl_backward (count, key) + int count, key; { - register int i; - - for (i = 0; i < NUM_TC_STRINGS; i++) - *(tc_strings[i].tc_value) = tgetstr (tc_strings[i].tc_var, bp); - tcap_initialized = 1; + if (count < 0) + rl_forward (-count, key); + else if (count > 0) + { + if (rl_point < count) + { + rl_point = 0; + ding (); + } + else + rl_point -= count; + } + return 0; } -static int -init_terminal_io (terminal_name) - char *terminal_name; +/* Move to the beginning of the line. */ +int +rl_beg_of_line (count, key) + int count, key; { -#if defined (__GO32__) - screenwidth = ScreenCols (); - screenheight = ScreenRows (); - screenchars = screenwidth * screenheight; - term_cr = "\r"; - term_im = term_ei = term_ic = term_IC = (char *)NULL; - term_up = term_dc = term_DC = visible_bell = (char *)NULL; - - /* Does the __GO32__ have a meta key? I don't know. */ - term_has_meta = 0; - term_mm = term_mo = (char *)NULL; - - /* It probably has arrow keys, but I don't know what they are. */ - term_ku = term_kd = term_kr = term_kl = (char *)NULL; - -#if defined (HACK_TERMCAP_MOTION) - term_forward_char = (char *)NULL; -#endif /* HACK_TERMCAP_MOTION */ - terminal_can_insert = term_xn = 0; - return; -#else /* !__GO32__ */ - - char *term, *buffer; - int tty; - Keymap xkeymap; + rl_point = 0; + return 0; +} - term = terminal_name ? terminal_name : getenv ("TERM"); +/* Move to the end of the line. */ +int +rl_end_of_line (count, key) + int count, key; +{ + rl_point = rl_end; + return 0; +} - if (!term_string_buffer) - term_string_buffer = xmalloc (2048); +/* Move forward a word. We do what Emacs does. */ +int +rl_forward_word (count, key) + int count, key; +{ + int c; - if (!term_buffer) - term_buffer = xmalloc (2048); + if (count < 0) + { + rl_backward_word (-count, key); + return 0; + } - buffer = term_string_buffer; + while (count) + { + if (rl_point == rl_end) + return 0; - term_clrpag = term_cr = term_clreol = (char *)NULL; + /* If we are not in a word, move forward until we are in one. + Then, move forward until we hit a non-alphabetic character. */ + c = the_line[rl_point]; + if (alphabetic (c) == 0) + { + while (++rl_point < rl_end) + { + c = the_line[rl_point]; + if (alphabetic (c)) + break; + } + } + if (rl_point == rl_end) + return 0; + while (++rl_point < rl_end) + { + c = the_line[rl_point]; + if (alphabetic (c) == 0) + break; + } + --count; + } + return 0; +} - if (!term) - term = "dumb"; +/* Move backward a word. We do what Emacs does. */ +int +rl_backward_word (count, key) + int count, key; +{ + int c; - if (tgetent (term_buffer, term) <= 0) + if (count < 0) { - dumb_term = 1; - screenwidth = 79; - screenheight = 24; - screenchars = 79 * 24; - term_cr = "\r"; - term_im = term_ei = term_ic = term_IC = (char *)NULL; - term_up = term_dc = term_DC = visible_bell = (char *)NULL; - term_ku = term_kd = term_kl = term_kr = (char *)NULL; -#if defined (HACK_TERMCAP_MOTION) - term_forward_char = (char *)NULL; -#endif - terminal_can_insert = 0; + rl_forward_word (-count, key); return 0; } - get_term_capabilities (&buffer); - - /* Set up the variables that the termcap library expects the application - to provide. */ - PC = term_pc ? *term_pc : 0; - BC = term_backspace; - UP = term_up; - - if (!term_cr) - term_cr = "\r"; + while (count) + { + if (!rl_point) + return 0; - if (rl_instream) - tty = fileno (rl_instream); - else - tty = 0; + /* Like rl_forward_word (), except that we look at the characters + just before point. */ - screenwidth = screenheight = 0; + c = the_line[rl_point - 1]; + if (alphabetic (c) == 0) + { + while (--rl_point) + { + c = the_line[rl_point - 1]; + if (alphabetic (c)) + break; + } + } - term_xn = tgetflag ("am") && tgetflag ("xn"); + while (rl_point) + { + c = the_line[rl_point - 1]; + if (alphabetic (c) == 0) + break; + else + --rl_point; + } + --count; + } + return 0; +} - _rl_set_screen_size (tty, 0); +/* Clear the current line. Numeric argument to C-l does this. */ +int +rl_refresh_line () +{ + int curr_line, nleft; - /* "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... */ - terminal_can_insert = (term_IC || term_im || term_ic); + /* Find out whether or not there might be invisible characters in the + editing buffer. */ + if (rl_display_prompt == rl_prompt) + nleft = _rl_last_c_pos - screenwidth - rl_visible_prompt_length; + else + nleft = _rl_last_c_pos - screenwidth; - /* 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) - { - term_mm = (char *)NULL; - term_mo = (char *)NULL; - } + if (nleft > 0) + curr_line = 1 + nleft / screenwidth; + else + curr_line = 0; - /* Attempt to find and bind the arrow keys. Do not override already - bound keys in an overzealous attempt, however. */ - xkeymap = _rl_keymap; + _rl_move_vert (curr_line); + _rl_move_cursor_relative (0, the_line); /* XXX is this right */ - _rl_keymap = emacs_standard_keymap; - _rl_bind_if_unbound (term_ku, rl_get_previous_history); - _rl_bind_if_unbound (term_kd, rl_get_next_history); - _rl_bind_if_unbound (term_kr, rl_forward); - _rl_bind_if_unbound (term_kl, rl_backward); +#if defined (__GO32__) + { + int row, col, width, row_start; -#if defined (VI_MODE) - _rl_keymap = vi_movement_keymap; - _rl_bind_if_unbound (term_ku, rl_get_previous_history); - _rl_bind_if_unbound (term_kd, rl_get_next_history); - _rl_bind_if_unbound (term_kr, rl_forward); - _rl_bind_if_unbound (term_kl, rl_backward); -#endif /* VI_MODE */ + ScreenGetCursor (&row, &col); + width = ScreenCols (); + row_start = ScreenPrimary + (row * width); + memset (row_start + col, 0, (width - col) * 2); + } +#else /* !__GO32__ */ + if (term_clreol) + tputs (term_clreol, 1, _rl_output_character_function); +#endif /* !__GO32__ */ - _rl_keymap = xkeymap; + rl_forced_update_display (); + rl_display_fixed = 1; -#endif /* !__GO32__ */ return 0; } -char * -rl_get_termcap (cap) - char *cap; +/* C-l typed to a line without quoting clears the screen, and then reprints + the prompt and the current input line. Given a numeric arg, redraw only + the current line. */ +int +rl_clear_screen (count, key) + int count, key; { - register int i; - - if (tcap_initialized == 0) - return ((char *)NULL); - for (i = 0; i < NUM_TC_STRINGS; i++) + if (rl_explicit_arg) { - if (tc_strings[i].tc_var[0] == cap[0] && strcmp (tc_strings[i].tc_var, cap) == 0) - return *(tc_strings[i].tc_value); + rl_refresh_line (); + return 0; } - return ((char *)NULL); -} - -/* A function for the use of tputs () */ -int -_rl_output_character_function (c) - int c; -{ - return putc (c, out_stream); -} - -/* Write COUNT characters from STRING to the output stream. */ -void -_rl_output_some_chars (string, count) - char *string; - int count; -{ - fwrite (string, 1, count, out_stream); -} - -/* Move the cursor back. */ -backspace (count) - int count; -{ - register int i; #if !defined (__GO32__) - if (term_backspace) - for (i = 0; i < count; i++) - tputs (term_backspace, 1, _rl_output_character_function); + if (term_clrpag) + tputs (term_clrpag, 1, _rl_output_character_function); else #endif /* !__GO32__ */ - for (i = 0; i < count; i++) - putc ('\b', out_stream); - return 0; -} + crlf (); + + rl_forced_update_display (); + rl_display_fixed = 1; -/* Move to the start of the next line. */ -crlf () -{ -#if defined (NEW_TTY_DRIVER) - tputs (term_cr, 1, _rl_output_character_function); -#endif /* NEW_TTY_DRIVER */ - putc ('\n', out_stream); return 0; } -rl_tty_status (count, key) - int count, key; +int +rl_arrow_keys (count, c) + int count, c; { -#if defined (TIOCSTAT) - ioctl (1, TIOCSTAT, (char *)0); - rl_refresh_line (); -#else - ding (); -#endif + int ch; + + ch = rl_read_key (); + + switch (_rl_to_upper (ch)) + { + case 'A': + rl_get_previous_history (count, ch); + break; + + case 'B': + rl_get_next_history (count, ch); + break; + + case 'C': + rl_forward (count, ch); + break; + + case 'D': + rl_backward (count, ch); + break; + + default: + ding (); + } return 0; } /* **************************************************************** */ /* */ -/* Utility Functions */ +/* Text commands */ /* */ /* **************************************************************** */ -/* Return 0 if C is not a member of the class of characters that belong - in words, or 1 if it is. */ - -int allow_pathname_alphabetic_chars = 0; -char *pathname_alphabetic_chars = "/-_=~.#$"; - +/* Insert the character C at the current location, moving point forward. */ int -alphabetic (c) - int c; +rl_insert (count, c) + int count, c; { - if (pure_alphabetic (c) || (digit_p (c))) - return (1); + register int i; + char *string; - if (allow_pathname_alphabetic_chars) - return (strchr (pathname_alphabetic_chars, c) != NULL); - else - return (0); -} + if (count <= 0) + return 0; -/* Ring the terminal bell. */ -int -ding () -{ - if (readline_echoing_p) + /* If we can optimize, then do it. But don't let people crash + readline because of extra large arguments. */ + if (count > 1 && count <= 1024) { -#if !defined (__GO32__) - switch (_rl_bell_preference) - { - case NO_BELL: - default: - break; - case VISIBLE_BELL: - if (visible_bell) - { - tputs (visible_bell, 1, _rl_output_character_function); - break; - } - /* FALLTHROUGH */ - case AUDIBLE_BELL: - fprintf (stderr, "\007"); - fflush (stderr); - break; - } -#else /* __GO32__ */ - fprintf (stderr, "\007"); - fflush (stderr); -#endif /* __GO32__ */ - return (0); - } - return (-1); -} - -/* How to abort things. */ -rl_abort (count, key) - int count, key; -{ - ding (); - rl_clear_message (); - rl_init_argument (); - rl_pending_input = 0; + string = xmalloc (1 + count); - defining_kbd_macro = 0; - while (executing_macro) - pop_executing_macro (); - - rl_last_func = (Function *)NULL; - longjmp (readline_top_level, 1); -} - -/* Return a copy of the string between FROM and TO. - FROM is inclusive, TO is not. */ -char * -rl_copy_text (from, to) - int from, to; -{ - register int length; - char *copy; - - /* Fix it if the caller is confused. */ - if (from > to) - { - int t = from; - from = to; - to = t; - } - - length = to - from; - copy = xmalloc (1 + length); - strncpy (copy, the_line + from, length); - copy[length] = '\0'; - return (copy); -} - -/* Increase the size of RL_LINE_BUFFER until it has enough space to hold - LEN characters. */ -void -rl_extend_line_buffer (len) - int len; -{ - while (len >= rl_line_buffer_len) - { - rl_line_buffer_len += DEFAULT_BUFFER_SIZE; - rl_line_buffer = xrealloc (rl_line_buffer, rl_line_buffer_len); - } - - the_line = rl_line_buffer; -} - - -/* **************************************************************** */ -/* */ -/* Insert and Delete */ -/* */ -/* **************************************************************** */ - -/* Insert a string of text into the line at point. This is the only - way that you should do insertion. rl_insert () calls this - function. */ -rl_insert_text (string) - char *string; -{ - register int i, l = strlen (string); - - if (rl_end + l >= rl_line_buffer_len) - rl_extend_line_buffer (rl_end + l); - - for (i = rl_end; i >= rl_point; i--) - the_line[i + l] = the_line[i]; - strncpy (the_line + rl_point, string, l); - - /* Remember how to undo this if we aren't undoing something. */ - if (!doing_an_undo) - { - /* If possible and desirable, concatenate the undos. */ - if ((l == 1) && - rl_undo_list && - (rl_undo_list->what == UNDO_INSERT) && - (rl_undo_list->end == rl_point) && - (rl_undo_list->end - rl_undo_list->start < 20)) - rl_undo_list->end++; - else - rl_add_undo (UNDO_INSERT, rl_point, rl_point + l, (char *)NULL); - } - rl_point += l; - rl_end += l; - the_line[rl_end] = '\0'; - return l; -} - -/* Delete the string between FROM and TO. FROM is - inclusive, TO is not. */ -rl_delete_text (from, to) - int from, to; -{ - register char *text; - register int diff, i; - - /* Fix it if the caller is confused. */ - if (from > to) - { - int t = from; - from = to; - to = t; - } - - if (to > rl_end) - to = rl_end; - - text = rl_copy_text (from, to); - - /* Some versions of strncpy() can't handle overlapping arguments. */ - diff = to - from; - for (i = from; i < rl_end - diff; i++) - the_line[i] = the_line[i + diff]; - - /* Remember how to undo this delete. */ - if (!doing_an_undo) - rl_add_undo (UNDO_DELETE, from, to, text); - else - free (text); - - rl_end -= diff; - the_line[rl_end] = '\0'; - return (diff); -} - - -/* **************************************************************** */ -/* */ -/* Readline character functions */ -/* */ -/* **************************************************************** */ - -/* This is not a gap editor, just a stupid line input routine. No hair - is involved in writing any of the functions, and none should be. */ - -/* Note that: - - rl_end is the place in the string that we would place '\0'; - i.e., it is always safe to place '\0' there. - - rl_point is the place in the string where the cursor is. Sometimes - this is the same as rl_end. - - Any command that is called interactively receives two arguments. - The first is a count: the numeric arg pased to this command. - The second is the key which invoked this command. -*/ - - -/* **************************************************************** */ -/* */ -/* Movement Commands */ -/* */ -/* **************************************************************** */ - -/* Note that if you `optimize' the display for these functions, you cannot - use said functions in other functions which do not do optimizing display. - I.e., you will have to update the data base for rl_redisplay, and you - might as well let rl_redisplay do that job. */ - -/* Move forward COUNT characters. */ -rl_forward (count, key) - int count, key; -{ - if (count < 0) - rl_backward (-count); - else if (count > 0) - { - int end = rl_point + count; -#if defined (VI_MODE) - int lend = rl_end - (rl_editing_mode == vi_mode); -#else - int lend = rl_end; -#endif - - if (end > lend) - { - rl_point = lend; - ding (); - } - else - rl_point = end; - } - return 0; -} - -/* Move backward COUNT characters. */ -rl_backward (count, key) - int count, key; -{ - if (count < 0) - rl_forward (-count); - else if (count > 0) - { - if (rl_point < count) - { - rl_point = 0; - ding (); - } - else - rl_point -= count; - } - return 0; -} - -/* Move to the beginning of the line. */ -rl_beg_of_line (count, key) - int count, key; -{ - rl_point = 0; - return 0; -} - -/* Move to the end of the line. */ -rl_end_of_line (count, key) - int count, key; -{ - rl_point = rl_end; - return 0; -} - -/* Move forward a word. We do what Emacs does. */ -rl_forward_word (count, key) - int count, key; -{ - int c; - - if (count < 0) - { - rl_backward_word (-count); - return 0; - } - - while (count) - { - if (rl_point == rl_end) - return 0; - - /* If we are not in a word, move forward until we are in one. - Then, move forward until we hit a non-alphabetic character. */ - c = the_line[rl_point]; - if (!alphabetic (c)) - { - while (++rl_point < rl_end) - { - c = the_line[rl_point]; - if (alphabetic (c)) - break; - } - } - if (rl_point == rl_end) - return 0; - while (++rl_point < rl_end) - { - c = the_line[rl_point]; - if (!alphabetic (c)) - break; - } - --count; - } - return 0; -} - -/* Move backward a word. We do what Emacs does. */ -rl_backward_word (count, key) - int count, key; -{ - int c; - - if (count < 0) - { - rl_forward_word (-count); - return 0; - } - - while (count) - { - if (!rl_point) - return 0; - - /* Like rl_forward_word (), except that we look at the characters - just before point. */ - - c = the_line[rl_point - 1]; - if (!alphabetic (c)) - { - while (--rl_point) - { - c = the_line[rl_point - 1]; - if (alphabetic (c)) - break; - } - } - - while (rl_point) - { - c = the_line[rl_point - 1]; - if (!alphabetic (c)) - break; - else - --rl_point; - } - --count; - } - return 0; -} - -/* Clear the current line. Numeric argument to C-l does this. */ -rl_refresh_line () -{ - int curr_line, nleft; - - /* Find out whether or not there might be invisible characters in the - editing buffer. */ - if (rl_display_prompt == rl_prompt) - nleft = _rl_last_c_pos - screenwidth - rl_visible_prompt_length; - else - nleft = _rl_last_c_pos - screenwidth; - - if (nleft > 0) - curr_line = 1 + nleft / screenwidth; - else - curr_line = 0; - - _rl_move_vert (curr_line); - _rl_move_cursor_relative (0, the_line); /* XXX is this right */ - -#if defined (__GO32__) - { - int row, col, width, row_start; - - ScreenGetCursor (&row, &col); - width = ScreenCols (); - row_start = ScreenPrimary + (row * width); - memset (row_start + col, 0, (width - col) * 2); - } -#else /* !__GO32__ */ - if (term_clreol) - tputs (term_clreol, 1, _rl_output_character_function); -#endif /* !__GO32__ */ - - rl_forced_update_display (); - rl_display_fixed = 1; - - return 0; -} - -/* C-l typed to a line without quoting clears the screen, and then reprints - the prompt and the current input line. Given a numeric arg, redraw only - the current line. */ -rl_clear_screen (count, key) - int count, key; -{ - if (rl_explicit_arg) - { - rl_refresh_line (); - return 0; - } - -#if !defined (__GO32__) - if (term_clrpag) - tputs (term_clrpag, 1, _rl_output_character_function); - else -#endif /* !__GO32__ */ - crlf (); - - rl_forced_update_display (); - rl_display_fixed = 1; - - return 0; -} - -rl_arrow_keys (count, c) - int count, c; -{ - int ch; - - ch = rl_read_key (); - - switch (to_upper (ch)) - { - case 'A': - rl_get_previous_history (count); - break; - - case 'B': - rl_get_next_history (count); - break; - - case 'C': - rl_forward (count); - break; - - case 'D': - rl_backward (count); - break; - - default: - ding (); - } - return 0; -} - - -/* **************************************************************** */ -/* */ -/* Text commands */ -/* */ -/* **************************************************************** */ - -/* Insert the character C at the current location, moving point forward. */ -rl_insert (count, c) - int count, c; -{ - register int i; - char *string; - - if (count <= 0) - return 0; - - /* If we can optimize, then do it. But don't let people crash - readline because of extra large arguments. */ - if (count > 1 && count < 1024) - { - string = xmalloc (1 + count); - - for (i = 0; i < count; i++) - string[i] = c; - - string[i] = '\0'; - rl_insert_text (string); - free (string); - - return 0; - } - - if (count > 1024) - { - int decreaser; - char str[1024+1]; - - for (i = 0; i < 1024; i++) - str[i] = c; - - while (count) - { - decreaser = (count > 1024 ? 1024 : count); - str[decreaser] = '\0'; - rl_insert_text (str); - count -= decreaser; - } - - return 0; - } - - /* We are inserting a single character. - If there is pending input, then make a string of all of the - pending characters that are bound to rl_insert, and insert - them all. */ - if (any_typein) - { - int key = 0, t; - - i = 0; - string = xmalloc (ibuffer_len + 1); - string[i++] = 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); - } - else - { - /* Inserting a single character. */ - char str[2]; - - str[1] = '\0'; - str[0] = c; - rl_insert_text (str); - } - return 0; -} - -/* Insert the next typed character verbatim. */ -rl_quoted_insert (count, key) - int count, key; -{ - int c; - - c = rl_read_key (); - return (rl_insert (count, c)); -} - -/* Insert a tab character. */ -rl_tab_insert (count, key) - int count, key; -{ - return (rl_insert (count, '\t')); -} - -/* What to do when a NEWLINE is pressed. We accept the whole line. - KEY is the key that invoked this command. I guess it could have - meaning in the future. */ -rl_newline (count, key) - int count, key; -{ - rl_done = 1; - -#if defined (VI_MODE) - _rl_vi_done_inserting (); - _rl_vi_reset_last (); - -#endif /* VI_MODE */ - - if (readline_echoing_p) - _rl_update_final (); - return 0; -} - -rl_clean_up_for_exit () -{ - if (readline_echoing_p) - { - _rl_move_vert (_rl_vis_botlin); - _rl_vis_botlin = 0; - fflush (out_stream); - rl_restart_output (); - } - return 0; -} - -/* What to do for some uppercase characters, like meta characters, - and some characters appearing in emacs_ctlx_keymap. This function - is just a stub, you bind keys to it and the code in _rl_dispatch () - is special cased. */ -rl_do_lowercase_version (ignore1, ignore2) - int ignore1, ignore2; -{ - return 0; -} - -/* Rubout the character behind point. */ -rl_rubout (count, key) - int count, key; -{ - if (count < 0) - { - rl_delete (-count); - return 0; - } - - if (!rl_point) - { - ding (); - return -1; - } - - if (count > 1 || rl_explicit_arg) - { - int orig_point = rl_point; - rl_backward (count); - rl_kill_text (orig_point, rl_point); - } - else - { - int c = the_line[--rl_point]; - rl_delete_text (rl_point, rl_point + 1); - - if (rl_point == rl_end && isprint (c) && _rl_last_c_pos) - { - int l; - l = rl_character_len (c, rl_point); - _rl_erase_at_end_of_line (l); - } - } - return 0; -} - -/* Delete the character under the cursor. Given a numeric argument, - kill that many characters instead. */ -rl_delete (count, invoking_key) - int count, invoking_key; -{ - if (count < 0) - { - return (rl_rubout (-count)); - } - - if (rl_point == rl_end) - { - ding (); - return -1; - } - - if (count > 1 || rl_explicit_arg) - { - int orig_point = rl_point; - rl_forward (count); - rl_kill_text (orig_point, rl_point); - rl_point = orig_point; - return 0; - } - else - return (rl_delete_text (rl_point, rl_point + 1)); - -} - -/* Delete all spaces and tabs around point. */ -rl_delete_horizontal_space (count, ignore) - int count, ignore; -{ - int start = rl_point; - - while (rl_point && whitespace (the_line[rl_point - 1])) - rl_point--; - - start = rl_point; - - while (rl_point < rl_end && whitespace (the_line[rl_point])) - rl_point++; - - if (start != rl_point) - { - rl_delete_text (start, rl_point); - rl_point = start; - } - return 0; -} - - -/* **************************************************************** */ -/* */ -/* Kill commands */ -/* */ -/* **************************************************************** */ - -/* The next two functions mimic unix line editing behaviour, except they - save the deleted text on the kill ring. This is safer than not saving - it, and since we have a ring, nobody should get screwed. */ - -/* This does what C-w does in Unix. We can't prevent people from - using behaviour that they expect. */ -rl_unix_word_rubout (count, key) - int count, key; -{ - if (!rl_point) - ding (); - else - { - int orig_point = rl_point; - if (count <= 0) - count = 1; - - while (count--) - { - while (rl_point && whitespace (the_line[rl_point - 1])) - rl_point--; - - while (rl_point && !whitespace (the_line[rl_point - 1])) - rl_point--; - } - - rl_kill_text (orig_point, rl_point); - } - return 0; -} - -/* Here is C-u doing what Unix does. You don't *have* to use these - key-bindings. We have a choice of killing the entire line, or - killing from where we are to the start of the line. We choose the - latter, because if you are a Unix weenie, then you haven't backspaced - into the line at all, and if you aren't, then you know what you are - doing. */ -rl_unix_line_discard (count, key) - int count, key; -{ - if (!rl_point) - ding (); - else - { - rl_kill_text (rl_point, 0); - rl_point = 0; - } - return 0; -} - - -/* **************************************************************** */ -/* */ -/* Commands For Typos */ -/* */ -/* **************************************************************** */ - -/* Random and interesting things in here. */ - -/* **************************************************************** */ -/* */ -/* Changing Case */ -/* */ -/* **************************************************************** */ - -/* The three kinds of things that we know how to do. */ -#define UpCase 1 -#define DownCase 2 -#define CapCase 3 - -static int rl_change_case (); - -/* Uppercase the word at point. */ -rl_upcase_word (count, key) - int count, key; -{ - return (rl_change_case (count, UpCase)); -} - -/* Lowercase the word at point. */ -rl_downcase_word (count, key) - int count, key; -{ - return (rl_change_case (count, DownCase)); -} - -/* Upcase the first letter, downcase the rest. */ -rl_capitalize_word (count, key) - int count, key; -{ - return (rl_change_case (count, CapCase)); -} - -/* The meaty function. - Change the case of COUNT words, performing OP on them. - OP is one of UpCase, DownCase, or CapCase. - If a negative argument is given, leave point where it started, - otherwise, leave it where it moves to. */ -static int -rl_change_case (count, op) - int count, op; -{ - register int start = rl_point, end; - int state = 0; - - rl_forward_word (count); - end = rl_point; - - if (count < 0) - { - int temp = start; - start = end; - end = temp; - } - - /* We are going to modify some text, so let's prepare to undo it. */ - rl_modifying (start, end); - - for (; start < end; start++) - { - switch (op) - { - case UpCase: - the_line[start] = to_upper (the_line[start]); - break; - - case DownCase: - the_line[start] = to_lower (the_line[start]); - break; - - case CapCase: - if (state == 0) - { - the_line[start] = to_upper (the_line[start]); - state = 1; - } - else - { - the_line[start] = to_lower (the_line[start]); - } - if (!pure_alphabetic (the_line[start])) - state = 0; - break; - - default: - ding (); - return -1; - } - } - rl_point = end; - return 0; -} - -/* **************************************************************** */ -/* */ -/* Transposition */ -/* */ -/* **************************************************************** */ - -/* Transpose the words at point. */ -rl_transpose_words (count, key) - int count, key; -{ - char *word1, *word2; - int w1_beg, w1_end, w2_beg, w2_end; - int orig_point = rl_point; - - if (!count) - return 0; - - /* Find the two words. */ - rl_forward_word (count); - w2_end = rl_point; - rl_backward_word (1); - w2_beg = rl_point; - rl_backward_word (count); - w1_beg = rl_point; - rl_forward_word (1); - w1_end = rl_point; - - /* Do some check to make sure that there really are two words. */ - if ((w1_beg == w2_beg) || (w2_beg < w1_end)) - { - ding (); - rl_point = orig_point; - return -1; - } - - /* Get the text of the words. */ - word1 = rl_copy_text (w1_beg, w1_end); - word2 = rl_copy_text (w2_beg, w2_end); - - /* We are about to do many insertions and deletions. Remember them - as one operation. */ - rl_begin_undo_group (); - - /* Do the stuff at word2 first, so that we don't have to worry - about word1 moving. */ - rl_point = w2_beg; - rl_delete_text (w2_beg, w2_end); - rl_insert_text (word1); - - rl_point = w1_beg; - rl_delete_text (w1_beg, w1_end); - rl_insert_text (word2); - - /* This is exactly correct since the text before this point has not - changed in length. */ - rl_point = w2_end; - - /* I think that does it. */ - rl_end_undo_group (); - free (word1); - free (word2); - - return 0; -} - -/* Transpose the characters at point. If point is at the end of the line, - then transpose the characters before point. */ -rl_transpose_chars (count, key) - int count, key; -{ - char dummy[2]; - - if (!count) - return 0; - - if (!rl_point || rl_end < 2) - { - ding (); - return -1; - } - - rl_begin_undo_group (); - - if (rl_point == rl_end) - { - --rl_point; - count = 1; - } - rl_point--; - - dummy[0] = the_line[rl_point]; - dummy[1] = '\0'; - - rl_delete_text (rl_point, rl_point + 1); - - rl_point += count; - if (rl_point > rl_end) - rl_point = rl_end; - else if (rl_point < 0) - rl_point = 0; - rl_insert_text (dummy); - - rl_end_undo_group (); - return 0; -} - -/* **************************************************************** */ -/* */ -/* Undo, and Undoing */ -/* */ -/* **************************************************************** */ - -/* The current undo list for THE_LINE. */ -UNDO_LIST *rl_undo_list = (UNDO_LIST *)NULL; - -/* Remember how to undo something. Concatenate some undos if that - seems right. */ -void -rl_add_undo (what, start, end, text) - enum undo_code what; - int start, end; - char *text; -{ - UNDO_LIST *temp = (UNDO_LIST *)xmalloc (sizeof (UNDO_LIST)); - temp->what = what; - temp->start = start; - temp->end = end; - temp->text = text; - temp->next = rl_undo_list; - rl_undo_list = temp; -} - -/* Free the existing undo list. */ -void -free_undo_list () -{ - while (rl_undo_list) - { - UNDO_LIST *release = rl_undo_list; - rl_undo_list = rl_undo_list->next; - - if (release->what == UNDO_DELETE) - free (release->text); - - free (release); - } - rl_undo_list = (UNDO_LIST *)NULL; -} - -/* Undo the next thing in the list. Return 0 if there - is nothing to undo, or non-zero if there was. */ -int -rl_do_undo () -{ - UNDO_LIST *release; - int waiting_for_begin = 0; - -undo_thing: - if (!rl_undo_list) - return (0); - - doing_an_undo = 1; - - switch (rl_undo_list->what) { - - /* Undoing deletes means inserting some text. */ - case UNDO_DELETE: - rl_point = rl_undo_list->start; - rl_insert_text (rl_undo_list->text); - free (rl_undo_list->text); - break; - - /* Undoing inserts means deleting some text. */ - case UNDO_INSERT: - rl_delete_text (rl_undo_list->start, rl_undo_list->end); - rl_point = rl_undo_list->start; - break; - - /* Undoing an END means undoing everything 'til we get to - a BEGIN. */ - case UNDO_END: - waiting_for_begin++; - break; - - /* Undoing a BEGIN means that we are done with this group. */ - case UNDO_BEGIN: - if (waiting_for_begin) - waiting_for_begin--; - else - ding (); - break; - } - - doing_an_undo = 0; - - release = rl_undo_list; - rl_undo_list = rl_undo_list->next; - free (release); - - if (waiting_for_begin) - goto undo_thing; - - return (1); -} - -/* Begin a group. Subsequent undos are undone as an atomic operation. */ -int -rl_begin_undo_group () -{ - rl_add_undo (UNDO_BEGIN, 0, 0, 0); - return 0; -} - -/* End an undo group started with rl_begin_undo_group (). */ -int -rl_end_undo_group () -{ - rl_add_undo (UNDO_END, 0, 0, 0); - return 0; -} - -/* Save an undo entry for the text from START to END. */ -rl_modifying (start, end) - int start, end; -{ - if (start > end) - { - int t = start; - start = end; - end = t; - } - - if (start != end) - { - char *temp = rl_copy_text (start, end); - rl_begin_undo_group (); - rl_add_undo (UNDO_DELETE, start, end, temp); - rl_add_undo (UNDO_INSERT, start, end, (char *)NULL); - rl_end_undo_group (); - } - return 0; -} - -/* Revert the current line to its previous state. */ -int -rl_revert_line (count, key) - int count, key; -{ - if (!rl_undo_list) - ding (); - else - { - while (rl_undo_list) - rl_do_undo (); - } - return 0; -} - -/* Do some undoing of things that were done. */ -int -rl_undo_command (count, key) - int count, key; -{ - if (count < 0) - return 0; /* Nothing to do. */ - - while (count) - { - if (rl_do_undo ()) - count--; - else - { - ding (); - break; - } - } - return 0; -} - -/* **************************************************************** */ -/* */ -/* History Utilities */ -/* */ -/* **************************************************************** */ - -/* We already have a history library, and that is what we use to control - the history features of readline. However, this is our local interface - to the history mechanism. */ - -/* While we are editing the history, this is the saved - version of the original line. */ -HIST_ENTRY *saved_line_for_history = (HIST_ENTRY *)NULL; - -/* Set the history pointer back to the last entry in the history. */ -static void -start_using_history () -{ - using_history (); - if (saved_line_for_history) - _rl_free_history_entry (saved_line_for_history); - - saved_line_for_history = (HIST_ENTRY *)NULL; -} - -/* Free the contents (and containing structure) of a HIST_ENTRY. */ -void -_rl_free_history_entry (entry) - HIST_ENTRY *entry; -{ - if (!entry) - return; - if (entry->line) - free (entry->line); - free (entry); -} + for (i = 0; i < count; i++) + string[i] = c; -/* Perhaps put back the current line if it has changed. */ -maybe_replace_line () -{ - HIST_ENTRY *temp = current_history (); + string[i] = '\0'; + rl_insert_text (string); + free (string); - /* If the current line has changed, save the changes. */ - if (temp && ((UNDO_LIST *)(temp->data) != rl_undo_list)) - { - temp = replace_history_entry (where_history (), the_line, rl_undo_list); - free (temp->line); - free (temp); + return 0; } - return 0; -} -/* Put back the saved_line_for_history if there is one. */ -maybe_unsave_line () -{ - if (saved_line_for_history) + if (count > 1024) { - int line_len; + int decreaser; + char str[1024+1]; - line_len = strlen (saved_line_for_history->line); + for (i = 0; i < 1024; i++) + str[i] = c; - if (line_len >= rl_line_buffer_len) - rl_extend_line_buffer (line_len); + while (count) + { + decreaser = (count > 1024 ? 1024 : count); + str[decreaser] = '\0'; + rl_insert_text (str); + count -= decreaser; + } - strcpy (the_line, saved_line_for_history->line); - rl_undo_list = (UNDO_LIST *)saved_line_for_history->data; - _rl_free_history_entry (saved_line_for_history); - saved_line_for_history = (HIST_ENTRY *)NULL; - rl_end = rl_point = strlen (the_line); + return 0; } - else - ding (); - return 0; -} -/* Save the current line in saved_line_for_history. */ -maybe_save_line () -{ - if (!saved_line_for_history) + /* We are inserting a single character. + If there is pending input, then make a string of all of the + pending characters that are bound to rl_insert, and insert + them all. */ + if (_rl_any_typein ()) + _rl_insert_typein (c); + else { - saved_line_for_history = (HIST_ENTRY *)xmalloc (sizeof (HIST_ENTRY)); - saved_line_for_history->line = savestring (the_line); - saved_line_for_history->data = (char *)rl_undo_list; + /* Inserting a single character. */ + char str[2]; + + str[1] = '\0'; + str[0] = c; + rl_insert_text (str); } return 0; } - -/* **************************************************************** */ -/* */ -/* History Commands */ -/* */ -/* **************************************************************** */ -/* Meta-< goes to the start of the history. */ -rl_beginning_of_history (count, key) +/* Insert the next typed character verbatim. */ +int +rl_quoted_insert (count, key) int count, key; { - return (rl_get_previous_history (1 + where_history ())); + int c; + + c = rl_read_key (); + return (rl_insert (count, c)); } -/* Meta-> goes to the end of the history. (The current line). */ -rl_end_of_history (count, key) +/* Insert a tab character. */ +int +rl_tab_insert (count, key) int count, key; { - maybe_replace_line (); - using_history (); - maybe_unsave_line (); - return 0; + return (rl_insert (count, '\t')); } -/* Move down to the next history line. */ -rl_get_next_history (count, key) +/* What to do when a NEWLINE is pressed. We accept the whole line. + KEY is the key that invoked this command. I guess it could have + meaning in the future. */ +int +rl_newline (count, key) int count, key; { - HIST_ENTRY *temp = (HIST_ENTRY *)NULL; + rl_done = 1; - if (count < 0) - return (rl_get_previous_history (-count)); +#if defined (VI_MODE) + _rl_vi_done_inserting (); + _rl_vi_reset_last (); +#endif /* VI_MODE */ - if (!count) - return 0; + if (readline_echoing_p) + _rl_update_final (); + return 0; +} - maybe_replace_line (); +/* What to do for some uppercase characters, like meta characters, + and some characters appearing in emacs_ctlx_keymap. This function + is just a stub, you bind keys to it and the code in _rl_dispatch () + is special cased. */ +int +rl_do_lowercase_version (ignore1, ignore2) + int ignore1, ignore2; +{ + return 0; +} - while (count) +/* Rubout the character behind point. */ +int +rl_rubout (count, key) + int count, key; +{ + if (count < 0) { - temp = next_history (); - if (!temp) - break; - --count; + rl_delete (-count, key); + return 0; } - if (!temp) - maybe_unsave_line (); - else + if (!rl_point) { - int line_len; - - line_len = strlen (temp->line); + ding (); + return -1; + } - if (line_len >= rl_line_buffer_len) - rl_extend_line_buffer (line_len); + if (count > 1 || rl_explicit_arg) + { + int orig_point = rl_point; + rl_backward (count, key); + rl_kill_text (orig_point, rl_point); + } + else + { + int c = the_line[--rl_point]; + rl_delete_text (rl_point, rl_point + 1); - strcpy (the_line, temp->line); - rl_undo_list = (UNDO_LIST *)temp->data; - rl_end = rl_point = strlen (the_line); -#if defined (VI_MODE) - if (rl_editing_mode == vi_mode) - rl_point = 0; -#endif /* VI_MODE */ + if (rl_point == rl_end && isprint (c) && _rl_last_c_pos) + { + int l; + l = rl_character_len (c, rl_point); + _rl_erase_at_end_of_line (l); + } } return 0; } -/* Get the previous item out of our interactive history, making it the current - line. If there is no previous history, just ding. */ -rl_get_previous_history (count, key) +/* Delete the character under the cursor. Given a numeric argument, + kill that many characters instead. */ +int +rl_delete (count, key) int count, key; { - HIST_ENTRY *old_temp = (HIST_ENTRY *)NULL; - HIST_ENTRY *temp = (HIST_ENTRY *)NULL; - if (count < 0) - return (rl_get_next_history (-count)); - - if (!count) - return 0; - - /* If we don't have a line saved, then save this one. */ - maybe_save_line (); + return (rl_rubout (-count, key)); - /* If the current line has changed, save the changes. */ - maybe_replace_line (); - - while (count) + if (rl_point == rl_end) { - temp = previous_history (); - if (!temp) - break; - else - old_temp = temp; - --count; + ding (); + return -1; } - /* If there was a large argument, and we moved back to the start of the - history, that is not an error. So use the last value found. */ - if (!temp && old_temp) - temp = old_temp; - - if (!temp) - ding (); - else + if (count > 1 || rl_explicit_arg) { - int line_len; - - line_len = strlen (temp->line); - - if (line_len >= rl_line_buffer_len) - rl_extend_line_buffer (line_len); - - strcpy (the_line, temp->line); - rl_undo_list = (UNDO_LIST *)temp->data; - rl_end = rl_point = line_len; - -#if defined (VI_MODE) - if (rl_editing_mode == vi_mode) - rl_point = 0; -#endif /* VI_MODE */ + int orig_point = rl_point; + rl_forward (count, key); + rl_kill_text (orig_point, rl_point); + rl_point = orig_point; + return 0; } - return 0; + else + return (rl_delete_text (rl_point, rl_point + 1)); + } -/* Make C be the next command to be executed. */ -rl_execute_next (c) - int c; +/* Delete all spaces and tabs around point. */ +int +rl_delete_horizontal_space (count, ignore) + int count, ignore; { - rl_pending_input = c; - return 0; -} - -/* **************************************************************** */ -/* */ -/* The Mark and the Region. */ -/* */ -/* **************************************************************** */ + int start = rl_point; -/* Set the mark at POSITION. */ -rl_set_mark (position) - int position; -{ - if (position > rl_end) - return -1; + while (rl_point && whitespace (the_line[rl_point - 1])) + rl_point--; - rl_mark = position; - return 0; -} + start = rl_point; -/* Exchange the position of mark and point. */ -rl_exchange_mark_and_point (count, key) - int count, key; -{ - if (rl_mark > rl_end) - rl_mark = -1; + while (rl_point < rl_end && whitespace (the_line[rl_point])) + rl_point++; - if (rl_mark == -1) - { - ding (); - return -1; - } - else + if (start != rl_point) { - int temp = rl_point; - - rl_point = rl_mark; - rl_mark = temp; + rl_delete_text (start, rl_point); + rl_point = start; } return 0; } - +#ifndef RL_COMMENT_BEGIN_DEFAULT +#define RL_COMMENT_BEGIN_DEFAULT "#" +#endif + +/* Turn the current line into a comment in shell history. + A K*rn shell style function. */ +int +rl_insert_comment (count, key) + int count, key; +{ + rl_beg_of_line (1, key); + rl_insert_text (_rl_comment_begin ? _rl_comment_begin + : RL_COMMENT_BEGIN_DEFAULT); + (*rl_redisplay_function) (); + rl_newline (1, '\n'); + return (0); +} + /* **************************************************************** */ /* */ -/* Killing Mechanism */ +/* Changing Case */ /* */ /* **************************************************************** */ -/* What we assume for a max number of kills. */ -#define DEFAULT_MAX_KILLS 10 - -/* The real variable to look at to find out when to flush kills. */ -int rl_max_kills = DEFAULT_MAX_KILLS; +/* The three kinds of things that we know how to do. */ +#define UpCase 1 +#define DownCase 2 +#define CapCase 3 -/* Where to store killed text. */ -char **rl_kill_ring = (char **)NULL; +static int rl_change_case (); -/* Where we are in the kill ring. */ -int rl_kill_index = 0; +/* Uppercase the word at point. */ +int +rl_upcase_word (count, key) + int count, key; +{ + return (rl_change_case (count, UpCase)); +} -/* How many slots we have in the kill ring. */ -int rl_kill_ring_length = 0; +/* Lowercase the word at point. */ +int +rl_downcase_word (count, key) + int count, key; +{ + return (rl_change_case (count, DownCase)); +} -/* How to say that you only want to save a certain amount - of kill material. */ -rl_set_retained_kills (num) - int num; +/* Upcase the first letter, downcase the rest. */ +int +rl_capitalize_word (count, key) + int count, key; { - return 0; + return (rl_change_case (count, CapCase)); } -/* The way to kill something. This appends or prepends to the last - kill, if the last command was a kill command. if FROM is less - than TO, then the text is appended, otherwise prepended. If the - last command was not a kill command, then a new slot is made for - this kill. */ -rl_kill_text (from, to) - int from, to; +/* The meaty function. + Change the case of COUNT words, performing OP on them. + OP is one of UpCase, DownCase, or CapCase. + If a negative argument is given, leave point where it started, + otherwise, leave it where it moves to. */ +static int +rl_change_case (count, op) + int count, op; { - int slot; - char *text; + register int start, end; + int inword, c; - /* Is there anything to kill? */ - if (from == to) - { - last_command_was_kill++; - return 0; - } + start = rl_point; + rl_forward_word (count, 0); + end = rl_point; - text = rl_copy_text (from, to); + if (count < 0) + SWAP (start, end); - /* Delete the copied text from the line. */ - rl_delete_text (from, to); + /* We are going to modify some text, so let's prepare to undo it. */ + rl_modifying (start, end); - /* First, find the slot to work with. */ - if (!last_command_was_kill) + for (inword = 0; start < end; start++) { - /* Get a new slot. */ - if (!rl_kill_ring) - { - /* If we don't have any defined, then make one. */ - rl_kill_ring = (char **) - xmalloc (((rl_kill_ring_length = 1) + 1) * sizeof (char *)); - rl_kill_ring[slot = 0] = (char *)NULL; - } - else + c = the_line[start]; + switch (op) { - /* We have to add a new slot on the end, unless we have - exceeded the max limit for remembering kills. */ - slot = rl_kill_ring_length; - if (slot == rl_max_kills) - { - register int i; - free (rl_kill_ring[0]); - for (i = 0; i < slot; i++) - rl_kill_ring[i] = rl_kill_ring[i + 1]; - } - else - { - slot = rl_kill_ring_length += 1; - rl_kill_ring = (char **)xrealloc (rl_kill_ring, slot * sizeof (char *)); - } - rl_kill_ring[--slot] = (char *)NULL; - } - } - else - slot = rl_kill_ring_length - 1; + case UpCase: + the_line[start] = _rl_to_upper (c); + break; - /* If the last command was a kill, prepend or append. */ - if (last_command_was_kill && rl_editing_mode != vi_mode) - { - char *old = rl_kill_ring[slot]; - char *new = xmalloc (1 + strlen (old) + strlen (text)); + case DownCase: + the_line[start] = _rl_to_lower (c); + break; - if (from < to) - { - strcpy (new, old); - strcat (new, text); - } - else - { - strcpy (new, text); - strcat (new, old); + case CapCase: + the_line[start] = (inword == 0) ? _rl_to_upper (c) : _rl_to_lower (c); + inword = alphabetic (the_line[start]); + break; + + default: + ding (); + return -1; } - free (old); - free (text); - rl_kill_ring[slot] = new; } - else - { - rl_kill_ring[slot] = text; - } - rl_kill_index = slot; - last_command_was_kill++; + rl_point = end; return 0; } -/* Now REMEMBER! In order to do prepending or appending correctly, kill - commands always make rl_point's original position be the FROM argument, - and rl_point's extent be the TO argument. */ - /* **************************************************************** */ /* */ -/* Killing Commands */ +/* Transposition */ /* */ /* **************************************************************** */ -/* Delete the word at point, saving the text in the kill ring. */ -rl_kill_word (count, key) +/* Transpose the words at point. */ +int +rl_transpose_words (count, key) int count, key; { + char *word1, *word2; + int w1_beg, w1_end, w2_beg, w2_end; int orig_point = rl_point; - if (count < 0) - return (rl_backward_kill_word (-count)); - else - { - rl_forward_word (count); + if (!count) + return 0; - if (rl_point != orig_point) - rl_kill_text (orig_point, rl_point); + /* Find the two words. */ + rl_forward_word (count, key); + w2_end = rl_point; + rl_backward_word (1, key); + w2_beg = rl_point; + rl_backward_word (count, key); + w1_beg = rl_point; + rl_forward_word (1, key); + w1_end = rl_point; + /* Do some check to make sure that there really are two words. */ + if ((w1_beg == w2_beg) || (w2_beg < w1_end)) + { + ding (); rl_point = orig_point; + return -1; } - return 0; -} -/* Rubout the word before point, placing it on the kill ring. */ -rl_backward_kill_word (count, ignore) - int count, ignore; -{ - int orig_point = rl_point; - - if (count < 0) - return (rl_kill_word (-count)); - else - { - rl_backward_word (count); - - if (rl_point != orig_point) - rl_kill_text (orig_point, rl_point); - } - return 0; -} + /* Get the text of the words. */ + word1 = rl_copy_text (w1_beg, w1_end); + word2 = rl_copy_text (w2_beg, w2_end); -/* Kill from here to the end of the line. If DIRECTION is negative, kill - back to the line start instead. */ -rl_kill_line (direction, ignore) - int direction, ignore; -{ - int orig_point = rl_point; + /* We are about to do many insertions and deletions. Remember them + as one operation. */ + rl_begin_undo_group (); - if (direction < 0) - return (rl_backward_kill_line (1)); - else - { - rl_end_of_line (1, ignore); - if (orig_point != rl_point) - rl_kill_text (orig_point, rl_point); - rl_point = orig_point; - } - return 0; -} + /* Do the stuff at word2 first, so that we don't have to worry + about word1 moving. */ + rl_point = w2_beg; + rl_delete_text (w2_beg, w2_end); + rl_insert_text (word1); -/* Kill backwards to the start of the line. If DIRECTION is negative, kill - forwards to the line end instead. */ -rl_backward_kill_line (direction, ignore) - int direction, ignore; -{ - int orig_point = rl_point; + rl_point = w1_beg; + rl_delete_text (w1_beg, w1_end); + rl_insert_text (word2); - if (direction < 0) - return (rl_kill_line (1)); - else - { - if (!rl_point) - ding (); - else - { - rl_beg_of_line (1, ignore); - rl_kill_text (orig_point, rl_point); - } - } - return 0; -} + /* This is exactly correct since the text before this point has not + changed in length. */ + rl_point = w2_end; -/* Kill the whole line, no matter where point is. */ -rl_kill_full_line (count, ignore) - int count, ignore; -{ - rl_begin_undo_group (); - rl_point = 0; - rl_kill_text (rl_point, rl_end); + /* I think that does it. */ rl_end_undo_group (); - return 0; -} - -/* Yank back the last killed text. This ignores arguments. */ -rl_yank (count, ignore) - int count, ignore; -{ - if (!rl_kill_ring) - { - rl_abort (count, ignore); - return -1; - } + free (word1); + free (word2); - rl_set_mark (rl_point); - rl_insert_text (rl_kill_ring[rl_kill_index]); return 0; } -/* If the last command was yank, or yank_pop, and the text just - before point is identical to the current kill item, then - delete that text from the line, rotate the index down, and - yank back some other text. */ -rl_yank_pop (count, key) +/* Transpose the characters at point. If point is at the end of the line, + then transpose the characters before point. */ +int +rl_transpose_chars (count, key) int count, key; { - int l; - - if (((rl_last_func != rl_yank_pop) && (rl_last_func != rl_yank)) || - !rl_kill_ring) - { - rl_abort (1, key); - return -1; - } - - l = strlen (rl_kill_ring[rl_kill_index]); - if (((rl_point - l) >= 0) && - (strncmp (the_line + (rl_point - l), - rl_kill_ring[rl_kill_index], l) == 0)) - { - rl_delete_text ((rl_point - l), rl_point); - rl_point -= l; - rl_kill_index--; - if (rl_kill_index < 0) - rl_kill_index = rl_kill_ring_length - 1; - rl_yank (1, 0); - return 0; - } - else - { - rl_abort (1, key); - return -1; - } -} - -/* Yank the COUNTth argument from the previous history line. */ -rl_yank_nth_arg (count, ignore) - int count, ignore; -{ - register HIST_ENTRY *entry = previous_history (); - char *arg; + char dummy[2]; - if (entry) - next_history (); - else - { - ding (); - return -1; - } + if (!count) + return 0; - arg = history_arg_extract (count, count, entry->line); - if (!arg || !*arg) + if (!rl_point || rl_end < 2) { ding (); return -1; @@ -3235,305 +1619,385 @@ rl_yank_nth_arg (count, ignore) rl_begin_undo_group (); -#if defined (VI_MODE) - /* Vi mode always inserts a space before yanking the argument, and it - inserts it right *after* rl_point. */ - if (rl_editing_mode == vi_mode) + if (rl_point == rl_end) { - rl_vi_append_mode (); - rl_insert_text (" "); + --rl_point; + count = 1; } -#endif /* VI_MODE */ - - rl_insert_text (arg); - free (arg); + rl_point--; - rl_end_undo_group (); - return 0; -} + dummy[0] = the_line[rl_point]; + dummy[1] = '\0'; -/* Yank the last argument from the previous history line. This `knows' - how rl_yank_nth_arg treats a count of `$'. With an argument, this - behaves the same as rl_yank_nth_arg. */ -int -rl_yank_last_arg (count, key) - int count, key; -{ - if (rl_explicit_arg) - return (rl_yank_nth_arg (count, key)); - else - return (rl_yank_nth_arg ('$', key)); -} + rl_delete_text (rl_point, rl_point + 1); -/* How to toggle back and forth between editing modes. */ -rl_vi_editing_mode (count, key) - int count, key; -{ -#if defined (VI_MODE) - rl_editing_mode = vi_mode; - rl_vi_insertion_mode (); - return 0; -#endif /* VI_MODE */ -} + rl_point += count; + if (rl_point > rl_end) + rl_point = rl_end; + else if (rl_point < 0) + rl_point = 0; + rl_insert_text (dummy); -rl_emacs_editing_mode (count, key) - int count, key; -{ - rl_editing_mode = emacs_mode; - _rl_keymap = emacs_standard_keymap; + rl_end_undo_group (); return 0; } - /* **************************************************************** */ /* */ -/* USG (System V) Support */ +/* Character Searching */ /* */ /* **************************************************************** */ int -rl_getc (stream) - FILE *stream; -{ - int result; - unsigned char c; - -#if defined (__GO32__) - if (isatty (0)) - return (getkey () & 0x7F); -#endif /* __GO32__ */ - - while (1) - { - 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); +_rl_char_search_internal (count, dir, schar) + int count, dir, schar; +{ + int pos, inc; -#if defined (EWOULDBLOCK) - if (errno == EWOULDBLOCK) + pos = rl_point; + inc = (dir < 0) ? -1 : 1; + while (count) + { + if ((dir < 0 && pos <= 0) || (dir > 0 && pos >= rl_end)) { - int flags; - - if ((flags = fcntl (fileno (stream), F_GETFL, 0)) < 0) - return (EOF); - if (flags & O_NDELAY) - { - flags &= ~O_NDELAY; - fcntl (fileno (stream), F_SETFL, flags); - continue; - } - continue; + ding (); + return -1; } -#endif /* EWOULDBLOCK */ -#if defined (_POSIX_VERSION) && defined (EAGAIN) && defined (O_NONBLOCK) - if (errno == EAGAIN) + pos += inc; + do { - int flags; - - if ((flags = fcntl (fileno (stream), F_GETFL, 0)) < 0) - return (EOF); - if (flags & O_NONBLOCK) + if (rl_line_buffer[pos] == schar) { - flags &= ~O_NONBLOCK; - fcntl (fileno (stream), F_SETFL, flags); - continue; + count--; + if (dir < 0) + rl_point = (dir == BTO) ? pos + 1 : pos; + else + rl_point = (dir == FTO) ? pos - 1 : pos; + break; } } -#endif /* _POSIX_VERSION && EAGAIN && O_NONBLOCK */ - -#if !defined (__GO32__) - /* 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); -#endif /* !__GO32__ */ + while ((dir < 0) ? pos-- : ++pos < rl_end); } + return (0); } -#if !defined (SHELL) -#ifdef savestring -#undef savestring -#endif -/* Backwards compatibilty, now that savestring has been removed from - all `public' readline header files. */ -char * -savestring (s) - char *s; +/* Search COUNT times for a character read from the current input stream. + FDIR is the direction to search if COUNT is non-negative; otherwise + the search goes in BDIR. */ +static int +_rl_char_search (count, fdir, bdir) + int count, fdir, bdir; { - return ((char *)strcpy (xmalloc (1 + (int)strlen (s)), (s))); + int c; + + c = rl_read_key (); + if (count < 0) + return (_rl_char_search_internal (-count, bdir, c)); + else + return (_rl_char_search_internal (count, fdir, c)); } -#endif -/* Function equivalents for the macros defined in chartypes.h. */ -#undef uppercase_p int -uppercase_p (c) - int c; +rl_char_search (count, key) + int count, key; { - return (isupper (c)); + return (_rl_char_search (count, FFIND, BFIND)); } -#undef lowercase_p int -lowercase_p (c) - int c; +rl_backward_char_search (count, key) + int count, key; { - return (islower (c)); + return (_rl_char_search (count, BFIND, FFIND)); } -#undef pure_alphabetic -int -pure_alphabetic (c) - int c; +/* **************************************************************** */ +/* */ +/* History Utilities */ +/* */ +/* **************************************************************** */ + +/* We already have a history library, and that is what we use to control + the history features of readline. This is our local interface to + the history mechanism. */ + +/* While we are editing the history, this is the saved + version of the original line. */ +HIST_ENTRY *saved_line_for_history = (HIST_ENTRY *)NULL; + +/* Set the history pointer back to the last entry in the history. */ +static void +start_using_history () { - return (isupper (c) || islower (c)); + using_history (); + if (saved_line_for_history) + _rl_free_history_entry (saved_line_for_history); + + saved_line_for_history = (HIST_ENTRY *)NULL; } -#undef digit_p -int -digit_p (c) - int c; +/* Free the contents (and containing structure) of a HIST_ENTRY. */ +void +_rl_free_history_entry (entry) + HIST_ENTRY *entry; { - return (isdigit (c)); + if (entry == 0) + return; + if (entry->line) + free (entry->line); + free (entry); } -#undef to_lower +/* Perhaps put back the current line if it has changed. */ int -to_lower (c) - int c; +maybe_replace_line () { - return (isupper (c) ? tolower (c) : c); + HIST_ENTRY *temp; + + temp = current_history (); + /* If the current line has changed, save the changes. */ + if (temp && ((UNDO_LIST *)(temp->data) != rl_undo_list)) + { + temp = replace_history_entry (where_history (), the_line, rl_undo_list); + free (temp->line); + free (temp); + } + return 0; } -#undef to_upper +/* Put back the saved_line_for_history if there is one. */ int -to_upper (c) - int c; +maybe_unsave_line () { - return (islower (c) ? toupper (c) : c); + int line_len; + + if (saved_line_for_history) + { + line_len = strlen (saved_line_for_history->line); + + if (line_len >= rl_line_buffer_len) + rl_extend_line_buffer (line_len); + + strcpy (the_line, saved_line_for_history->line); + rl_undo_list = (UNDO_LIST *)saved_line_for_history->data; + _rl_free_history_entry (saved_line_for_history); + saved_line_for_history = (HIST_ENTRY *)NULL; + rl_end = rl_point = strlen (the_line); + } + else + ding (); + return 0; } -#undef digit_value +/* Save the current line in saved_line_for_history. */ int -digit_value (c) - int c; +maybe_save_line () { - return (isdigit (c) ? c - '0' : c); + if (saved_line_for_history == 0) + { + saved_line_for_history = (HIST_ENTRY *)xmalloc (sizeof (HIST_ENTRY)); + saved_line_for_history->line = savestring (the_line); + saved_line_for_history->data = (char *)rl_undo_list; + } + return 0; } -#if defined (STATIC_MALLOC) - /* **************************************************************** */ /* */ -/* xmalloc and xrealloc () */ +/* History Commands */ /* */ /* **************************************************************** */ -static void memory_error_and_abort (); - -static char * -xmalloc (bytes) - int bytes; +/* Meta-< goes to the start of the history. */ +int +rl_beginning_of_history (count, key) + int count, key; { - char *temp = (char *)malloc (bytes); + return (rl_get_previous_history (1 + where_history (), key)); +} - if (!temp) - memory_error_and_abort (); - return (temp); +/* Meta-> goes to the end of the history. (The current line). */ +int +rl_end_of_history (count, key) + int count, key; +{ + maybe_replace_line (); + using_history (); + maybe_unsave_line (); + return 0; } -static char * -xrealloc (pointer, bytes) - char *pointer; - int bytes; +/* Move down to the next history line. */ +int +rl_get_next_history (count, key) + int count, key; { - char *temp; + HIST_ENTRY *temp; + int line_len; + + if (count < 0) + return (rl_get_previous_history (-count, key)); + + if (count == 0) + return 0; + + maybe_replace_line (); + + temp = (HIST_ENTRY *)NULL; + while (count) + { + temp = next_history (); + if (!temp) + break; + --count; + } - if (!pointer) - temp = (char *)malloc (bytes); + if (temp == 0) + maybe_unsave_line (); else - temp = (char *)realloc (pointer, bytes); + { + line_len = strlen (temp->line); - if (!temp) - memory_error_and_abort (); + if (line_len >= rl_line_buffer_len) + rl_extend_line_buffer (line_len); - return (temp); + strcpy (the_line, temp->line); + rl_undo_list = (UNDO_LIST *)temp->data; + rl_end = rl_point = strlen (the_line); +#if defined (VI_MODE) + if (rl_editing_mode == vi_mode) + rl_point = 0; +#endif /* VI_MODE */ + } + return 0; } -static void -memory_error_and_abort () +/* Get the previous item out of our interactive history, making it the current + line. If there is no previous history, just ding. */ +int +rl_get_previous_history (count, key) + int count, key; { - fprintf (stderr, "readline: Out of virtual memory!\n"); - abort (); + HIST_ENTRY *old_temp, *temp; + int line_len; + + if (count < 0) + return (rl_get_next_history (-count, key)); + + if (count == 0) + return 0; + + /* If we don't have a line saved, then save this one. */ + maybe_save_line (); + + /* If the current line has changed, save the changes. */ + maybe_replace_line (); + + temp = old_temp = (HIST_ENTRY *)NULL; + while (count) + { + temp = previous_history (); + if (temp == 0) + break; + + old_temp = temp; + --count; + } + + /* If there was a large argument, and we moved back to the start of the + history, that is not an error. So use the last value found. */ + if (!temp && old_temp) + temp = old_temp; + + if (temp == 0) + ding (); + else + { + line_len = strlen (temp->line); + + if (line_len >= rl_line_buffer_len) + rl_extend_line_buffer (line_len); + + strcpy (the_line, temp->line); + rl_undo_list = (UNDO_LIST *)temp->data; + rl_end = rl_point = line_len; + +#if defined (VI_MODE) + if (rl_editing_mode == vi_mode) + rl_point = 0; +#endif /* VI_MODE */ + } + return 0; } -#endif /* STATIC_MALLOC */ - /* **************************************************************** */ /* */ -/* Testing Readline */ +/* The Mark and the Region. */ /* */ /* **************************************************************** */ -#if defined (TEST) - -main () +/* Set the mark at POSITION. */ +int +_rl_set_mark_at_pos (position) + int position; { - HIST_ENTRY **history_list (); - char *temp = (char *)NULL; - char *prompt = "readline% "; - int done = 0; - - while (!done) - { - temp = readline (prompt); + if (position > rl_end) + return -1; - /* Test for EOF. */ - if (!temp) - exit (1); + rl_mark = position; + return 0; +} - /* If there is anything on the line, print it and remember it. */ - if (*temp) - { - fprintf (stderr, "%s\r\n", temp); - add_history (temp); - } +/* A bindable command to set the mark. */ +int +rl_set_mark (count, key) + int count, key; +{ + return (_rl_set_mark_at_pos (rl_explicit_arg ? count : rl_point)); +} - /* Check for `command' that we handle. */ - if (strcmp (temp, "quit") == 0) - done = 1; +/* Exchange the position of mark and point. */ +int +rl_exchange_point_and_mark (count, key) + int count, key; +{ + if (rl_mark > rl_end) + rl_mark = -1; - if (strcmp (temp, "list") == 0) - { - HIST_ENTRY **list = history_list (); - register int i; - if (list) - { - for (i = 0; list[i]; i++) - { - fprintf (stderr, "%d: %s\r\n", i, list[i]->line); - free (list[i]->line); - } - free (list); - } - } - free (temp); + if (rl_mark == -1) + { + ding (); + return -1; } + else + SWAP (rl_point, rl_mark); + + return 0; } -#endif /* TEST */ +/* **************************************************************** */ +/* */ +/* Editing Modes */ +/* */ +/* **************************************************************** */ +/* How to toggle back and forth between editing modes. */ +int +rl_vi_editing_mode (count, key) + int count, key; +{ +#if defined (VI_MODE) + rl_editing_mode = vi_mode; + rl_vi_insertion_mode (); +#endif /* VI_MODE */ + return 0; +} - -/* - * Local variables: - * compile-command: "gcc -g -traditional -I. -I.. -DTEST -o readline readline.c keymaps.o funmap.o history.o -ltermcap" - * end: - */ +int +rl_emacs_editing_mode (count, key) + int count, key; +{ + rl_editing_mode = emacs_mode; + _rl_keymap = emacs_standard_keymap; + return 0; +} diff --git a/lib/readline/readline.h b/lib/readline/readline.h index b397177..4f7d498 100644 --- a/lib/readline/readline.h +++ b/lib/readline/readline.h @@ -31,15 +31,44 @@ # include #endif -/* The functions for manipulating the text of the line within readline. -Most of these functions are bound to keys by default. */ +/* Readline data structures. */ + +/* Maintaining the state of undo. We remember individual deletes and inserts + on a chain of things to do. */ + +/* The actions that undo knows how to undo. Notice that UNDO_DELETE means + to insert some text, and UNDO_INSERT means to delete some text. I.e., + the code tells undo what to undo, not how to undo it. */ +enum undo_code { UNDO_DELETE, UNDO_INSERT, UNDO_BEGIN, UNDO_END }; + +/* What an element of THE_UNDO_LIST looks like. */ +typedef struct undo_list { + struct undo_list *next; + int start, end; /* Where the change took place. */ + char *text; /* The text to insert, if undoing a delete. */ + enum undo_code what; /* Delete, Insert, Begin, End. */ +} UNDO_LIST; + +/* The current undo list for RL_LINE_BUFFER. */ +extern UNDO_LIST *rl_undo_list; + +/* The data structure for mapping textual names to code addresses. */ +typedef struct _funmap { + char *name; + Function *function; +} FUNMAP; + +extern FUNMAP **funmap; + +/* Functions available to bind to key sequences. */ extern int - rl_tilde_expand (), + rl_tilde_expand (), rl_set_mark (), rl_exchange_point_and_mark (), rl_beg_of_line (), rl_backward (), rl_delete (), rl_end_of_line (), - rl_forward (), ding (), rl_backward (), rl_newline (), rl_kill_line (), + rl_forward (), ding (), rl_newline (), rl_kill_line (), + rl_copy_region_to_kill (), rl_kill_region (), rl_char_search (), rl_clear_screen (), rl_get_next_history (), rl_get_previous_history (), rl_quoted_insert (), rl_reverse_search_history (), rl_transpose_chars (), - rl_unix_line_discard (), rl_quoted_insert (), rl_unix_word_rubout (), + rl_unix_line_discard (), rl_unix_word_rubout (), rl_yank (), rl_rubout (), rl_backward_word (), rl_kill_word (), rl_forward_word (), rl_tab_insert (), rl_yank_pop (), rl_yank_nth_arg (), rl_backward_kill_word (), rl_backward_kill_line (), rl_transpose_words (), @@ -49,28 +78,21 @@ extern int rl_undo_command (), rl_revert_line (), rl_beginning_of_history (), rl_end_of_history (), rl_forward_search_history (), rl_insert (), rl_upcase_word (), rl_downcase_word (), rl_capitalize_word (), - rl_restart_output (), rl_re_read_init_file (), rl_dump_functions (), + rl_restart_output (), rl_re_read_init_file (), + rl_dump_functions (), rl_dump_variables (), rl_dump_macros (), rl_delete_horizontal_space (), rl_history_search_forward (), - rl_history_search_backward (), rl_tty_status (), rl_yank_last_arg (); - -/* `Public' utility functions. */ -extern int rl_insert_text (), rl_delete_text (), rl_kill_text (); -extern int rl_complete_internal (); -extern int rl_expand_prompt (); -extern int rl_initialize (); -extern int rl_set_signals (), rl_clear_signals (); -extern int rl_init_argument (), rl_digit_argument (); -extern int rl_read_key (), rl_getc (), rl_stuff_char (); -extern int maybe_save_line (), maybe_unsave_line (), maybe_replace_line (); -extern int rl_modifying (); - -extern int rl_begin_undo_group (), rl_end_undo_group (); -extern void rl_add_undo (), free_undo_list (); -extern int rl_do_undo (); + rl_history_search_backward (), rl_tty_status (), rl_yank_last_arg (), + rl_insert_comment (), rl_backward_char_search (), + rl_copy_forward_word (), rl_copy_backward_word (); /* Not available unless readline is compiled -DPAREN_MATCHING. */ extern int rl_insert_close (); +/* Not available unless READLINE_CALLBACKS is defined. */ +extern void rl_callback_handler_install (); +extern void rl_callback_read_char (); +extern void rl_callback_handler_remove (); + /* These are *both* defined even when VI_MODE is not. */ extern int rl_vi_editing_mode (), rl_emacs_editing_mode (); @@ -82,11 +104,11 @@ extern int /* Things for vi mode. Not available unless readline is compiled -DVI_MODE. */ extern int rl_vi_check (), rl_vi_textmod_command (); extern int - rl_vi_redo (), rl_vi_tilde_expand (), + rl_vi_undo (), rl_vi_redo (), rl_vi_tilde_expand (), rl_vi_movement_mode (), rl_vi_insertion_mode (), rl_vi_arg_digit (), rl_vi_prev_word (), rl_vi_next_word (), rl_vi_char_search (), rl_vi_eof_maybe (), rl_vi_append_mode (), rl_vi_put (), - rl_vi_append_eol (), rl_vi_insert_beg (), rl_vi_delete (), rl_vi_comment (), + rl_vi_append_eol (), rl_vi_insert_beg (), rl_vi_delete (), rl_vi_first_print (), rl_vi_fword (), rl_vi_fWord (), rl_vi_bword (), rl_vi_bWord (), rl_vi_eword (), rl_vi_eWord (), rl_vi_end_word (), rl_vi_change_case (), rl_vi_match (), rl_vi_bracktype (), @@ -94,40 +116,112 @@ extern int rl_vi_search_again (), rl_vi_subst (), rl_vi_overstrike (), rl_vi_overstrike_delete (), rl_vi_replace(), rl_vi_column (), rl_vi_delete_to (), rl_vi_change_to (), rl_vi_yank_to (), - rl_vi_complete (), rl_vi_fetch_history (); + rl_vi_complete (), rl_vi_fetch_history (), rl_vi_set_mark (), + rl_vi_goto_mark (), rl_vi_back_to_indent (); /* Keyboard macro commands. */ extern int rl_start_kbd_macro (), rl_end_kbd_macro (); extern int rl_call_last_kbd_macro (); +extern void rl_push_macro_input (); extern int rl_arrow_keys(), rl_refresh_line (); -/* Maintaining the state of undo. We remember individual deletes and inserts - on a chain of things to do. */ +/* **************************************************************** */ +/* */ +/* Well Published Functions */ +/* */ +/* **************************************************************** */ -/* The actions that undo knows how to undo. Notice that UNDO_DELETE means - to insert some text, and UNDO_INSERT means to delete some text. I.e., - the code tells undo what to undo, not how to undo it. */ -enum undo_code { UNDO_DELETE, UNDO_INSERT, UNDO_BEGIN, UNDO_END }; +/* Readline functions. */ +/* Read a line of input. Prompt with PROMPT. A NULL PROMPT means none. */ +extern char *readline (); -/* What an element of THE_UNDO_LIST looks like. */ -typedef struct undo_list { - struct undo_list *next; - int start, end; /* Where the change took place. */ - char *text; /* The text to insert, if undoing a delete. */ - enum undo_code what; /* Delete, Insert, Begin, End. */ -} UNDO_LIST; +/* These functions are from bind.c. */ +/* rl_add_defun (char *name, Function *function, int key) + Add NAME to the list of named functions. Make FUNCTION + be the function that gets called. + If KEY is not -1, then bind it. */ +extern int rl_add_defun (); -/* The current undo list for RL_LINE_BUFFER. */ -extern UNDO_LIST *rl_undo_list; +extern Keymap rl_make_bare_keymap (); +extern Keymap rl_copy_keymap (); +extern Keymap rl_make_keymap (); +extern void rl_discard_keymap (); +extern Keymap rl_get_keymap (), rl_get_keymap_by_name (); +extern void rl_set_keymap (); +extern char *rl_get_keymap_name (); -/* The data structure for mapping textual names to code addresses. */ -typedef struct { - char *name; - Function *function; -} FUNMAP; +extern int rl_bind_key (), rl_bind_key_in_map (); +extern int rl_unbind_key (), rl_unbind_key_in_map (); +extern int rl_set_key (); +extern int rl_generic_bind (); +extern int rl_parse_and_bind (); +/* Backwards compatibility, use rl_generic_bind instead. */ +extern int rl_macro_bind (), rl_variable_bind (); -extern FUNMAP **funmap; +extern int rl_read_init_file (); + +extern Function *rl_named_function (), *rl_function_of_keyseq (); +extern char **rl_invoking_keyseqs (), **rl_invoking_keyseqs_in_map (); +extern void rl_function_dumper (); +extern void rl_variable_dumper (); +extern void rl_macro_dumper (); +extern void rl_list_funmap_names (); + +/* Undocumented in the texinfo manual; not really useful to programs. */ +extern int rl_translate_keyseq (); +extern void rl_initialize_funmap (); + +/* Functions for undoing. */ +extern int rl_begin_undo_group (), rl_end_undo_group (); +extern void rl_add_undo (), free_undo_list (); +extern int rl_do_undo (); +extern int rl_modifying (); + +/* Functions for redisplay. */ +extern void rl_redisplay (); +extern int rl_forced_update_display (); +extern int rl_clear_message (); +extern int rl_reset_line_state (); +extern int rl_on_new_line (); + +#if defined (__STDC__) && defined (USE_VARARGS) && defined (PREFER_STDARG) +extern int rl_message (const char *, ...); +#else +extern int rl_message (); +#endif + +/* Undocumented in texinfo manual. */ +extern int rl_character_len (); +extern int rl_show_char (); +extern int crlf (); + +/* Modifying text. */ +extern int rl_insert_text (), rl_delete_text (); +extern int rl_kill_text (); +extern char *rl_copy_text (); + +/* `Public' utility functions. */ +extern int rl_reset_terminal (); +extern int rl_stuff_char (); +extern int rl_read_key (), rl_getc (); + +extern int rl_initialize (); + +/* Undocumented. */ +extern int rl_expand_prompt (); +extern int rl_set_signals (), rl_clear_signals (); +extern int maybe_save_line (), maybe_unsave_line (), maybe_replace_line (); + +/* Completion functions. */ +/* These functions are from complete.c. */ +extern int rl_complete_internal (); + +/* Return an array of strings which are the result of repeatadly calling + FUNC with TEXT. */ +extern char **completion_matches (); +extern char *username_completion_function (); +extern char *filename_completion_function (); /* **************************************************************** */ /* */ @@ -135,6 +229,9 @@ extern FUNMAP **funmap; /* */ /* **************************************************************** */ +/* The version of this incarnation of the readline library. */ +extern char *rl_library_version; + /* The name of the calling program. You should initialize this to whatever was in argv[0]. It is used when parsing conditionals. */ extern char *rl_readline_name; @@ -145,33 +242,36 @@ extern char *rl_line_buffer; /* The location of point, and end. */ extern int rl_point, rl_end; +extern int rl_mark; + +extern int rl_done; + +extern int rl_pending_input; + /* The name of the terminal to use. */ extern char *rl_terminal_name; /* The input and output streams. */ extern FILE *rl_instream, *rl_outstream; -/* The basic list of characters that signal a break between words for the - completer routine. The initial contents of this variable is what - breaks words in the shell, i.e. "n\"\\'`@$>". */ -extern char *rl_basic_word_break_characters; +/* If non-zero, then this is the address of a function to call just + before readline_internal () prints the first prompt. */ +extern Function *rl_startup_hook; -/* The list of characters that signal a break between words for - rl_complete_internal. The default list is the contents of - rl_basic_word_break_characters. */ -extern char *rl_completer_word_break_characters; +/* The address of a function to call periodically while Readline is + awaiting character input, or NULL, for no event handling. */ +extern Function *rl_event_hook; -/* List of characters which can be used to quote a substring of the line. - Completion occurs on the entire substring, and within the substring - rl_completer_word_break_characters are treated as any other character, - unless they also appear within this list. */ -extern char *rl_completer_quote_characters; +extern Function *rl_getc_function; +extern VFunction *rl_redisplay_function; +extern VFunction *rl_prep_term_function; +extern VFunction *rl_deprep_term_function; -/* List of characters that are word break characters, but should be left - in TEXT when it is passed to the completion function. The shell uses - this to help determine what kind of completing to do. */ -extern char *rl_special_prefixes; +/* Dispatch variables. */ +extern Keymap rl_executing_keymap; +extern Keymap rl_binding_keymap; +/* Completion variables. */ /* Pointer to the generator function for completion_matches (). NULL means to use filename_entry_function (), the default filename completer. */ @@ -194,9 +294,32 @@ extern Function *rl_ignore_some_completions_function; array of strings returned. */ extern CPPFunction *rl_attempted_completion_function; -/* If non-zero, then this is the address of a function to call just - before readline_internal () prints the first prompt. */ -extern Function *rl_startup_hook; +/* The basic list of characters that signal a break between words for the + completer routine. The initial contents of this variable is what + breaks words in the shell, i.e. "n\"\\'`@$>". */ +extern char *rl_basic_word_break_characters; + +/* The list of characters that signal a break between words for + rl_complete_internal. The default list is the contents of + rl_basic_word_break_characters. */ +extern char *rl_completer_word_break_characters; + +/* List of characters which can be used to quote a substring of the line. + Completion occurs on the entire substring, and within the substring + rl_completer_word_break_characters are treated as any other character, + unless they also appear within this list. */ +extern char *rl_completer_quote_characters; + +/* List of quote characters which cause a word break. */ +extern char *rl_basic_quote_characters; + +/* List of characters that need to be quoted in filenames by the completer. */ +extern char *rl_filename_quote_characters; + +/* List of characters that are word break characters, but should be left + in TEXT when it is passed to the completion function. The shell uses + this to help determine what kind of completing to do. */ +extern char *rl_special_prefixes; /* If non-zero, then this is the address of a function to call when completing on a directory name. The function is called with @@ -206,14 +329,6 @@ extern Function *rl_directory_completion_hook; /* Backwards compatibility with previous versions of readline. */ #define rl_symbolic_link_hook rl_directory_completion_hook -/* The address of a function to call periodically while Readline is - awaiting character input, or NULL, for no event handling. */ -extern Function *rl_event_hook; - -/* Non-zero means that modified history lines are preceded - with an asterisk. */ -extern int rl_show_star; - /* Non-zero means that the results of the matches are to be treated as filenames. This is ALWAYS zero on entry, and can only be changed within a completion entry finder function. */ @@ -226,62 +341,49 @@ extern int rl_filename_completion_desired; entry finder function. */ extern int rl_filename_quoting_desired; -/* Non-zero means to suppress normal filename completion after the - user-specified completion function has been called. */ -extern int rl_attempted_completion_over; - -/* **************************************************************** */ -/* */ -/* Well Published Functions */ -/* */ -/* **************************************************************** */ +/* Set to a function to quote a filename in an application-specific fashion. + Called with the text to quote, the type of match found (single or multiple) + and a pointer to the quoting character to be used, which the function can + reset if desired. */ +extern CPFunction *rl_filename_quoting_function; -/* Read a line of input. Prompt with PROMPT. A NULL PROMPT means none. */ -extern char *readline (); +/* Function to call to remove quoting characters from a filename. Called + before completion is attempted, so the embedded quotes do not interfere + with matching names in the file system. */ +extern CPFunction *rl_filename_dequoting_function; -/* These functions are from complete.c. */ -/* Return an array of strings which are the result of repeatadly calling - FUNC with TEXT. */ -extern char **completion_matches (); -extern char *username_completion_function (); -extern char *filename_completion_function (); +/* Function to call to decide whether or not a word break character is + quoted. If a character is quoted, it does not break words for the + completer. */ +extern Function *rl_char_is_quoted_p; -/* These functions are from bind.c. */ -/* rl_add_defun (char *name, Function *function, int key) - Add NAME to the list of named functions. Make FUNCTION - be the function that gets called. - If KEY is not -1, then bind it. */ -extern int rl_add_defun (); -extern int rl_bind_key (), rl_bind_key_in_map (); -extern int rl_unbind_key (), rl_unbind_key_in_map (); -extern int rl_set_key (); -extern int rl_macro_bind (), rl_generic_bind (), rl_variable_bind (); -extern int rl_translate_keyseq (); -extern Function *rl_named_function (), *rl_function_of_keyseq (); -extern int rl_parse_and_bind (); -extern Keymap rl_get_keymap (), rl_get_keymap_by_name (); -extern void rl_set_keymap (); -extern char **rl_invoking_keyseqs (), **rl_invoking_keyseqs_in_map (); -extern void rl_function_dumper (); -extern int rl_read_init_file (); +/* Non-zero means to suppress normal filename completion after the + user-specified completion function has been called. */ +extern int rl_attempted_completion_over; -/* Functions in funmap.c */ -extern void rl_list_funmap_names (); -extern void rl_initialize_funmap (); +/* Set to a character describing the type of completion being attempted by + rl_complete_internal; available for use by application completion + functions. */ +extern int rl_completion_type; -/* Functions in display.c */ -extern void rl_redisplay (); -extern int rl_message (), rl_clear_message (); -extern int rl_reset_line_state (); -extern int rl_character_len (); -extern int rl_show_char (); -extern int crlf (), rl_on_new_line (); -extern int rl_forced_update_display (); +/* Character appended to completed words when at the end of the line. The + default is a space. Nothing is added if this is '\0'. */ +extern int rl_completion_append_character; +/* If this is non-zero, completion is (temporarily) inhibited, and the + completion character will be inserted as any other. */ +extern int rl_inhibit_completion; + /* Definitions available for use by readline clients. */ #define RL_PROMPT_START_IGNORE '\001' #define RL_PROMPT_END_IGNORE '\002' +/* Possible values for do_replace argument to rl_filename_quoting_function, + called by rl_complete_internal. */ +#define NO_MATCH 0 +#define SINGLE_MATCH 1 +#define MULT_MATCH 2 + #if !defined (savestring) extern char *savestring (); /* XXX backwards compatibility */ #endif diff --git a/lib/readline/rlconf.h b/lib/readline/rlconf.h index 0035b93..8f07db1 100644 --- a/lib/readline/rlconf.h +++ b/lib/readline/rlconf.h @@ -51,7 +51,13 @@ over a character when updating the line rather than rewriting it. */ /* #define HACK_TERMCAP_MOTION */ -/* The string inserted by the vi-mode `insert comment' command. */ -#define VI_COMMENT_BEGIN_DEFAULT "#" +/* The string inserted by the `insert comment' command. */ +#define RL_COMMENT_BEGIN_DEFAULT "#" + +/* Define this if you want code that allows readline to be used in an + X `callback' style. */ +#if !defined (SHELL) +# define READLINE_CALLBACKS +#endif #endif /* _RLCONF_H_ */ diff --git a/lib/readline/rldefs.h b/lib/readline/rldefs.h index 683f8b5..5a9e62a 100644 --- a/lib/readline/rldefs.h +++ b/lib/readline/rldefs.h @@ -23,106 +23,33 @@ have a copy of the license, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ -#if !defined (_RLDEFS_H) -#define _RLDEFS_H +#if !defined (_RLDEFS_H_) +#define _RLDEFS_H_ #if defined (HAVE_CONFIG_H) # include "config.h" #endif -#if !defined (PRAGMA_ALLOCA) -# include "memalloc.h" -#endif - -#define NEW_TTY_DRIVER -#define HAVE_BSD_SIGNALS -/* #define USE_XON_XOFF */ - -#if defined (__linux__) || defined (HAVE_TERMCAP_H) -# include -#endif /* __linux__ || HAVE_TERMCAP_H */ - -/* Some USG machines have BSD signal handling (sigblock, sigsetmask, etc.) */ -#if defined (USG) && !defined (hpux) -# undef HAVE_BSD_SIGNALS -#endif - -/* System V machines use termio. */ -#if !defined (_POSIX_VERSION) -# if defined (USG) || defined (hpux) || defined (Xenix) || defined (sgi) || \ - defined (DGUX) || defined (HAVE_TERMIO_H) -# undef NEW_TTY_DRIVER +#if defined (_POSIX_VERSION) && !defined (TERMIOS_MISSING) +# define TERMIOS_TTY_DRIVER +#else +# if defined (HAVE_TERMIO_H) # define TERMIO_TTY_DRIVER -# include -# if !defined (TCOON) -# define TCOON 1 -# endif -# endif /* USG || hpux || Xenix || sgi || DUGX || HAVE_TERMIO_H */ -#endif /* !_POSIX_VERSION */ - -/* Posix systems use termios and the Posix signal functions. */ -#if defined (_POSIX_VERSION) -# if !defined (TERMIOS_MISSING) -# undef NEW_TTY_DRIVER -# define TERMIOS_TTY_DRIVER -# include -# endif /* !TERMIOS_MISSING */ -# define HAVE_POSIX_SIGNALS -# if !defined (O_NDELAY) -# define O_NDELAY O_NONBLOCK /* Posix-style non-blocking i/o */ -# endif /* O_NDELAY */ -#endif /* _POSIX_VERSION */ - -/* System V.3 machines have the old 4.1 BSD `reliable' signal interface. */ -#if !defined (HAVE_BSD_SIGNALS) && !defined (HAVE_POSIX_SIGNALS) -# if defined (USGr3) && !defined (XENIX_22) -# if !defined (HAVE_USG_SIGHOLD) -# define HAVE_USG_SIGHOLD -# endif /* !HAVE_USG_SIGHOLD */ -# endif /* USGr3 && !XENIX_22 */ -#endif /* !HAVE_BSD_SIGNALS && !HAVE_POSIX_SIGNALS */ - -/* Other (BSD) machines use sgtty. */ -#if defined (NEW_TTY_DRIVER) -# include +# else +# define NEW_TTY_DRIVER +# endif #endif -#if !defined (SHELL) && (defined (_POSIX_VERSION) || defined (USGr3)) -# if !defined (HAVE_DIRENT_H) -# define HAVE_DIRENT_H -# endif /* !HAVE_DIRENT_H */ -#endif /* !SHELL && (_POSIX_VERSION || USGr3) */ - -#if defined (HAVE_DIRENT_H) -# include -# define D_NAMLEN(d) strlen ((d)->d_name) -#else /* !HAVE_DIRENT_H */ -# define D_NAMLEN(d) ((d)->d_namlen) -# if defined (USG) -# if defined (Xenix) -# include -# else /* !Xenix (but USG...) */ -# include "ndir.h" -# endif /* !Xenix */ -# else /* !USG */ -# include -# endif /* !USG */ -# if !defined (dirent) -# define dirent direct -# endif /* !dirent */ -#endif /* !HAVE_DIRENT_H */ - -#if defined (USG) && defined (TIOCGWINSZ) && !defined (Linux) -# if defined (HAVE_SYS_STREAM_H) -# include -# endif /* HAVE_SYS_STREAM_H */ -# if defined (HAVE_SYS_PTEM_H) -# include -# endif /* HAVE_SYS_PTEM_H */ -# if defined (HAVE_SYS_PTE_H) -# include -# endif /* HAVE_SYS_PTE_H */ -#endif /* USG && TIOCGWINSZ && !Linux */ +#if defined (HAVE_SYS_STREAM_H) +# include +#endif /* HAVE_SYS_STREAM_H */ +#if defined (HAVE_SYS_PTEM_H) +# include +# define _IO_PTEM_H /* work around SVR4.2 1.1.4 bug */ +#endif /* HAVE_SYS_PTEM_H */ +#if defined (HAVE_SYS_PTE_H) +# include +#endif /* HAVE_SYS_PTE_H */ /* Posix macro to check file in statbuf for directory-ness. This requires that be included before this test. */ @@ -133,12 +60,6 @@ /* Decide which flavor of the header file describing the C library string functions to include and include it. */ -#if defined (USG) || defined (NeXT) -# if !defined (HAVE_STRING_H) -# define HAVE_STRING_H -# endif /* !HAVE_STRING_H */ -#endif /* USG || NeXT */ - #if defined (HAVE_STRING_H) # include #else /* !HAVE_STRING_H */ @@ -149,33 +70,20 @@ extern char *strchr (), *strrchr (); #endif /* !strchr && !__STDC__ */ -#if defined (HAVE_VARARGS_H) -# include -#endif /* HAVE_VARARGS_H */ - -/* This is needed to include support for TIOCGWINSZ and window resizing. */ -#if defined (OSF1) || defined (BSD386) || defined (NetBSD) || \ - defined (__BSD_4_4__) || defined (FreeBSD) || defined (_386BSD) || \ - defined (AIX) -# define GWINSZ_IN_SYS_IOCTL +#if defined (PREFER_STDARG) +# include +#else +# if defined (PREFER_VARARGS) +# include +# endif #endif -/* Define _POSIX_VDISABLE if we are not using the `new' tty driver and - it is not already defined. It is used both to determine if a - special character is disabled and to disable certain special - characters. Posix systems should set to 0, USG systems to -1. */ -#if !defined (NEW_TTY_DRIVER) && !defined (_POSIX_VDISABLE) -# if defined (_SVR4_VDISABLE) -# define _POSIX_VDISABLE _SVR4_VDISABLE -# else -# if defined (_POSIX_VERSION) -# define _POSIX_VDISABLE 0 -# else /* !_POSIX_VERSION */ -# define _POSIX_VDISABLE -1 -# endif /* !_POSIX_VERSION */ -# endif /* !_SVR4_VDISABLE */ -#endif /* !NEW_TTY_DRIVER && !_POSIX_VDISABLE */ - +#if defined (HAVE_STRCASECMP) +#define _rl_stricmp strcasecmp +#define _rl_strnicmp strncasecmp +#else +extern int _rl_stricmp (), _rl_strnicmp (); +#endif #if !defined (emacs_mode) # define no_mode -1 @@ -206,7 +114,33 @@ extern char *xmalloc (); #define AUDIBLE_BELL 1 #define VISIBLE_BELL 2 +/* Definitions used when searching the line for characters. */ +/* NOTE: it is necessary that opposite directions are inverses */ +#define FTO 1 /* forward to */ +#define BTO -1 /* backward to */ +#define FFIND 2 /* forward find */ +#define BFIND -2 /* backward find */ + +/* Possible values for the found_quote flags word used by the completion + functions. It says what kind of (shell-like) quoting we found anywhere + in the line. */ +#define RL_QF_SINGLE_QUOTE 0x1 +#define RL_QF_DOUBLE_QUOTE 0x2 +#define RL_QF_BACKSLASH 0x4 + +/* Default readline line buffer length. */ +#define DEFAULT_BUFFER_SIZE 256 + +#if !defined (STREQ) +#define STREQ(a, b) (((a)[0] == (b)[0]) && (strcmp ((a), (b)) == 0)) +#define STREQN(a, b, n) (((a)[0] == (b)[0]) && (strncmp ((a), (b), (n)) == 0)) +#endif + +#if !defined (FREE) +# define FREE(x) if (x) free (x) +#endif + /* CONFIGURATION SECTION */ #include "rlconf.h" -#endif /* !_RLDEFS_H */ +#endif /* !_RLDEFS_H_ */ diff --git a/lib/readline/rltty.c b/lib/readline/rltty.c index 02c036d..d35eb6a 100644 --- a/lib/readline/rltty.c +++ b/lib/readline/rltty.c @@ -23,7 +23,7 @@ #define READLINE_LIBRARY #if defined (HAVE_CONFIG_H) -# include "config.h" +# include #endif #include @@ -36,6 +36,12 @@ #endif /* HAVE_UNISTD_H */ #include "rldefs.h" + +#if !defined (SHELL) && defined (GWINSZ_IN_SYS_IOCTL) +# include +#endif /* !SHELL && GWINSZ_IN_SYS_IOCTL */ + +#include "rltty.h" #include "readline.h" #if !defined (errno) @@ -45,11 +51,19 @@ extern int errno; extern int readline_echoing_p; extern int _rl_eof_char; +extern int _rl_enable_keypad, _rl_enable_meta; + #if defined (__GO32__) -# include +# include # undef HANDLE_SIGNALS #endif /* __GO32__ */ +/* Indirect functions to allow apps control over terminal management. */ +extern void rl_prep_terminal (), rl_deprep_terminal (); + +VFunction *rl_prep_term_function = rl_prep_terminal; +VFunction *rl_deprep_term_function = rl_deprep_terminal; + /* **************************************************************** */ /* */ /* Signal Management */ @@ -64,7 +78,7 @@ static int sigint_oldmask; # endif /* HAVE_BSD_SIGNALS */ #endif /* !HAVE_POSIX_SIGNALS */ -static int sigint_blocked = 0; +static int sigint_blocked; /* Cause SIGINT to not be delivered until the corresponding call to release_sigint(). */ @@ -115,64 +129,35 @@ release_sigint () /* **************************************************************** */ /* */ -/* Controlling the Meta Key and Keypad */ -/* */ -/* **************************************************************** */ - -extern int term_has_meta; -extern char *term_mm; -extern char *term_mo; - -extern char *term_ks; -extern char *term_ke; - -static int -outchar (c) - int c; -{ - return putc (c, rl_outstream); -} - -/* Turn on/off the meta key depending on ON. */ -static void -control_meta_key (on) - int on; -{ - if (term_has_meta) - { - if (on && term_mm) - tputs (term_mm, 1, outchar); - else if (!on && term_mo) - tputs (term_mo, 1, outchar); - } -} - -#if 0 -static void -control_keypad (on) - int on; -{ - if (on && term_ks) - tputs (term_ks, 1, outchar); - else if (!on && term_ke) - tputs (term_ke, 1, outchar); -} -#endif - -/* **************************************************************** */ -/* */ /* Saving and Restoring the TTY */ /* */ /* **************************************************************** */ /* Non-zero means that the terminal is in a prepped state. */ -static int terminal_prepped = 0; +static int terminal_prepped; /* If non-zero, means that this process has called tcflow(fd, TCOOFF) and output is suspended. */ #if defined (__ksr1__) -static int ksrflow = 0; +static int ksrflow; #endif + +#if !defined (SHELL) && defined (TIOCGWINSZ) +/* Dummy call to force a backgrounded readline to stop before it tries + to get the tty settings. */ +static void +set_winsize (tty) + int tty; +{ + struct winsize w; + + if (ioctl (tty, TIOCGWINSZ, &w) == 0) + (void) ioctl (tty, TIOCSWINSZ, &w); +} +#else /* SHELL || !TIOCGWINSZ */ +# define set_winsize(tty) +#endif /* SHELL || !TIOCGWINSZ */ + #if defined (NEW_TTY_DRIVER) /* Values for the `flags' field of a struct bsdtty. This tells which @@ -204,12 +189,7 @@ get_tty_settings (tty, tiop) int tty; TIOTYPE *tiop; { -#if !defined (SHELL) && defined (TIOCGWINSZ) - struct winsize w; - - if (ioctl (tty, TIOCGWINSZ, &w) == 0) - (void) ioctl (tty, TIOCSWINSZ, &w); -#endif + set_winsize (tty); tiop->flags = tiop->lflag = 0; @@ -234,6 +214,7 @@ get_tty_settings (tty, tiop) return 0; } +static int set_tty_settings (tty, tiop) int tty; TIOTYPE *tiop; @@ -360,7 +341,11 @@ prepare_terminal_settings (meta_flag, otio, tiop) # define TIOTYPE struct termios # define DRAIN_OUTPUT(fd) tcdrain (fd) # define GETATTR(tty, tiop) (tcgetattr (tty, tiop)) -# define SETATTR(tty, tiop) (tcsetattr (tty, TCSANOW, tiop)) +# ifdef M_UNIX +# define SETATTR(tty, tiop) (tcsetattr (tty, TCSANOW, tiop)) +# else +# define SETATTR(tty, tiop) (tcsetattr (tty, TCSADRAIN, tiop)) +# endif /* !M_UNIX */ #else # define TIOTYPE struct termio # define DRAIN_OUTPUT(fd) @@ -376,29 +361,61 @@ static TIOTYPE otio; # define OUTPUT_BEING_FLUSHED(tp) 0 #endif +static void +rltty_warning (msg) + char *msg; +{ + fprintf (stderr, "readline: warning: %s\n", msg); +} + +#if defined (_AIX) +void +setopost(tp) +TIOTYPE *tp; +{ + if ((tp->c_oflag & OPOST) == 0) + { + rltty_warning ("turning on OPOST for terminal\r"); + tp->c_oflag |= OPOST|ONLCR; + } +} +#endif + static int get_tty_settings (tty, tiop) int tty; TIOTYPE *tiop; { int ioctl_ret; -#if !defined (SHELL) && defined (TIOCGWINSZ) - struct winsize w; + set_winsize (tty); - if (ioctl (tty, TIOCGWINSZ, &w) == 0) - (void) ioctl (tty, TIOCSWINSZ, &w); -#endif - - /* Keep looping if output is being flushed after a ^O (or whatever - the flush character is). */ - while ((ioctl_ret = GETATTR (tty, tiop)) < 0 || OUTPUT_BEING_FLUSHED (tiop)) + while (1) { - if (ioctl_ret < 0 && errno != EINTR) - return -1; + ioctl_ret = GETATTR (tty, tiop); + if (ioctl_ret < 0) + { + if (errno != EINTR) + return -1; + else + continue; + } if (OUTPUT_BEING_FLUSHED (tiop)) - continue; - errno = 0; + { +#if defined (FLUSHO) && defined (_AIX41) + rltty_warning ("turning off output flushing"); + tiop->c_lflag &= ~FLUSHO; + break; +#else + continue; +#endif + } + break; } + +#if defined (_AIX) + setopost(tiop); +#endif + return 0; } @@ -503,7 +520,7 @@ rl_prep_terminal (meta_flag) int meta_flag; { #if !defined (__GO32__) - int tty = fileno (rl_instream); + int tty; TIOTYPE tio; if (terminal_prepped) @@ -512,6 +529,8 @@ rl_prep_terminal (meta_flag) /* Try to keep this function from being INTerrupted. */ block_sigint (); + tty = fileno (rl_instream); + if (get_tty_settings (tty, &tio) < 0) { release_sigint (); @@ -528,10 +547,9 @@ rl_prep_terminal (meta_flag) return; } - control_meta_key (1); -#if 0 - control_keypad (1); -#endif + if (_rl_enable_keypad) + _rl_control_keypad (1); + fflush (rl_outstream); terminal_prepped = 1; @@ -544,18 +562,19 @@ void rl_deprep_terminal () { #if !defined (__GO32__) - int tty = fileno (rl_instream); + int tty; if (!terminal_prepped) return; - /* Try to keep this function from being INTerrupted. */ + /* Try to keep this function from being interrupted. */ block_sigint (); - control_meta_key (0); -#if 0 - control_keypad (0); -#endif + tty = fileno (rl_instream); + + if (_rl_enable_keypad) + _rl_control_keypad (0); + fflush (rl_outstream); if (set_tty_settings (tty, &otio) < 0) @@ -576,6 +595,7 @@ rl_deprep_terminal () /* */ /* **************************************************************** */ +int rl_restart_output (count, key) int count, key; { @@ -608,6 +628,7 @@ rl_restart_output (count, key) return 0; } +int rl_stop_output (count, key) int count, key; { @@ -634,7 +655,7 @@ rl_stop_output (count, key) return 0; } - + /* **************************************************************** */ /* */ /* Default Key Bindings */ diff --git a/lib/readline/rltty.h b/lib/readline/rltty.h new file mode 100644 index 0000000..3ee6b3f --- /dev/null +++ b/lib/readline/rltty.h @@ -0,0 +1,61 @@ +/* rltty.h - tty driver-related definitions used by some library files. */ + +/* Copyright (C) 1995 Free Software Foundation, Inc. + + This file contains the Readline Library (the Library), a set of + routines for providing Emacs style line input to programs that ask + for it. + + The 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 1, or (at your option) + any later version. + + The 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, + 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#if !defined (_RLTTY_H_) +#define _RLTTY_H + +/* Posix systems use termios and the Posix signal functions. */ +#if defined (TERMIOS_TTY_DRIVER) +# include +#endif /* TERMIOS_TTY_DRIVER */ + +/* System V machines use termio. */ +#if defined (TERMIO_TTY_DRIVER) +# include +# if !defined (TCOON) +# define TCOON 1 +# endif +#endif /* TERMIO_TTY_DRIVER */ + +/* Other (BSD) machines use sgtty. */ +#if defined (NEW_TTY_DRIVER) +# include +#endif + +/* Define _POSIX_VDISABLE if we are not using the `new' tty driver and + it is not already defined. It is used both to determine if a + special character is disabled and to disable certain special + characters. Posix systems should set to 0, USG systems to -1. */ +#if !defined (NEW_TTY_DRIVER) && !defined (_POSIX_VDISABLE) +# if defined (_SVR4_VDISABLE) +# define _POSIX_VDISABLE _SVR4_VDISABLE +# else +# if defined (_POSIX_VERSION) +# define _POSIX_VDISABLE 0 +# else /* !_POSIX_VERSION */ +# define _POSIX_VDISABLE -1 +# endif /* !_POSIX_VERSION */ +# endif /* !_SVR4_DISABLE */ +#endif /* !NEW_TTY_DRIVER && !_POSIX_VDISABLE */ + +#endif /* _RLTTY_H_ */ diff --git a/lib/readline/search.c b/lib/readline/search.c index d56e554..05641a1 100644 --- a/lib/readline/search.c +++ b/lib/readline/search.c @@ -22,6 +22,10 @@ 675 Mass Ave, Cambridge, MA 02139, USA. */ #define READLINE_LIBRARY +#if defined (HAVE_CONFIG_H) +# include +#endif + #include #include @@ -33,16 +37,12 @@ #include "readline.h" #include "history.h" -#define STREQ(a, b) (((a)[0] == (b)[0]) && (strcmp ((a), (b)) == 0)) -#define STREQN(a, b, n) (((a)[0] == (b)[0]) && (strncmp ((a), (b), (n)) == 0)) - #define abs(x) (((x) > 0) ? (x) : -(x)) extern char *xmalloc (), *xrealloc (); /* Variables imported from readline.c */ extern int rl_point, rl_end, rl_line_buffer_len; -extern Keymap _rl_keymap; extern int rl_editing_mode; extern char *rl_prompt; extern char *rl_line_buffer; @@ -51,9 +51,12 @@ extern Function *rl_last_func; /* Functions imported from the rest of the library. */ extern int _rl_free_history_entry (); +extern char *_rl_make_prompt_for_search (); +extern void _rl_restore_prompt (); +extern void rl_extend_line_buffer (); static char *noninc_search_string = (char *) NULL; -static int noninc_history_pos = 0; +static int noninc_history_pos; static char *prev_line_found = (char *) NULL; /* Search the history list for STRING starting at absolute history position @@ -91,7 +94,7 @@ noninc_dosearch (string, dir) char *string; int dir; { - int oldpos, pos; + int oldpos, pos, line_len; HIST_ENTRY *entry; if (string == 0 || *string == '\0' || noninc_history_pos < 0) @@ -121,14 +124,10 @@ noninc_dosearch (string, dir) #endif history_set_pos (oldpos); - { - int line_len; - - line_len = strlen (entry->line); - if (line_len >= rl_line_buffer_len) - rl_extend_line_buffer (line_len); - strcpy (rl_line_buffer, entry->line); - } + line_len = strlen (entry->line); + if (line_len >= rl_line_buffer_len) + rl_extend_line_buffer (line_len); + strcpy (rl_line_buffer, entry->line); rl_undo_list = (UNDO_LIST *)entry->data; rl_end = strlen (rl_line_buffer); @@ -150,7 +149,7 @@ noninc_search (dir, pchar) int dir; int pchar; { - int saved_point, c, pmtlen; + int saved_point, c; char *p; maybe_save_line (); @@ -160,17 +159,12 @@ noninc_search (dir, pchar) rl_line_buffer[0] = 0; rl_end = rl_point = 0; - /* XXX - this needs fixing to work with the prompt expansion stuff - XXX */ - pmtlen = (rl_prompt && *rl_prompt) ? strlen (rl_prompt) : 0; - p = xmalloc (2 + pmtlen); - if (pmtlen) - strcpy (p, rl_prompt); - p[pmtlen] = pchar ? pchar : ':'; - p[pmtlen + 1] = '\0'; - + p = _rl_make_prompt_for_search (pchar ? pchar : ':'); rl_message (p, 0, 0); free (p); +#define SEARCH_RETURN _rl_restore_prompt (); return + /* Read the search string. */ while (c = rl_read_key ()) { @@ -183,9 +177,9 @@ noninc_search (dir, pchar) maybe_unsave_line (); rl_clear_message (); rl_point = saved_point; - return; + SEARCH_RETURN; } - rl_rubout (1); + rl_rubout (1, c); break; case CTRL('W'): @@ -208,13 +202,13 @@ noninc_search (dir, pchar) rl_clear_message (); rl_point = saved_point; ding (); - return; + SEARCH_RETURN; default: rl_insert (1, c); break; } - rl_redisplay (); + (*rl_redisplay_function) (); } dosearch: @@ -226,7 +220,7 @@ noninc_search (dir, pchar) if (!noninc_search_string) { ding (); - return; + SEARCH_RETURN; } } else @@ -238,35 +232,33 @@ noninc_search (dir, pchar) noninc_search_string = savestring (rl_line_buffer); } + _rl_restore_prompt (); noninc_dosearch (noninc_search_string, dir); } /* Search forward through the history list for a string. If the vi-mode code calls this, KEY will be `?'. */ +int rl_noninc_forward_search (count, key) int count, key; { - if (key == '?') - noninc_search (1, '?'); - else - noninc_search (1, 0); + noninc_search (1, (key == '?') ? '?' : 0); return 0; } /* Reverse search the history list for a string. If the vi-mode code calls this, KEY will be `/'. */ +int rl_noninc_reverse_search (count, key) int count, key; { - if (key == '/') - noninc_search (-1, '/'); - else - noninc_search (-1, 0); + noninc_search (-1, (key == '/') ? '/' : 0); return 0; } /* Search forward through the history list for the last string searched for. If there is no saved search string, abort. */ +int rl_noninc_forward_search_again (count, key) int count, key; { @@ -281,6 +273,7 @@ rl_noninc_forward_search_again (count, key) /* Reverse search in the history list for the last string searched for. If there is no saved search string, abort. */ +int rl_noninc_reverse_search_again (count, key) int count, key; { @@ -306,8 +299,14 @@ rl_history_search_internal (count, direction) while (count) { temp = (direction < 0) ? previous_history () : next_history (); - if (!temp) + if (temp == 0) break; + /* On an empty prefix, make this the same as previous-history. */ + if (rl_point == 0) + { + count--; + continue; + } if (STREQN (rl_line_buffer, temp->line, rl_point)) { /* Don't find multiple instances of the same line. */ @@ -320,7 +319,7 @@ rl_history_search_internal (count, direction) } } - if (!temp) + if (temp == 0) { if (direction < 0 && old_temp) temp = old_temp; diff --git a/lib/readline/signals.c b/lib/readline/signals.c index e3d93a0..2fe7953 100644 --- a/lib/readline/signals.c +++ b/lib/readline/signals.c @@ -21,32 +21,18 @@ 675 Mass Ave, Cambridge, MA 02139, USA. */ #define READLINE_LIBRARY -#include +#if defined (HAVE_CONFIG_H) +# include +#endif + +#include /* Just for NULL. Yuck. */ #include -#include -#if !defined (NO_SYS_FILE) -# include -#endif /* !NO_SYS_FILE */ #include #if defined (HAVE_UNISTD_H) # include #endif /* HAVE_UNISTD_H */ -#if defined (HAVE_STDLIB_H) -# include -#else -# include "ansi_stdlib.h" -#endif /* HAVE_STDLIB_H */ - -#include -/* Not all systems declare ERRNO in errno.h... and some systems #define it! */ -#if !defined (errno) -extern int errno; -#endif /* !errno */ - -#include "posixstat.h" - /* System-specific feature definitions and include files. */ #include "rldefs.h" @@ -54,6 +40,11 @@ extern int errno; # include #endif /* GWINSZ_IN_SYS_IOCTL */ +#if defined (__GO32__) +# undef HANDLE_SIGNALS +#endif /* __GO32__ */ + +#if defined (HANDLE_SIGNALS) /* Some standard library routines. */ #include "readline.h" #include "history.h" @@ -63,72 +54,60 @@ extern int rl_pending_input; extern int _rl_meta_flag; extern void free_undo_list (); +extern void _rl_get_screen_size (); +extern void _rl_redisplay_after_sigwinch (); +extern void _rl_clean_up_for_exit (); +extern void _rl_kill_kbd_macro (); +extern void _rl_init_argument (); +extern void rl_deprep_terminal (), rl_prep_terminal (); + +#if !defined (RETSIGTYPE) +# if defined (VOID_SIGHANDLER) +# define RETSIGTYPE void +# else +# define RETSIGTYPE int +# endif /* !VOID_SIGHANDLER */ +#endif /* !RETSIGTYPE */ #if defined (VOID_SIGHANDLER) -# define sighandler void +# define SIGHANDLER_RETURN return #else -# define sighandler int -#endif /* VOID_SIGHANDLER */ +# define SIGHANDLER_RETURN return (0) +#endif /* This typedef is equivalant to the one for Function; it allows us to say SigHandler *foo = signal (SIGKILL, SIG_IGN); */ -typedef sighandler SigHandler (); +typedef RETSIGTYPE SigHandler (); -#if defined (__GO32__) -# undef HANDLE_SIGNALS -#endif /* __GO32__ */ +static SigHandler *rl_set_sighandler (); -#if defined (STATIC_MALLOC) -static char *xmalloc (), *xrealloc (); -#else -extern char *xmalloc (), *xrealloc (); -#endif /* STATIC_MALLOC */ - - /* **************************************************************** */ /* */ /* Signal Handling */ /* */ /* **************************************************************** */ -#if defined (SIGWINCH) -static SigHandler *old_sigwinch = (SigHandler *)NULL; - -static sighandler -rl_handle_sigwinch (sig) - int sig; -{ - if (readline_echoing_p) - { - _rl_set_screen_size (fileno (rl_instream), 1); - _rl_redisplay_after_sigwinch (); - } +#if defined (HAVE_POSIX_SIGNALS) +typedef struct sigaction sighandler_cxt; +# define rl_sigaction(s, nh, oh) sigaction(s, nh, oh) +#else +typedef struct { SigHandler *sa_handler; } sighandler_cxt; +# define sigemptyset(m) +#endif /* !HAVE_POSIX_SIGNALS */ - if (old_sigwinch && - old_sigwinch != (SigHandler *)SIG_IGN && - old_sigwinch != (SigHandler *)SIG_DFL) - (*old_sigwinch) (sig); -#if !defined (VOID_SIGHANDLER) - return (0); -#endif /* VOID_SIGHANDLER */ -} -#endif /* SIGWINCH */ +static sighandler_cxt old_int, old_alrm; -#if defined (HANDLE_SIGNALS) -/* Interrupt handling. */ -static SigHandler - *old_int = (SigHandler *)NULL, - *old_alrm = (SigHandler *)NULL; #if !defined (SHELL) -static SigHandler - *old_tstp = (SigHandler *)NULL, - *old_ttou = (SigHandler *)NULL, - *old_ttin = (SigHandler *)NULL, - *old_cont = (SigHandler *)NULL; +static sighandler_cxt old_tstp, old_ttou, old_ttin, old_term; #endif /* !SHELL */ -/* Handle an interrupt character. */ -static sighandler +#if defined (SIGWINCH) +static sighandler_cxt old_winch; +#endif + +/* Readline signal handler functions. */ + +static RETSIGTYPE rl_signal_handler (sig) int sig; { @@ -143,9 +122,9 @@ rl_signal_handler (sig) #if !defined (HAVE_BSD_SIGNALS) && !defined (HAVE_POSIX_SIGNALS) /* Since the signal will not be blocked while we are in the signal handler, ignore it until rl_clear_signals resets the catcher. */ - if (sig == SIGINT) - signal (sig, SIG_IGN); -#endif /* !HAVE_BSD_SIGNALS */ + if (sig == SIGINT || sig == SIGALRM) + rl_set_sighandler (sig, SIG_IGN, (sighandler_cxt *)NULL); +#endif /* !HAVE_BSD_SIGNALS && !HAVE_POSIX_SIGNALS */ switch (sig) { @@ -161,7 +140,7 @@ rl_signal_handler (sig) } _rl_kill_kbd_macro (); rl_clear_message (); - rl_init_argument (); + _rl_init_argument (); #if defined (SIGTSTP) case SIGTSTP: @@ -169,8 +148,9 @@ rl_signal_handler (sig) case SIGTTIN: #endif /* SIGTSTP */ case SIGALRM: - rl_clean_up_for_exit (); - rl_deprep_terminal (); + case SIGTERM: + _rl_clean_up_for_exit (); + (*rl_deprep_term_function) (); rl_clear_signals (); rl_pending_input = 0; @@ -194,92 +174,159 @@ rl_signal_handler (sig) # endif /* HAVE_BSD_SIGNALS */ #endif /* !HAVE_POSIX_SIGNALS */ - rl_prep_terminal (_rl_meta_flag); + (*rl_prep_term_function) (_rl_meta_flag); rl_set_signals (); } -#if !defined (VOID_SIGHANDLER) - return (0); -#endif /* !VOID_SIGHANDLER */ + SIGHANDLER_RETURN; } -#if defined (HAVE_POSIX_SIGNALS) +#if defined (SIGWINCH) +static RETSIGTYPE +rl_handle_sigwinch (sig) + int sig; +{ + SigHandler *oh; + + if (readline_echoing_p) + { + _rl_get_screen_size (fileno (rl_instream), 1); + _rl_redisplay_after_sigwinch (); + } + + /* If another sigwinch handler has been installed, call it. */ + oh = (SigHandler *)old_winch.sa_handler; + if (oh && oh != (SigHandler *)SIG_IGN && oh != (SigHandler *)SIG_DFL) + (*oh) (sig); + + SIGHANDLER_RETURN; +} +#endif /* SIGWINCH */ + +/* Functions to manage signal handling. */ + +#if !defined (HAVE_POSIX_SIGNALS) +static int +rl_sigaction (sig, nh, oh) + int sig; + sighandler_cxt *nh, *oh; +{ + oh->sa_handler = signal (sig, nh->sa_handler); + return 0; +} +#endif /* !HAVE_POSIX_SIGNALS */ + +/* Set up a readline-specific signal handler, saving the old signal + information in OHANDLER. Return the old signal handler, like + signal(). */ static SigHandler * -rl_set_sighandler (sig, handler) +rl_set_sighandler (sig, handler, ohandler) int sig; SigHandler *handler; + sighandler_cxt *ohandler; { - struct sigaction act, oact; +#if defined (HAVE_POSIX_SIGNALS) + struct sigaction act; act.sa_handler = handler; act.sa_flags = 0; sigemptyset (&act.sa_mask); - sigemptyset (&oact.sa_mask); - sigaction (sig, &act, &oact); - return (oact.sa_handler); -} - -#else /* !HAVE_POSIX_SIGNALS */ -# define rl_set_sighandler(sig, handler) (SigHandler *)signal (sig, handler) + sigemptyset (&ohandler->sa_mask); + sigaction (sig, &act, ohandler); +#else + ohandler->sa_handler = (SigHandler *)signal (sig, handler); #endif /* !HAVE_POSIX_SIGNALS */ + return (ohandler->sa_handler); +} +int rl_set_signals () { - old_int = (SigHandler *)rl_set_sighandler (SIGINT, rl_signal_handler); - if (old_int == (SigHandler *)SIG_IGN) - rl_set_sighandler (SIGINT, SIG_IGN); + sighandler_cxt dummy; + SigHandler *oh; + +#if defined (HAVE_POSIX_SIGNALS) + sigemptyset (&dummy.sa_mask); +#endif - old_alrm = (SigHandler *)rl_set_sighandler (SIGALRM, rl_signal_handler); - if (old_alrm == (SigHandler *)SIG_IGN) - rl_set_sighandler (SIGALRM, SIG_IGN); + oh = rl_set_sighandler (SIGINT, rl_signal_handler, &old_int); + if (oh == (SigHandler *)SIG_IGN) + rl_sigaction (SIGINT, &old_int, &dummy); + + oh = rl_set_sighandler (SIGALRM, rl_signal_handler, &old_alrm); + if (oh == (SigHandler *)SIG_IGN) + rl_sigaction (SIGALRM, &old_alrm, &dummy); +#if defined (HAVE_POSIX_SIGNALS) && defined (SA_RESTART) + /* If the application using readline has already installed a signal + handler with SA_RESTART, SIGALRM will cause reads to be restarted + automatically, so readline should just get out of the way. Since + we tested for SIG_IGN above, we can just test for SIG_DFL here. */ + if (oh != (SigHandler *)SIG_DFL && (old_alrm.sa_flags & SA_RESTART)) + rl_sigaction (SIGALRM, &old_alrm, &dummy); +#endif /* HAVE_POSIX_SIGNALS */ #if !defined (SHELL) #if defined (SIGTSTP) - old_tstp = (SigHandler *)rl_set_sighandler (SIGTSTP, rl_signal_handler); - if (old_tstp == (SigHandler *)SIG_IGN) - rl_set_sighandler (SIGTSTP, SIG_IGN); + oh = rl_set_sighandler (SIGTSTP, rl_signal_handler, &old_tstp); + if (oh == (SigHandler *)SIG_IGN) + rl_sigaction (SIGTSTP, &old_tstp, &dummy); +#else + oh = (SigHandler *)NULL; #endif /* SIGTSTP */ + #if defined (SIGTTOU) - old_ttou = (SigHandler *)rl_set_sighandler (SIGTTOU, rl_signal_handler); - old_ttin = (SigHandler *)rl_set_sighandler (SIGTTIN, rl_signal_handler); + rl_set_sighandler (SIGTTOU, rl_signal_handler, &old_ttou); + rl_set_sighandler (SIGTTIN, rl_signal_handler, &old_ttin); - if (old_tstp == (SigHandler *)SIG_IGN) + if (oh == (SigHandler *)SIG_IGN) { - rl_set_sighandler (SIGTTOU, SIG_IGN); - rl_set_sighandler (SIGTTIN, SIG_IGN); + rl_set_sighandler (SIGTTOU, SIG_IGN, &dummy); + rl_set_sighandler (SIGTTIN, SIG_IGN, &dummy); } #endif /* SIGTTOU */ + /* Handle SIGTERM if we're not being compiled as part of bash. */ + rl_set_sighandler (SIGTERM, rl_signal_handler, &old_term); #endif /* !SHELL */ #if defined (SIGWINCH) - old_sigwinch = - (SigHandler *) rl_set_sighandler (SIGWINCH, rl_handle_sigwinch); + rl_set_sighandler (SIGWINCH, rl_handle_sigwinch, &old_winch); #endif /* SIGWINCH */ + return 0; } +int rl_clear_signals () { - rl_set_sighandler (SIGINT, old_int); - rl_set_sighandler (SIGALRM, old_alrm); + sighandler_cxt dummy; + +#if defined (HAVE_POSIX_SIGNALS) + sigemptyset (&dummy.sa_mask); +#endif + + rl_sigaction (SIGINT, &old_int, &dummy); + rl_sigaction (SIGALRM, &old_alrm, &dummy); #if !defined (SHELL) #if defined (SIGTSTP) - rl_set_sighandler (SIGTSTP, old_tstp); + rl_sigaction (SIGTSTP, &old_tstp, &dummy); #endif #if defined (SIGTTOU) - rl_set_sighandler (SIGTTOU, old_ttou); - rl_set_sighandler (SIGTTIN, old_ttin); + rl_sigaction (SIGTTOU, &old_ttou, &dummy); + rl_sigaction (SIGTTIN, &old_ttin, &dummy); #endif /* SIGTTOU */ + rl_sigaction (SIGTERM, &old_term, &dummy); + #endif /* !SHELL */ #if defined (SIGWINCH) - rl_set_sighandler (SIGWINCH, old_sigwinch); + sigemptyset (&dummy.sa_mask); + rl_sigaction (SIGWINCH, &old_winch, &dummy); #endif return 0; diff --git a/lib/readline/tcap.h b/lib/readline/tcap.h new file mode 100644 index 0000000..0673288 --- /dev/null +++ b/lib/readline/tcap.h @@ -0,0 +1,57 @@ +/* tcap.h -- termcap library functions and variables. */ + +/* Copyright (C) 1996 Free Software Foundation, Inc. + + This file contains the Readline Library (the Library), a set of + routines for providing Emacs style line input to programs that ask + for it. + + The 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 1, or (at your option) + any later version. + + The 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, + 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#if !defined (_RLTCAP_H_) +#define _RLTCAP_H_ + +#if defined (HAVE_CONFIG_H) +# include "config.h" +#endif + +#if defined (HAVE_TERMCAP_H) +# include +#else + +/* On Solaris2, sys/types.h #includes sys/reg.h, which #defines PC. + Unfortunately, PC is a global variable used by the termcap library. */ +#ifdef PC +# undef PC +#endif + +extern char PC; +extern char *UP, *BC; + +extern short ospeed; + +extern int tgetent (); +extern int tgetflag (); +extern int tgetnum (); +extern char *tgetstr (); + +extern int tputs (); + +extern char *tgoto (); + +#endif /* HAVE_TERMCAP_H */ + +#endif /* !_RLTCAP_H_ */ diff --git a/lib/readline/terminal.c b/lib/readline/terminal.c new file mode 100644 index 0000000..9ca9bc6 --- /dev/null +++ b/lib/readline/terminal.c @@ -0,0 +1,554 @@ +/* terminal.c -- controlling the terminal with termcap. */ + +/* Copyright (C) 1996 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 1, 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, + 675 Mass Ave, Cambridge, MA 02139, USA. */ +#define READLINE_LIBRARY + +#if defined (HAVE_CONFIG_H) +# include +#endif + +#include +#include "posixstat.h" +#include +#if defined (HAVE_SYS_FILE_H) +# include +#endif /* HAVE_SYS_FILE_H */ + +#if defined (HAVE_UNISTD_H) +# include +#endif /* HAVE_UNISTD_H */ + +#if defined (HAVE_STDLIB_H) +# include +#else +# include "ansi_stdlib.h" +#endif /* HAVE_STDLIB_H */ + +#if defined (HAVE_LOCALE_H) +# include +#endif + +#include +#include +#include + +/* System-specific feature definitions and include files. */ +#include "rldefs.h" + +#include "tcap.h" + +#if defined (GWINSZ_IN_SYS_IOCTL) +# include +#endif /* GWINSZ_IN_SYS_IOCTL */ + +/* Some standard library routines. */ +#include "readline.h" +#include "history.h" + +/* Variables and functions imported from readline.c */ +extern FILE *_rl_in_stream, *_rl_out_stream; +extern int readline_echoing_p; +extern int _rl_bell_preference; +extern Keymap _rl_keymap; + +/* **************************************************************** */ +/* */ +/* Terminal and Termcap */ +/* */ +/* **************************************************************** */ + +static char *term_buffer = (char *)NULL; +static char *term_string_buffer = (char *)NULL; + +static int tcap_initialized; + +/* Non-zero means this terminal can't really do anything. */ +static int dumb_term; + +#if !defined (__linux__) +/* If this causes problems, add back the `extern'. */ +/*extern*/ char PC, *BC, *UP; +#endif /* __linux__ */ + +/* Some strings to control terminal actions. These are output by tputs (). */ +char *term_goto, *term_clreol, *term_cr, *term_clrpag, *term_backspace; +char *term_pc; + +/* Non-zero if we determine that the terminal can do character insertion. */ +int terminal_can_insert = 0; + +/* How to insert characters. */ +char *term_im, *term_ei, *term_ic, *term_ip, *term_IC; + +/* How to delete characters. */ +char *term_dc, *term_DC; + +#if defined (HACK_TERMCAP_MOTION) +char *term_forward_char; +#endif /* HACK_TERMCAP_MOTION */ + +/* How to go up a line. */ +char *term_up; + +/* A visible bell, if the terminal can be made to flash the screen. */ +static char *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 *term_mm, *term_mo; + +/* The key sequences output by the arrow keys, if this terminal has any. */ +static char *term_ku, *term_kd, *term_kr, *term_kl; + +/* How to initialize and reset the arrow keys, if this terminal has any. */ +static char *term_ks, *term_ke; + +/* The key sequences sent by the Home and End keys, if any. */ +static char *term_kh, *term_kH; + +/* Variables that hold the screen dimensions, used by the display code. */ +int screenwidth, screenheight, 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; + +/* Re-initialize the terminal considering that the TERM/TERMCAP variable + has changed. */ +int +rl_reset_terminal (terminal_name) + char *terminal_name; +{ + _rl_init_terminal_io (terminal_name); + return 0; +} + +#if !defined (SHELL) +static void +set_lines_and_columns (lines, cols) + int lines, cols; +{ + char *b; + +#if defined (HAVE_PUTENV) + b = xmalloc (24); + sprintf (b, "LINES=%d", lines); + putenv (b); + b = xmalloc (24); + sprintf (b, "COLUMNS=%d", cols); + putenv (b); +#else /* !HAVE_PUTENV */ +# if defined (HAVE_SETENV) + b = xmalloc (8); + sprintf (b, "%d", lines); + setenv ("LINES", b, 1); + b = xmalloc (8); + sprintf (b, "%d", cols); + setenv ("COLUMNS", b, 1); +# endif /* HAVE_SETENV */ +#endif /* !HAVE_PUTENV */ +} +#else /* SHELL */ +extern void set_lines_and_columns (); +#endif /* SHELL */ + +/* 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 */ + +#if defined (TIOCGWINSZ) + if (ioctl (tty, TIOCGWINSZ, &window_size) == 0) + { + screenwidth = (int) window_size.ws_col; + screenheight = (int) window_size.ws_row; + } +#endif /* TIOCGWINSZ */ + + /* Environment variable COLUMNS overrides setting of "co" if IGNORE_ENV + is unset. */ + if (screenwidth <= 0) + { + if (ignore_env == 0 && (ss = getenv ("COLUMNS"))) + screenwidth = atoi (ss); + + if (screenwidth <= 0 && term_string_buffer) + screenwidth = tgetnum ("co"); + } + + /* Environment variable LINES overrides setting of "li" if IGNORE_ENV + is unset. */ + if (screenheight <= 0) + { + if (ignore_env == 0 && (ss = getenv ("LINES"))) + screenheight = atoi (ss); + + if (screenheight <= 0 && term_string_buffer) + screenheight = tgetnum ("li"); + } + + /* If all else fails, default to 80x24 terminal. */ + if (screenwidth <= 1) + screenwidth = 80; + + if (screenheight <= 0) + 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. */ + set_lines_and_columns (screenheight, screenwidth); + + if (!_rl_term_autowrap) + screenwidth--; + + screenchars = screenwidth * screenheight; +} + +void +_rl_set_screen_size (rows, cols) + int rows, cols; +{ + screenheight = rows; + screenwidth = cols; + + if (_rl_term_autowrap == 0) + screenwidth--; + + screenchars = screenwidth * screenheight; +} + +struct _tc_string { + 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[] = +{ + "DC", &term_DC, + "IC", &term_IC, + "ce", &term_clreol, + "cl", &term_clrpag, + "cr", &term_cr, + "dc", &term_dc, + "ei", &term_ei, + "ic", &term_ic, + "im", &term_im, + "kd", &term_kd, + "kh", &term_kh, /* home */ + "kH", &term_kH, /* end */ + "kl", &term_kl, + "kr", &term_kr, + "ku", &term_ku, + "ks", &term_ks, + "ke", &term_ke, + "le", &term_backspace, + "mm", &term_mm, + "mo", &term_mo, +#if defined (HACK_TERMCAP_MOTION) + "nd", &term_forward_char, +#endif + "pc", &term_pc, + "up", &term_up, + "vb", &visible_bell, +}; + +#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; +{ + register int i; + + for (i = 0; i < NUM_TC_STRINGS; i++) + *(tc_strings[i].tc_value) = tgetstr (tc_strings[i].tc_var, bp); + tcap_initialized = 1; +} + +int +_rl_init_terminal_io (terminal_name) + char *terminal_name; +{ +#if defined (__GO32__) + screenwidth = ScreenCols (); + screenheight = ScreenRows (); + screenchars = screenwidth * screenheight; + term_cr = "\r"; + term_im = term_ei = term_ic = term_IC = (char *)NULL; + term_up = term_dc = term_DC = visible_bell = (char *)NULL; + + /* Does the __GO32__ have a meta key? I don't know. */ + term_has_meta = 0; + term_mm = term_mo = (char *)NULL; + + /* It probably has arrow keys, but I don't know what they are. */ + term_ku = term_kd = term_kr = term_kl = (char *)NULL; + +#if defined (HACK_TERMCAP_MOTION) + term_forward_char = (char *)NULL; +#endif /* HACK_TERMCAP_MOTION */ + terminal_can_insert = _rl_term_autowrap = 0; + return; +#else /* !__GO32__ */ + + char *term, *buffer; + int tty; + Keymap xkeymap; + + term = terminal_name ? terminal_name : getenv ("TERM"); + + if (term_string_buffer == 0) + term_string_buffer = xmalloc (2032); + + if (term_buffer == 0) + term_buffer = xmalloc (4080); + + buffer = term_string_buffer; + + term_clrpag = term_cr = term_clreol = (char *)NULL; + + if (term == 0) + term = "dumb"; + + if (tgetent (term_buffer, term) <= 0) + { + dumb_term = 1; + screenwidth = 79; + screenheight = 24; + screenchars = 79 * 24; + term_cr = "\r"; + term_im = term_ei = term_ic = term_IC = (char *)NULL; + term_up = term_dc = term_DC = visible_bell = (char *)NULL; + term_ku = term_kd = term_kl = term_kr = (char *)NULL; +#if defined (HACK_TERMCAP_MOTION) + term_forward_char = (char *)NULL; +#endif + terminal_can_insert = 0; + return 0; + } + + get_term_capabilities (&buffer); + + /* Set up the variables that the termcap library expects the application + to provide. */ + PC = term_pc ? *term_pc : 0; + BC = term_backspace; + UP = term_up; + + if (!term_cr) + term_cr = "\r"; + + tty = rl_instream ? fileno (rl_instream) : 0; + + screenwidth = screenheight = 0; + + _rl_term_autowrap = tgetflag ("am") && tgetflag ("xn"); + + _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... */ + terminal_can_insert = (term_IC || term_im || 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) + term_mm = term_mo = (char *)NULL; + + /* Attempt to find and bind the arrow keys. Do not override already + bound keys in an overzealous attempt, however. */ + xkeymap = _rl_keymap; + + _rl_keymap = emacs_standard_keymap; + _rl_bind_if_unbound (term_ku, rl_get_previous_history); + _rl_bind_if_unbound (term_kd, rl_get_next_history); + _rl_bind_if_unbound (term_kr, rl_forward); + _rl_bind_if_unbound (term_kl, rl_backward); + + _rl_bind_if_unbound (term_kh, rl_beg_of_line); /* Home */ + _rl_bind_if_unbound (term_kH, rl_end_of_line); /* End */ + +#if defined (VI_MODE) + _rl_keymap = vi_movement_keymap; + _rl_bind_if_unbound (term_ku, rl_get_previous_history); + _rl_bind_if_unbound (term_kd, rl_get_next_history); + _rl_bind_if_unbound (term_kr, rl_forward); + _rl_bind_if_unbound (term_kl, rl_backward); + + _rl_bind_if_unbound (term_kh, rl_beg_of_line); /* Home */ + _rl_bind_if_unbound (term_kH, rl_end_of_line); /* End */ +#endif /* VI_MODE */ + + _rl_keymap = xkeymap; + +#endif /* !__GO32__ */ + return 0; +} + +char * +rl_get_termcap (cap) + 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); +} + +/* A function for the use of tputs () */ +int +_rl_output_character_function (c) + int c; +{ + return putc (c, _rl_out_stream); +} + +/* Write COUNT characters from STRING to the output stream. */ +void +_rl_output_some_chars (string, count) + 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 !defined (__GO32__) + if (term_backspace) + for (i = 0; i < count; i++) + tputs (term_backspace, 1, _rl_output_character_function); + else +#endif /* !__GO32__ */ + for (i = 0; i < count; i++) + putc ('\b', _rl_out_stream); + return 0; +} + +/* Move to the start of the next line. */ +int +crlf () +{ +#if defined (NEW_TTY_DRIVER) + if (term_cr) + tputs (term_cr, 1, _rl_output_character_function); +#endif /* NEW_TTY_DRIVER */ + putc ('\n', _rl_out_stream); + return 0; +} + +/* Ring the terminal bell. */ +int +ding () +{ + if (readline_echoing_p) + { +#if !defined (__GO32__) + switch (_rl_bell_preference) + { + case NO_BELL: + default: + break; + case VISIBLE_BELL: + if (visible_bell) + { + tputs (visible_bell, 1, _rl_output_character_function); + break; + } + /* FALLTHROUGH */ + case AUDIBLE_BELL: + fprintf (stderr, "\007"); + fflush (stderr); + break; + } +#else /* __GO32__ */ + fprintf (stderr, "\007"); + fflush (stderr); +#endif /* __GO32__ */ + return (0); + } + return (-1); +} + +/* **************************************************************** */ +/* */ +/* Controlling the Meta Key and Keypad */ +/* */ +/* **************************************************************** */ + +static int +outchar (c) + int c; +{ + return putc (c, rl_outstream); +} + +int +_rl_enable_meta_key () +{ + if (term_has_meta && term_mm) + tputs (term_mm, 1, outchar); +} + +void +_rl_control_keypad (on) + int on; +{ + if (on && term_ks) + tputs (term_ks, 1, outchar); + else if (!on && term_ke) + tputs (term_ke, 1, outchar); +} diff --git a/lib/readline/tilde.c b/lib/readline/tilde.c index da75d95..69f5768 100644 --- a/lib/readline/tilde.c +++ b/lib/readline/tilde.c @@ -19,6 +19,10 @@ along with Readline; see the file COPYING. If not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ +#if defined (HAVE_CONFIG_H) +# include +#endif + #if defined (HAVE_STRING_H) # include #else /* !HAVE_STRING_H */ @@ -31,13 +35,14 @@ # include "ansi_stdlib.h" #endif /* HAVE_STDLIB_H */ -#include "tilde.h" #include #include -#if defined (USG) && !defined (HAVE_GETPW_DECLS) +#include "tilde.h" + +#if !defined (HAVE_GETPW_DECLS) extern struct passwd *getpwuid (), *getpwnam (); -#endif /* USG && !defined (HAVE_GETPW_DECLS) */ +#endif /* !HAVE_GETPW_DECLS */ #if !defined (savestring) extern char *xmalloc (); @@ -171,7 +176,7 @@ tilde_expand (string) /* Copy the skipped text into the result. */ if ((result_index + start + 1) > result_size) - result = (char *)xrealloc (result, 1 + (result_size += (start + 20))); + result = xrealloc (result, 1 + (result_size += (start + 20))); strncpy (result + result_index, string, start); result_index += start; @@ -188,7 +193,7 @@ tilde_expand (string) break; /* Expand the entire tilde word, and copy it into RESULT. */ - tilde_word = (char *)xmalloc (1 + end); + tilde_word = xmalloc (1 + end); strncpy (tilde_word, string, end); tilde_word[end] = '\0'; string += end; @@ -198,7 +203,7 @@ tilde_expand (string) len = strlen (expansion); if ((result_index + len + 1) > result_size) - result = (char *)xrealloc (result, 1 + (result_size += (len + 20))); + result = xrealloc (result, 1 + (result_size += (len + 20))); strcpy (result + result_index, expansion); result_index += len; @@ -217,85 +222,90 @@ tilde_expand_word (filename) char *filename; { char *dirname; + char *temp_name; - dirname = filename ? savestring (filename) : (char *)NULL; + if (filename == (char *)0) + return ((char *)NULL); - if (dirname && *dirname == '~') + dirname = savestring (filename); + + if (*dirname != '~') + return (dirname); + + if (!dirname[1] || dirname[1] == '/') { - char *temp_name; - if (!dirname[1] || dirname[1] == '/') + /* Prepend $HOME to the rest of the string. */ + char *temp_home = (char *)getenv ("HOME"); + int home_len; + + /* If there is no HOME variable, look up the directory in + the password database. */ + if (!temp_home) { - /* Prepend $HOME to the rest of the string. */ - char *temp_home = (char *)getenv ("HOME"); + struct passwd *entry; - /* If there is no HOME variable, look up the directory in - the password database. */ - if (!temp_home) - { - struct passwd *entry; + entry = getpwuid (getuid ()); + if (entry) + temp_home = entry->pw_dir; + } - entry = getpwuid (getuid ()); - if (entry) - temp_home = entry->pw_dir; - } + home_len = temp_home ? strlen (temp_home) : 0; + temp_name = xmalloc (1 + strlen (dirname + 1) + home_len); + + if (temp_home) + strcpy (temp_name, temp_home); + strcpy (temp_name + home_len, dirname + 1); + free (dirname); + dirname = temp_name; + } + else + { + char *username; + struct passwd *user_entry; + int i, len; - temp_name = xmalloc (1 + strlen (&dirname[1]) - + (temp_home ? strlen (temp_home) : 0)); - temp_name[0] = '\0'; - if (temp_home) - strcpy (temp_name, temp_home); - strcat (temp_name, dirname + 1); - free (dirname); - dirname = temp_name; - } - else + username = xmalloc (strlen (dirname)); + for (i = 1; dirname[i] && dirname[i] != '/'; i++) + username[i - 1] = dirname[i]; + username[i - 1] = '\0'; + + if ((user_entry = getpwnam (username)) == (struct passwd *)0) { - char *username; - struct passwd *user_entry; - int i; + /* If the calling program has a special syntax for + expanding tildes, and we couldn't find a standard + expansion, then let them try. */ + if (tilde_expansion_failure_hook) + { + char *expansion; - username = xmalloc (strlen (dirname)); - for (i = 1; dirname[i] && dirname[i] != '/'; i++) - username[i - 1] = dirname[i]; - username[i - 1] = '\0'; + expansion = (*tilde_expansion_failure_hook) (username); - if ((user_entry = getpwnam (username)) == 0) - { - /* If the calling program has a special syntax for - expanding tildes, and we couldn't find a standard - expansion, then let them try. */ - if (tilde_expansion_failure_hook) + if (expansion) { - char *expansion; - - expansion = (*tilde_expansion_failure_hook) (username); - - if (expansion) - { - temp_name = xmalloc (1 + strlen (expansion) - + strlen (&dirname[i])); - strcpy (temp_name, expansion); - strcat (temp_name, &dirname[i]); - free (expansion); - free (dirname); - dirname = temp_name; - } + len = strlen (expansion); + temp_name = xmalloc (1 + len + strlen (dirname + i)); + strcpy (temp_name, expansion); + strcpy (temp_name + len, dirname + i); + free (expansion); + free (dirname); + dirname = temp_name; } - /* We shouldn't report errors. */ - } - else - { - temp_name = xmalloc (1 + strlen (user_entry->pw_dir) - + strlen (&dirname[i])); - strcpy (temp_name, user_entry->pw_dir); - strcat (temp_name, &dirname[i]); - free (dirname); - dirname = temp_name; } - endpwent (); - free (username); + /* We shouldn't report errors. */ } + else + { + len = strlen (user_entry->pw_dir); + temp_name = xmalloc (1 + len + strlen (dirname + i)); + strcpy (temp_name, user_entry->pw_dir); + strcpy (temp_name + len, dirname + i); + free (dirname); + dirname = temp_name; + } + endpwent (); + free (username); } + return (dirname); } @@ -368,7 +378,7 @@ xrealloc (pointer, bytes) static void memory_error_and_abort () { - fprintf (stderr, "readline: Out of virtual memory!\n"); + fprintf (stderr, "readline: out of virtual memory\n"); abort (); } diff --git a/lib/readline/tilde.h b/lib/readline/tilde.h index 726d081..6f0898c 100644 --- a/lib/readline/tilde.h +++ b/lib/readline/tilde.h @@ -1,11 +1,32 @@ /* tilde.h: Externally available variables and function in libtilde.a. */ -#if !defined (__TILDE_H__) -# define __TILDE_H__ +/* Copyright (C) 1992 Free Software Foundation, Inc. + + This file contains the Readline Library (the Library), a set of + routines for providing Emacs style line input to programs that ask + for it. + + The 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 1, or (at your option) + any later version. + + The 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, + 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#if !defined (_TILDE_H_) +# define _TILDE_H_ /* Function pointers can be declared as (Function *)foo. */ -#if !defined (__FUNCTION_DEF) -# define __FUNCTION_DEF +#if !defined (_FUNCTION_DEF) +# define _FUNCTION_DEF typedef int Function (); typedef void VFunction (); typedef char *CPFunction (); @@ -35,4 +56,4 @@ extern char *tilde_expand (); tilde. If there is no expansion, call tilde_expansion_failure_hook. */ extern char *tilde_expand_word (); -#endif /* __TILDE_H__ */ +#endif /* _TILDE_H_ */ diff --git a/lib/readline/undo.c b/lib/readline/undo.c new file mode 100644 index 0000000..af7ccc3 --- /dev/null +++ b/lib/readline/undo.c @@ -0,0 +1,261 @@ +/* readline.c -- a general facility for reading lines of input + with emacs style editing and completion. */ + +/* Copyright (C) 1987, 1989, 1992 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 1, 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, + 675 Mass Ave, Cambridge, MA 02139, USA. */ +#define READLINE_LIBRARY + +#if defined (HAVE_CONFIG_H) +# include +#endif + +#include + +#if defined (HAVE_UNISTD_H) +# include /* for _POSIX_VERSION */ +#endif /* HAVE_UNISTD_H */ + +#if defined (HAVE_STDLIB_H) +# include +#else +# include "ansi_stdlib.h" +#endif /* HAVE_STDLIB_H */ + +#include +#include + +/* System-specific feature definitions and include files. */ +#include "rldefs.h" + +/* Some standard library routines. */ +#include "readline.h" +#include "history.h" + +#define SWAP(s, e) do { int t; t = s; s = e; e = t; } while (0) + +/* Non-zero tells rl_delete_text and rl_insert_text to not add to + the undo list. */ +int _rl_doing_an_undo = 0; + +/* How many unclosed undo groups we currently have. */ +int _rl_undo_group_level = 0; + +/* The current undo list for THE_LINE. */ +UNDO_LIST *rl_undo_list = (UNDO_LIST *)NULL; + +/* **************************************************************** */ +/* */ +/* Undo, and Undoing */ +/* */ +/* **************************************************************** */ + +/* Remember how to undo something. Concatenate some undos if that + seems right. */ +void +rl_add_undo (what, start, end, text) + enum undo_code what; + int start, end; + char *text; +{ + UNDO_LIST *temp = (UNDO_LIST *)xmalloc (sizeof (UNDO_LIST)); + temp->what = what; + temp->start = start; + temp->end = end; + temp->text = text; + temp->next = rl_undo_list; + rl_undo_list = temp; +} + +/* Free the existing undo list. */ +void +free_undo_list () +{ + while (rl_undo_list) + { + UNDO_LIST *release = rl_undo_list; + rl_undo_list = rl_undo_list->next; + + if (release->what == UNDO_DELETE) + free (release->text); + + free (release); + } + rl_undo_list = (UNDO_LIST *)NULL; +} + +/* Undo the next thing in the list. Return 0 if there + is nothing to undo, or non-zero if there was. */ +int +rl_do_undo () +{ + UNDO_LIST *release; + int waiting_for_begin = 0; + int start, end; + +#define TRANS(i) ((i) == -1 ? rl_point : ((i) == -2 ? rl_end : (i))) + + do + { + if (!rl_undo_list) + return (0); + + _rl_doing_an_undo = 1; + + /* To better support vi-mode, a start or end value of -1 means + rl_point, and a value of -2 means rl_end. */ + if (rl_undo_list->what == UNDO_DELETE || rl_undo_list->what == UNDO_INSERT) + { + start = TRANS (rl_undo_list->start); + end = TRANS (rl_undo_list->end); + } + + switch (rl_undo_list->what) + { + /* Undoing deletes means inserting some text. */ + case UNDO_DELETE: + rl_point = start; + rl_insert_text (rl_undo_list->text); + free (rl_undo_list->text); + break; + + /* Undoing inserts means deleting some text. */ + case UNDO_INSERT: + rl_delete_text (start, end); + rl_point = start; + break; + + /* Undoing an END means undoing everything 'til we get to a BEGIN. */ + case UNDO_END: + waiting_for_begin++; + break; + + /* Undoing a BEGIN means that we are done with this group. */ + case UNDO_BEGIN: + if (waiting_for_begin) + waiting_for_begin--; + else + ding (); + break; + } + + _rl_doing_an_undo = 0; + + release = rl_undo_list; + rl_undo_list = rl_undo_list->next; + free (release); + } + while (waiting_for_begin); + + return (1); +} +#undef TRANS + +int +_rl_fix_last_undo_of_type (type, start, end) + int type, start, end; +{ + UNDO_LIST *rl; + + for (rl = rl_undo_list; rl; rl = rl->next) + { + if (rl->what == type) + { + rl->start = start; + rl->end = end; + return 0; + } + } + return 1; +} + +/* Begin a group. Subsequent undos are undone as an atomic operation. */ +int +rl_begin_undo_group () +{ + rl_add_undo (UNDO_BEGIN, 0, 0, 0); + _rl_undo_group_level++; + return 0; +} + +/* End an undo group started with rl_begin_undo_group (). */ +int +rl_end_undo_group () +{ + rl_add_undo (UNDO_END, 0, 0, 0); + _rl_undo_group_level--; + return 0; +} + +/* Save an undo entry for the text from START to END. */ +int +rl_modifying (start, end) + int start, end; +{ + if (start > end) + { + SWAP (start, end); + } + + if (start != end) + { + char *temp = rl_copy_text (start, end); + rl_begin_undo_group (); + rl_add_undo (UNDO_DELETE, start, end, temp); + rl_add_undo (UNDO_INSERT, start, end, (char *)NULL); + rl_end_undo_group (); + } + return 0; +} + +/* Revert the current line to its previous state. */ +int +rl_revert_line (count, key) + int count, key; +{ + if (!rl_undo_list) + ding (); + else + { + while (rl_undo_list) + rl_do_undo (); + } + return 0; +} + +/* Do some undoing of things that were done. */ +int +rl_undo_command (count, key) + int count, key; +{ + if (count < 0) + return 0; /* Nothing to do. */ + + while (count) + { + if (rl_do_undo ()) + count--; + else + { + ding (); + break; + } + } + return 0; +} diff --git a/lib/readline/util.c b/lib/readline/util.c new file mode 100644 index 0000000..f63293a --- /dev/null +++ b/lib/readline/util.c @@ -0,0 +1,315 @@ +/* util.c -- readline utility functions */ + +/* Copyright (C) 1987, 1989, 1992 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 1, 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, + 675 Mass Ave, Cambridge, MA 02139, USA. */ +#define READLINE_LIBRARY + +#if defined (HAVE_CONFIG_H) +# include +#endif + +#include +#include +#include +#include +#include + +#if defined (HAVE_UNISTD_H) +# include /* for _POSIX_VERSION */ +#endif /* HAVE_UNISTD_H */ + +#if defined (HAVE_STDLIB_H) +# include +#else +# include "ansi_stdlib.h" +#endif /* HAVE_STDLIB_H */ + +/* System-specific feature definitions and include files. */ +#include "rldefs.h" + +#if defined (TIOCSTAT_IN_SYS_IOCTL) +# include +#endif /* TIOCSTAT_IN_SYS_IOCTL */ + +/* Some standard library routines. */ +#include "readline.h" + +#define SWAP(s, e) do { int t; t = s; s = e; e = t; } while (0) + +/* Pseudo-globals imported from readline.c */ +extern int readline_echoing_p; +extern jmp_buf readline_top_level; +extern int rl_line_buffer_len; +extern Function *rl_last_func; + +extern int _rl_defining_kbd_macro; +extern char *_rl_executing_macro; + +/* Pseudo-global functions imported from other library files. */ +extern void _rl_pop_executing_macro (); +extern void _rl_set_the_line (); +extern void _rl_init_argument (); + +extern char *xmalloc (), *xrealloc (); + +/* **************************************************************** */ +/* */ +/* Utility Functions */ +/* */ +/* **************************************************************** */ + +/* Return 0 if C is not a member of the class of characters that belong + in words, or 1 if it is. */ + +int _rl_allow_pathname_alphabetic_chars = 0; +static char *pathname_alphabetic_chars = "/-_=~.#$"; + +int +alphabetic (c) + int c; +{ + if (ALPHABETIC (c)) + return (1); + + return (_rl_allow_pathname_alphabetic_chars && + strchr (pathname_alphabetic_chars, c) != NULL); +} + +/* How to abort things. */ +int +_rl_abort_internal () +{ + ding (); + rl_clear_message (); + _rl_init_argument (); + rl_pending_input = 0; + + _rl_defining_kbd_macro = 0; + while (_rl_executing_macro) + _rl_pop_executing_macro (); + + rl_last_func = (Function *)NULL; + longjmp (readline_top_level, 1); + return (0); +} + +int +rl_abort (count, key) + int count, key; +{ + return (_rl_abort_internal ()); +} + +int +rl_tty_status (count, key) + int count, key; +{ +#if defined (TIOCSTAT) + ioctl (1, TIOCSTAT, (char *)0); + rl_refresh_line (); +#else + ding (); +#endif + return 0; +} + +/* Return a copy of the string between FROM and TO. + FROM is inclusive, TO is not. */ +char * +rl_copy_text (from, to) + int from, to; +{ + register int length; + char *copy; + + /* Fix it if the caller is confused. */ + if (from > to) + SWAP (from, to); + + length = to - from; + copy = xmalloc (1 + length); + strncpy (copy, rl_line_buffer + from, length); + copy[length] = '\0'; + return (copy); +} + +/* Increase the size of RL_LINE_BUFFER until it has enough space to hold + LEN characters. */ +void +rl_extend_line_buffer (len) + int len; +{ + while (len >= rl_line_buffer_len) + { + rl_line_buffer_len += DEFAULT_BUFFER_SIZE; + rl_line_buffer = xrealloc (rl_line_buffer, rl_line_buffer_len); + } + + _rl_set_the_line (); +} + +/* **************************************************************** */ +/* */ +/* String Utility Functions */ +/* */ +/* **************************************************************** */ + +/* Determine if s2 occurs in s1. If so, return a pointer to the + match in s1. The compare is case insensitive. */ +char * +_rl_strindex (s1, s2) + register char *s1, *s2; +{ + register int i, l, len; + + for (i = 0, l = strlen (s2), len = strlen (s1); (len - i) >= l; i++) + if (_rl_strnicmp (s1 + i, s2, l) == 0) + return (s1 + i); + return ((char *)NULL); +} + +#if !defined (HAVE_STRCASECMP) +/* Compare at most COUNT characters from string1 to string2. Case + doesn't matter. */ +int +_rl_strnicmp (string1, string2, count) + char *string1, *string2; + int count; +{ + register char ch1, ch2; + + while (count) + { + ch1 = *string1++; + ch2 = *string2++; + if (_rl_to_upper(ch1) == _rl_to_upper(ch2)) + count--; + else + break; + } + return (count); +} + +/* strcmp (), but caseless. */ +int +_rl_stricmp (string1, string2) + char *string1, *string2; +{ + register char ch1, ch2; + + while (*string1 && *string2) + { + ch1 = *string1++; + ch2 = *string2++; + if (_rl_to_upper(ch1) != _rl_to_upper(ch2)) + return (1); + } + return (*string1 - *string2); +} +#endif /* !HAVE_STRCASECMP */ + +/* Stupid comparison routine for qsort () ing strings. */ +int +_rl_qsort_string_compare (s1, s2) + char **s1, **s2; +{ +#if defined (HAVE_STRCOLL) + return (strcoll (*s1, *s2)); +#else + int result; + + result = **s1 - **s2; + if (result == 0) + result = strcmp (*s1, *s2); + + return result; +#endif +} + +#if !defined (SHELL) +#ifdef savestring +#undef savestring +#endif +/* Backwards compatibility, now that savestring has been removed from + all `public' readline header files. */ +char * +savestring (s) + char *s; +{ + return ((char *)strcpy (xmalloc (1 + (int)strlen (s)), (s))); +} +#endif /* !SHELL */ + +/* Function equivalents for the macros defined in chartypes.h. */ +#undef _rl_uppercase_p +int +_rl_uppercase_p (c) + int c; +{ + return (isupper (c)); +} + +#undef _rl_lowercase_p +int +_rl_lowercase_p (c) + int c; +{ + return (islower (c)); +} + +#undef _rl_pure_alphabetic +int +_rl_pure_alphabetic (c) + int c; +{ + return (isupper (c) || islower (c)); +} + +#undef _rl_digit_p +int +_rl_digit_p (c) + int c; +{ + return (isdigit (c)); +} + +#undef _rl_to_lower +int +_rl_to_lower (c) + int c; +{ + return (isupper (c) ? tolower (c) : c); +} + +#undef _rl_to_upper +int +_rl_to_upper (c) + int c; +{ + return (islower (c) ? toupper (c) : c); +} + +#undef _rl_digit_value +int +_rl_digit_value (c) + int c; +{ + return (isdigit (c) ? c - '0' : c); +} diff --git a/lib/readline/vi_keymap.c b/lib/readline/vi_keymap.c index b8b3123..14929a3 100644 --- a/lib/readline/vi_keymap.c +++ b/lib/readline/vi_keymap.c @@ -65,13 +65,13 @@ KEYMAP_ENTRY_ARRAY vi_movement_keymap = { { ISFUNC, (Function *)0x0 }, /* Control-\ */ { ISFUNC, (Function *)0x0 }, /* Control-] */ { ISFUNC, (Function *)0x0 }, /* Control-^ */ - { ISFUNC, rl_undo_command }, /* Control-_ */ + { ISFUNC, rl_vi_undo }, /* Control-_ */ /* The start of printing characters. */ { ISFUNC, rl_forward }, /* SPACE */ { ISFUNC, (Function *)0x0 }, /* ! */ { ISFUNC, (Function *)0x0 }, /* " */ - { ISFUNC, rl_vi_comment }, /* # */ + { ISFUNC, rl_insert_comment }, /* # */ { ISFUNC, rl_end_of_line }, /* $ */ { ISFUNC, rl_vi_match }, /* % */ { ISFUNC, rl_vi_tilde_expand }, /* & */ @@ -140,7 +140,7 @@ KEYMAP_ENTRY_ARRAY vi_movement_keymap = { { ISFUNC, (Function *)0x0 }, /* ] */ { ISFUNC, rl_vi_first_print }, /* ^ */ { ISFUNC, rl_vi_yank_arg }, /* _ */ - { ISFUNC, (Function *)0x0 }, /* ` */ + { ISFUNC, rl_vi_goto_mark }, /* ` */ /* Lowercase alphabet. */ { ISFUNC, rl_vi_append_mode }, /* a */ @@ -155,7 +155,7 @@ KEYMAP_ENTRY_ARRAY vi_movement_keymap = { { ISFUNC, rl_get_next_history }, /* j */ { ISFUNC, rl_get_previous_history }, /* k */ { ISFUNC, rl_forward }, /* l */ - { ISFUNC, (Function *)0x0 }, /* m */ + { ISFUNC, rl_vi_set_mark }, /* m */ { ISFUNC, rl_vi_search_again }, /* n */ { ISFUNC, (Function *)0x0 }, /* o */ { ISFUNC, rl_vi_put }, /* p */ @@ -163,7 +163,7 @@ KEYMAP_ENTRY_ARRAY vi_movement_keymap = { { ISFUNC, rl_vi_change_char }, /* r */ { ISFUNC, rl_vi_subst }, /* s */ { ISFUNC, rl_vi_char_search }, /* t */ - { ISFUNC, rl_undo_command }, /* u */ + { ISFUNC, rl_vi_undo }, /* u */ { ISFUNC, (Function *)0x0 }, /* v */ { ISFUNC, rl_vi_next_word }, /* w */ { ISFUNC, rl_vi_delete }, /* x */ @@ -345,7 +345,7 @@ KEYMAP_ENTRY_ARRAY vi_insertion_keymap = { { ISFUNC, rl_insert }, /* Control-\ */ { ISFUNC, rl_insert }, /* Control-] */ { ISFUNC, rl_insert }, /* Control-^ */ - { ISFUNC, rl_undo_command }, /* Control-_ */ + { ISFUNC, rl_vi_undo }, /* Control-_ */ /* The start of printing characters. */ { ISFUNC, rl_insert }, /* SPACE */ @@ -630,7 +630,7 @@ KEYMAP_ENTRY_ARRAY vi_escape_keymap = { { ISFUNC, (Function *)0x0 }, /* Control-\ */ { ISFUNC, (Function *)0x0 }, /* Control-] */ { ISFUNC, (Function *)0x0 }, /* Control-^ */ - { ISFUNC, rl_undo_command }, /* Control-_ */ + { ISFUNC, rl_vi_undo }, /* Control-_ */ /* The start of printing characters. */ { ISFUNC, (Function *)0x0 }, /* SPACE */ diff --git a/lib/readline/vi_mode.c b/lib/readline/vi_mode.c index d0b9310..c730296 100644 --- a/lib/readline/vi_mode.c +++ b/lib/readline/vi_mode.c @@ -31,6 +31,10 @@ #if defined (VI_MODE) +#if defined (HAVE_CONFIG_H) +# include +#endif + #include #if defined (HAVE_STDLIB_H) @@ -50,12 +54,12 @@ #include "readline.h" #include "history.h" -#ifndef digit_p -#define digit_p(c) ((c) >= '0' && (c) <= '9') +#ifndef _rl_digit_p +#define _rl_digit_p(c) ((c) >= '0' && (c) <= '9') #endif -#ifndef digit_value -#define digit_value(c) ((c) - '0') +#ifndef _rl_digit_value +#define _rl_digit_value(c) ((c) - '0') #endif #ifndef member @@ -63,22 +67,14 @@ #endif #ifndef isident -#define isident(c) ((pure_alphabetic (c) || digit_p (c) || c == '_')) +#define isident(c) ((_rl_pure_alphabetic (c) || _rl_digit_p (c) || c == '_')) #endif #ifndef exchange #define exchange(x, y) do {int temp = x; x = y; y = temp;} while (0) #endif -#ifndef VI_COMMENT_BEGIN_DEFAULT -#define VI_COMMENT_BEGIN_DEFAULT "#" -#endif - -#if defined (STATIC_MALLOC) -static char *xmalloc (), *xrealloc (); -#else extern char *xmalloc (), *xrealloc (); -#endif /* STATIC_MALLOC */ /* Variables imported from readline.c */ extern int rl_point, rl_end, rl_mark, rl_done; @@ -89,48 +85,64 @@ extern char *rl_prompt; extern char *rl_line_buffer; extern int rl_arg_sign; +extern int _rl_doing_an_undo; +extern int _rl_undo_group_level; + extern void _rl_dispatch (); +extern int _rl_char_search_internal (); extern void rl_extend_line_buffer (); extern int rl_vi_check (); /* Non-zero means enter insertion mode. */ -static int _rl_vi_doing_insert = 0; +static int _rl_vi_doing_insert; -/* String inserted into the line by rl_vi_comment (). */ -char *rl_vi_comment_begin = (char *)NULL; - -/* *** UNCLEAN *** */ /* Command keys which do movement for xxx_to commands. */ static char *vi_motion = " hl^$0ftFt;,%wbeWBE|"; /* Keymap used for vi replace characters. Created dynamically since rarely used. */ -static Keymap vi_replace_map = (Keymap)NULL; +static Keymap vi_replace_map; /* The number of characters inserted in the last replace operation. */ -static int vi_replace_count = 0; +static int vi_replace_count; /* If non-zero, we have text inserted after a c[motion] command that put us implicitly into insert mode. Some people want this text to be attached to the command so that it is `redoable' with `.'. */ -static int vi_continued_command = 0; +static int vi_continued_command; +static char *vi_insert_buffer; +static int vi_insert_buffer_size; static int _rl_vi_last_command = 'i'; /* default `.' puts you in insert mode */ static int _rl_vi_last_repeat = 1; static int _rl_vi_last_arg_sign = 1; -static int _rl_vi_last_motion = 0; -static int _rl_vi_last_search_char = 0; -static int _rl_vi_last_replacement = 0; +static int _rl_vi_last_motion; +static int _rl_vi_last_search_char; +static int _rl_vi_last_replacement; + +static int _rl_vi_last_key_before_insert; -static int vi_redoing = 0; +static int vi_redoing; /* Text modification commands. These are the `redoable' commands. */ static char *vi_textmod = "_*\\AaIiCcDdPpYyRrSsXx~"; +/* Arrays for the saved marks. */ +static int vi_mark_chars[27]; + static int rl_digit_loop1 (); void +_rl_vi_initialize_line () +{ + register int i; + + for (i = 0; i < sizeof (vi_mark_chars) / sizeof (int); i++) + vi_mark_chars[i] = -1; +} + +void _rl_vi_reset_last () { _rl_vi_last_command = 'i'; @@ -150,15 +162,26 @@ _rl_vi_set_last (key, repeat, sign) /* Is the command C a VI mode text modification command? */ int -rl_vi_textmod_command (c) +_rl_vi_textmod_command (c) int c; { return (member (c, vi_textmod)); } +static void +_rl_vi_stuff_insert (count) + int count; +{ + rl_begin_undo_group (); + while (count--) + rl_insert_text (vi_insert_buffer); + rl_end_undo_group (); +} + /* Bound to `.'. Called from command mode, so we know that we have to redo a text modification command. The default for _rl_vi_last_command puts you back into insert mode. */ +int rl_vi_redo (count, c) int count, c; { @@ -169,13 +192,32 @@ rl_vi_redo (count, c) } vi_redoing = 1; - _rl_dispatch (_rl_vi_last_command, _rl_keymap); + /* If we're redoing an insert with `i', stuff in the inserted text + and do not go into insertion mode. */ + if (_rl_vi_last_command == 'i' && vi_insert_buffer && *vi_insert_buffer) + { + _rl_vi_stuff_insert (count); + /* And back up point over the last character inserted. */ + if (rl_point > 0) + rl_point--; + } + else + _rl_dispatch (_rl_vi_last_command, _rl_keymap); vi_redoing = 0; return (0); } + +/* A placeholder for further expansion. */ +int +rl_vi_undo (count, key) + int count, key; +{ + return (rl_undo_command (count, key)); +} /* Yank the nth arg from the previous line into this line at point. */ +int rl_vi_yank_arg (count, key) int count, key; { @@ -191,10 +233,11 @@ rl_vi_yank_arg (count, key) /* With an argument, move back that many history lines, else move to the beginning of history. */ +int rl_vi_fetch_history (count, c) int count, c; { - int current = where_history (); + int wanted; /* Giving an argument of n means we want the nth command in the history file. The command number is interpreted the same way that the bash @@ -203,11 +246,11 @@ rl_vi_fetch_history (count, c) output of `history'. */ if (rl_explicit_arg) { - int wanted = history_base + current - count; + wanted = history_base + where_history () - count; if (wanted <= 0) rl_beginning_of_history (0, 0); else - rl_get_previous_history (wanted); + rl_get_previous_history (wanted, c); } else rl_beginning_of_history (count, 0); @@ -215,6 +258,7 @@ rl_vi_fetch_history (count, c) } /* Search again for the last thing searched for. */ +int rl_vi_search_again (count, key) int count, key; { @@ -232,6 +276,7 @@ rl_vi_search_again (count, key) } /* Do a vi style search. */ +int rl_vi_search (count, key) int count, key; { @@ -253,6 +298,7 @@ rl_vi_search (count, key) } /* Completion, from vi's point of view. */ +int rl_vi_complete (ignore, key) int ignore, key; { @@ -281,6 +327,7 @@ rl_vi_complete (ignore, key) } /* Tilde expansion for vi mode. */ +int rl_vi_tilde_expand (ignore, key) int ignore, key; { @@ -291,6 +338,7 @@ rl_vi_tilde_expand (ignore, key) } /* Previous word in vi mode. */ +int rl_vi_prev_word (count, key) int count, key; { @@ -303,7 +351,7 @@ rl_vi_prev_word (count, key) return (0); } - if (uppercase_p (key)) + if (_rl_uppercase_p (key)) rl_vi_bWord (count); else rl_vi_bword (count); @@ -312,6 +360,7 @@ rl_vi_prev_word (count, key) } /* Next word in vi mode. */ +int rl_vi_next_word (count, key) int count, key; { @@ -324,7 +373,7 @@ rl_vi_next_word (count, key) return (0); } - if (uppercase_p (key)) + if (_rl_uppercase_p (key)) rl_vi_fWord (count); else rl_vi_fword (count); @@ -332,6 +381,7 @@ rl_vi_next_word (count, key) } /* Move to the end of the ?next? word. */ +int rl_vi_end_word (count, key) int count, key; { @@ -341,7 +391,7 @@ rl_vi_end_word (count, key) return -1; } - if (uppercase_p (key)) + if (_rl_uppercase_p (key)) rl_vi_eWord (count); else rl_vi_eword (count); @@ -349,6 +399,7 @@ rl_vi_end_word (count, key) } /* Move forward a word the way that 'W' does. */ +int rl_vi_fWord (count) int count; { @@ -365,6 +416,7 @@ rl_vi_fWord (count) return (0); } +int rl_vi_bWord (count) int count; { @@ -388,6 +440,7 @@ rl_vi_bWord (count) return (0); } +int rl_vi_eWord (count) int count; { @@ -417,6 +470,7 @@ rl_vi_eWord (count) return (0); } +int rl_vi_fword (count) int count; { @@ -442,6 +496,7 @@ rl_vi_fword (count) return (0); } +int rl_vi_bword (count) int count; { @@ -480,6 +535,7 @@ rl_vi_bword (count) return (0); } +int rl_vi_eword (count) int count; { @@ -504,6 +560,7 @@ rl_vi_eword (count) return (0); } +int rl_vi_insert_beg (count, key) int count, key; { @@ -512,6 +569,7 @@ rl_vi_insert_beg (count, key) return (0); } +int rl_vi_append_mode (count, key) int count, key; { @@ -521,6 +579,7 @@ rl_vi_append_mode (count, key) return (0); } +int rl_vi_append_eol (count, key) int count, key; { @@ -530,6 +589,7 @@ rl_vi_append_eol (count, key) } /* What to do in the case of C-d. */ +int rl_vi_eof_maybe (count, c) int count, c; { @@ -540,13 +600,33 @@ rl_vi_eof_maybe (count, c) /* Switching from one mode to the other really just involves switching keymaps. */ +int rl_vi_insertion_mode (count, key) int count, key; { _rl_keymap = vi_insertion_keymap; + _rl_vi_last_key_before_insert = key; return (0); } +static void +_rl_vi_save_insert (up) + UNDO_LIST *up; +{ + int len, start, end; + + start = up->start; + end = up->end; + len = end - start + 1; + if (len >= vi_insert_buffer_size) + { + vi_insert_buffer_size += (len + 32) - (len % 32); + vi_insert_buffer = xrealloc (vi_insert_buffer, vi_insert_buffer_size); + } + strncpy (vi_insert_buffer, rl_line_buffer + start, len - 1); + vi_insert_buffer[len-1] = '\0'; +} + void _rl_vi_done_inserting () { @@ -555,38 +635,49 @@ _rl_vi_done_inserting () rl_end_undo_group (); /* Now, the text between rl_undo_list->next->start and rl_undo_list->next->end is what was inserted while in insert - mode. */ + mode. It gets copied to VI_INSERT_BUFFER because it depends + on absolute indices into the line which may change (though they + probably will not). */ _rl_vi_doing_insert = 0; + _rl_vi_save_insert (rl_undo_list->next); vi_continued_command = 1; } else - vi_continued_command = 0; + { + if (_rl_vi_last_key_before_insert == 'i' && rl_undo_list) + _rl_vi_save_insert (rl_undo_list); + /* XXX - Other keys probably need to be checked. */ + else if (_rl_vi_last_key_before_insert == 'C') + rl_end_undo_group (); + while (_rl_undo_group_level > 0) + rl_end_undo_group (); + vi_continued_command = 0; + } } +int rl_vi_movement_mode (count, key) int count, key; { if (rl_point > 0) - rl_backward (1); - -#if 0 - _rl_vi_reset_last (); -#endif + rl_backward (1, key); _rl_keymap = vi_movement_keymap; _rl_vi_done_inserting (); return (0); } +int rl_vi_arg_digit (count, c) int count, c; { if (c == '0' && rl_numeric_arg == 1 && !rl_explicit_arg) - return (rl_beg_of_line ()); + return (rl_beg_of_line (1, c)); else return (rl_digit_argument (count, c)); } +int rl_vi_change_case (count, ignore) int count, ignore; { @@ -598,14 +689,14 @@ rl_vi_change_case (count, ignore) while (count-- && rl_point < rl_end) { - if (uppercase_p (rl_line_buffer[rl_point])) - c = to_lower (rl_line_buffer[rl_point]); - else if (lowercase_p (rl_line_buffer[rl_point])) - c = to_upper (rl_line_buffer[rl_point]); + if (_rl_uppercase_p (rl_line_buffer[rl_point])) + c = _rl_to_lower (rl_line_buffer[rl_point]); + else if (_rl_lowercase_p (rl_line_buffer[rl_point])) + c = _rl_to_upper (rl_line_buffer[rl_point]); else { /* Just skip over characters neither upper nor lower case. */ - rl_forward (1); + rl_forward (1, c); continue; } @@ -619,22 +710,24 @@ rl_vi_change_case (count, ignore) rl_vi_check (); } else - rl_forward (1); + rl_forward (1, c); } return (0); } +int rl_vi_put (count, key) int count, key; { - if (!uppercase_p (key) && (rl_point + 1 <= rl_end)) + if (!_rl_uppercase_p (key) && (rl_point + 1 <= rl_end)) rl_point++; rl_yank (); - rl_backward (1); + rl_backward (1, key); return (0); } +int rl_vi_check () { if (rl_point && rl_point == rl_end) @@ -642,11 +735,12 @@ rl_vi_check () return (0); } +int rl_vi_column (count, key) int count, key; { if (count > rl_end) - rl_end_of_line (); + rl_end_of_line (1, key); else rl_point = count - 1; return (0); @@ -665,10 +759,10 @@ rl_vi_domove (key, nextkey) if (!member (c, vi_motion)) { - if (digit_p (c)) + if (_rl_digit_p (c)) { save = rl_numeric_arg; - rl_numeric_arg = digit_value (c); + rl_numeric_arg = _rl_digit_value (c); rl_digit_loop1 (); rl_numeric_arg *= save; c = rl_read_key (); /* real command */ @@ -677,7 +771,7 @@ rl_vi_domove (key, nextkey) else if (key == c && (key == 'd' || key == 'y' || key == 'c')) { rl_mark = rl_end; - rl_beg_of_line (); + rl_beg_of_line (1, c); _rl_vi_last_motion = c; return (0); } @@ -708,13 +802,13 @@ rl_vi_domove (key, nextkey) /* rl_vi_f[wW]ord () leaves the cursor on the first character of the next word. If we are not at the end of the line, and we are on a non-whitespace character, move back one (presumably to whitespace). */ - if ((to_upper (c) == 'W') && rl_point < rl_end && rl_point > rl_mark && + if ((_rl_to_upper (c) == 'W') && rl_point < rl_end && rl_point > rl_mark && !whitespace (rl_line_buffer[rl_point])) rl_point--; /* If cw or cW, back up to the end of a word, so the behaviour of ce or cE is the actual result. Brute-force, no subtlety. */ - if (key == 'c' && rl_point >= rl_mark && (to_upper (c) == 'W')) + if (key == 'c' && rl_point >= rl_mark && (_rl_to_upper (c) == 'W')) { /* Don't move farther back than where we started. */ while (rl_point > rl_mark && whitespace (rl_line_buffer[rl_point])) @@ -760,12 +854,12 @@ rl_digit_loop1 () } c = UNMETA (c); - if (digit_p (c)) + if (_rl_digit_p (c)) { if (rl_explicit_arg) - rl_numeric_arg = (rl_numeric_arg * 10) + digit_value (c); + rl_numeric_arg = (rl_numeric_arg * 10) + _rl_digit_value (c); else - rl_numeric_arg = digit_value (c); + rl_numeric_arg = _rl_digit_value (c); rl_explicit_arg = 1; } else @@ -778,12 +872,13 @@ rl_digit_loop1 () return (0); } +int rl_vi_delete_to (count, key) int count, key; { int c; - if (uppercase_p (key)) + if (_rl_uppercase_p (key)) rl_stuff_char ('$'); else if (vi_redoing) rl_stuff_char (_rl_vi_last_motion); @@ -803,12 +898,13 @@ rl_vi_delete_to (count, key) return (0); } +int rl_vi_change_to (count, key) int count, key; { int c, start_pos; - if (uppercase_p (key)) + if (_rl_uppercase_p (key)) rl_stuff_char ('$'); else if (vi_redoing) rl_stuff_char (_rl_vi_last_motion); @@ -828,25 +924,41 @@ rl_vi_change_to (count, key) rl_mark++; /* The cursor never moves with c[wW]. */ - if ((to_upper (c) == 'W') && rl_point < start_pos) + if ((_rl_to_upper (c) == 'W') && rl_point < start_pos) rl_point = start_pos; - rl_kill_text (rl_point, rl_mark); - - rl_begin_undo_group (); - _rl_vi_doing_insert = 1; - _rl_vi_set_last (key, count, rl_arg_sign); - rl_vi_insertion_mode (1, key); + if (vi_redoing) + { + if (vi_insert_buffer && *vi_insert_buffer) + rl_begin_undo_group (); + rl_delete_text (rl_point, rl_mark); + if (vi_insert_buffer && *vi_insert_buffer) + { + rl_insert_text (vi_insert_buffer); + rl_end_undo_group (); + } + } + else + { + rl_begin_undo_group (); /* to make the `u' command work */ + rl_kill_text (rl_point, rl_mark); + /* `C' does not save the text inserted for undoing or redoing. */ + if (_rl_uppercase_p (key) == 0) + _rl_vi_doing_insert = 1; + _rl_vi_set_last (key, count, rl_arg_sign); + rl_vi_insertion_mode (1, key); + } return (0); } +int rl_vi_yank_to (count, key) int count, key; { int c, save = rl_point; - if (uppercase_p (key)) + if (_rl_uppercase_p (key)) rl_stuff_char ('$'); if (rl_vi_domove (key, &c)) @@ -869,6 +981,7 @@ rl_vi_yank_to (count, key) return (0); } +int rl_vi_delete (count, key) int count, key; { @@ -888,57 +1001,36 @@ rl_vi_delete (count, key) rl_kill_text (rl_point, end); if (rl_point > 0 && rl_point == rl_end) - rl_backward (1); + rl_backward (1, key); return (0); } -/* Turn the current line into a comment in shell history. - A K*rn shell style function. */ -rl_vi_comment (count, key) +int +rl_vi_back_to_indent (count, key) int count, key; { - rl_beg_of_line (); - - if (rl_vi_comment_begin != (char *)NULL) - rl_insert_text (rl_vi_comment_begin); - else - rl_insert_text (VI_COMMENT_BEGIN_DEFAULT); /* Default. */ - - rl_redisplay (); - rl_newline (1, '\n'); + rl_beg_of_line (1, key); + while (rl_point < rl_end && whitespace (rl_line_buffer[rl_point])) + rl_point++; return (0); } +int rl_vi_first_print (count, key) int count, key; { - return (rl_back_to_indent ()); -} - -rl_back_to_indent (ignore1, ignore2) - int ignore1, ignore2; -{ - rl_beg_of_line (); - while (rl_point < rl_end && whitespace (rl_line_buffer[rl_point])) - rl_point++; - return (0); + return (rl_vi_back_to_indent (1, key)); } -/* NOTE: it is necessary that opposite directions are inverses */ -#define FTO 1 /* forward to */ -#define BTO -1 /* backward to */ -#define FFIND 2 /* forward find */ -#define BFIND -2 /* backward find */ - +int rl_vi_char_search (count, key) int count, key; { static char target; static int orig_dir, dir; - int pos; if (key == ';' || key == ',') - dir = (key == ';' ? orig_dir : -orig_dir); + dir = key == ';' ? orig_dir : -orig_dir; else { if (vi_redoing) @@ -966,71 +1058,11 @@ rl_vi_char_search (count, key) } } - pos = rl_point; - - while (count--) - { - if (dir < 0) - { - if (pos == 0) - { - ding (); - return -1; - } - - pos--; - do - { - if (rl_line_buffer[pos] == target) - { - if (dir == BTO) - rl_point = pos + 1; - else - rl_point = pos; - break; - } - } - while (pos--); - - if (pos < 0) - { - ding (); - return -1; - } - } - else - { /* dir > 0 */ - if (pos >= rl_end) - { - ding (); - return -1; - } - - pos++; - do - { - if (rl_line_buffer[pos] == target) - { - if (dir == FTO) - rl_point = pos - 1; - else - rl_point = pos; - break; - } - } - while (++pos < rl_end); - - if (pos >= (rl_end - 1)) - { - ding (); - return -1; - } - } - } - return (0); + return (_rl_char_search_internal (count, dir, target)); } /* Match brackets */ +int rl_vi_match (ignore, key) int ignore, key; { @@ -1041,7 +1073,7 @@ rl_vi_match (ignore, key) { while ((brack = rl_vi_bracktype (rl_line_buffer[rl_point])) == 0 && rl_point < rl_end - 1) - rl_forward (1); + rl_forward (1, key); if (brack <= 0) { @@ -1111,6 +1143,7 @@ rl_vi_bracktype (c) } } +int rl_vi_change_char (count, key) int count, key; { @@ -1131,22 +1164,23 @@ rl_vi_change_char (count, key) rl_delete (1, c); rl_insert (1, c); if (count == 0) - rl_backward (1); + rl_backward (1, c); rl_end_undo_group (); } return (0); } +int rl_vi_subst (count, key) int count, key; { rl_begin_undo_group (); - if (uppercase_p (key)) + if (_rl_uppercase_p (key)) { - rl_beg_of_line (); - rl_kill_line (1); + rl_beg_of_line (1, key); + rl_kill_line (1, key); } else rl_delete_text (rl_point, rl_point+count); @@ -1155,13 +1189,26 @@ rl_vi_subst (count, key) _rl_vi_set_last (key, count, rl_arg_sign); - rl_begin_undo_group (); - _rl_vi_doing_insert = 1; - rl_vi_insertion_mode (1, key); + if (vi_redoing) + { + int o = _rl_doing_an_undo; + + _rl_doing_an_undo = 1; + if (vi_insert_buffer && *vi_insert_buffer) + rl_insert_text (vi_insert_buffer); + _rl_doing_an_undo = o; + } + else + { + rl_begin_undo_group (); + _rl_vi_doing_insert = 1; + rl_vi_insertion_mode (1, key); + } return (0); } +int rl_vi_overstrike (count, key) int count, key; { @@ -1191,8 +1238,9 @@ rl_vi_overstrike (count, key) return (0); } -rl_vi_overstrike_delete (count) - int count; +int +rl_vi_overstrike_delete (count, key) + int count, key; { int i, s; @@ -1209,7 +1257,7 @@ rl_vi_overstrike_delete (count) vi_replace_count--; if (rl_point == s) - rl_backward (1); + rl_backward (1, key); } if (vi_replace_count == 0 && _rl_vi_doing_insert) @@ -1221,6 +1269,7 @@ rl_vi_overstrike_delete (count) return (0); } +int rl_vi_replace (count, key) int count, key; { @@ -1256,6 +1305,7 @@ rl_vi_replace (count, key) /* Try to complete the word we are standing on or the word that ends with the previous character. A space matches everything. Word delimiters are space and ;. */ +int rl_vi_possible_completions() { int save_pos = rl_point; @@ -1279,51 +1329,50 @@ rl_vi_possible_completions() } #endif -#if defined (STATIC_MALLOC) - -/* **************************************************************** */ -/* */ -/* xmalloc and xrealloc () */ -/* */ -/* **************************************************************** */ - -static void memory_error_and_abort (); - -static char * -xmalloc (bytes) - int bytes; +/* Functions to save and restore marks. */ +int +rl_vi_set_mark (count, key) + int count, key; { - char *temp = (char *)malloc (bytes); + int ch; - if (!temp) - memory_error_and_abort (); - return (temp); + ch = rl_read_key (); + if (_rl_lowercase_p (ch) == 0) + { + ding (); + return -1; + } + ch -= 'a'; + vi_mark_chars[ch] = rl_point; + return 0; } -static char * -xrealloc (pointer, bytes) - char *pointer; - int bytes; +int +rl_vi_goto_mark (count, key) + int count, key; { - char *temp; - - if (!pointer) - temp = (char *)xmalloc (bytes); - else - temp = (char *)realloc (pointer, bytes); + int ch; - if (!temp) - memory_error_and_abort (); - - return (temp); -} + ch = rl_read_key (); + if (ch == '`') + { + rl_point = rl_mark; + return 0; + } + else if (_rl_lowercase_p (ch) == 0) + { + ding (); + return -1; + } -static void -memory_error_and_abort () -{ - fprintf (stderr, "readline: Out of virtual memory!\n"); - abort (); + ch -= 'a'; + if (vi_mark_chars[ch] == -1) + { + ding (); + return -1; + } + rl_point = vi_mark_chars[ch]; + return 0; } -#endif /* STATIC_MALLOC */ #endif /* VI_MODE */ diff --git a/lib/readline/xmalloc.c b/lib/readline/xmalloc.c index 4f6dc76..4160651 100644 --- a/lib/readline/xmalloc.c +++ b/lib/readline/xmalloc.c @@ -19,8 +19,10 @@ along with Readline; see the file COPYING. If not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ -#if defined (ALREADY_HAVE_XMALLOC) -#else +#if defined (HAVE_CONFIG_H) +#include +#endif + #include #if defined (HAVE_STDLIB_H) @@ -44,9 +46,10 @@ char * xmalloc (bytes) int bytes; { - char *temp = (char *)malloc (bytes); + char *temp; - if (!temp) + temp = (char *)malloc (bytes); + if (temp == 0) memory_error_and_abort ("xmalloc"); return (temp); } @@ -58,12 +61,9 @@ xrealloc (pointer, bytes) { char *temp; - if (!pointer) - temp = (char *)malloc (bytes); - else - temp = (char *)realloc (pointer, bytes); + temp = pointer ? (char *)realloc (pointer, bytes) : (char *)malloc (bytes); - if (!temp) + if (temp == 0) memory_error_and_abort ("xrealloc"); return (temp); } @@ -72,7 +72,16 @@ static void memory_error_and_abort (fname) char *fname; { - fprintf (stderr, "%s: Out of virtual memory!\n", fname); - abort (); + fprintf (stderr, "%s: out of virtual memory\n", fname); + exit (2); +} + +/* Use this as the function to call when adding unwind protects so we + don't need to know what free() returns. */ +void +xfree (string) + char *string; +{ + if (string) + free (string); } -#endif /* !ALREADY_HAVE_XMALLOC */ diff --git a/lib/termcap/Makefile b/lib/termcap/Makefile deleted file mode 100644 index b87de8d..0000000 --- a/lib/termcap/Makefile +++ /dev/null @@ -1,67 +0,0 @@ -## -*- text -*- #################################################### -# # -# Makefile for termcap replacement libbrary. # -# # -#################################################################### - -# Here is a rule for making .o files from .c files that doesn't force -# the type of the machine (like -sun3) into the flags. -.c.o: - $(CC) -c $(CFLAGS) $(LOCAL_INCLUDES) $(CPPFLAGS) $*.c - -# Destination installation directory. The libraries are copied to DESTDIR -# when you do a `make install'. -DESTDIR = /usr/local/lib - -DEBUG_FLAGS = -g -#OPTIMIZE_FLAGS = -O -LDFLAGS = $(DEBUG_FLAGS) -CFLAGS = $(DEBUG_FLAGS) $(OPTIMIZE_FLAGS) - -SHELL = /bin/sh - -# A good alternative is gcc -traditional. -#CC = gcc -traditional -CC = cc -RANLIB = ranlib -AR = ar -RM = rm -CP = cp - -CSOURCES = termcap.c tparam.c - -SOURCES = $(CSOURCES) - -OBJECTS = termcap.o tparam.o - -DOCUMENTATION = termcap.texinfo - -THINGS_TO_TAR = $(SOURCES) $(DOCUMENTATION) - -########################################################################## - -all: libtermcap.a - -libtermcap.a: $(OBJECTS) - $(RM) -f $@ - $(AR) clq $@ $(OBJECTS) - -[ -n "$(RANLIB)" ] && $(RANLIB) $@ - -termcap.tar: $(THINGS_TO_TAR) - tar -cf $@ $(THINGS_TO_TAR) - -termcap.tar.Z: termcap.tar - compress -f termcap.tar - -install: $(DESTDIR)/libtermcap.a - -clean: - rm -f *.o *.a *.log *.cp *.tp *.vr *.fn *.aux *.pg *.toc - -maintainer-clean realclean mostlyclean distclean: clean - - -$(DESTDIR)/libtermcap.a: libtermcap.a - -mv $(DESTDIR)/libtermcap.a $(DESTDIR)/libtermcap.old - cp libtermcap.a $@ - -[ -n "$(RANLIB) ] && $(RANLIB) -t $@ diff --git a/lib/termcap/Makefile.in b/lib/termcap/Makefile.in new file mode 100644 index 0000000..64635f8 --- /dev/null +++ b/lib/termcap/Makefile.in @@ -0,0 +1,69 @@ +## -*- text -*- #################################################### +# # +# Makefile for termcap replacement libbrary. # +# # +#################################################################### + +srcdir = @srcdir@ +VPATH = .:@srcdir@ +topdir = @top_srcdir@ +BUILD_DIR = @BUILD_DIR@ + +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_DATA = @INSTALL_DATA@ + +CC = @CC@ +RANLIB = @RANLIB@ +AR = @AR@ +RM = rm -f +CP = cp +MV = mv + +CFLAGS = @CFLAGS@ +CPPFLAGS = @CPPFLAGS@ +LDFLAGS = @LDFLAGS@ + +DEFS = @DEFS@ + +INCLUDES = -I. -I../.. -I$(topdir) -I$(topdir)/lib + +CCFLAGS = $(CFLAGS) $(DEFS) $(CPPFLAGS) ${INCLUDES} + +# Here is a rule for making .o files from .c files that doesn't force +# the type of the machine (like -sun3) into the flags. +.c.o: + $(CC) -c $(CCFLAGS) $< + +SHELL = /bin/sh + +SOURCES = termcap.c tparam.c +OBJECTS = termcap.o tparam.o + +DOCUMENTATION = termcap.texinfo + +THINGS_TO_TAR = $(SOURCES) $(DOCUMENTATION) + +########################################################################## + +all: libtermcap.a + +libtermcap.a: $(OBJECTS) + $(RM) -f $@ + $(AR) cr $@ $(OBJECTS) + -test -n "$(RANLIB)" && $(RANLIB) $@ + +install: + +clean: + $(RM) *.o *.a *.log *.cp *.tp *.vr *.fn *.aux *.pg *.toc + +mostlyclean distclean maintainer-clean: clean + +$(DESTDIR)/libtermcap.a: libtermcap.a + ${INSTALL_DATA} -c -m 644 libtermcap.a $@ + -test -n "$(RANLIB)" && $(RANLIB) -t $@ + +termcap.o: $(BUILD_DIR)/config.h +tparam.o: $(BUILD_DIR)/config.h +version.o: $(BUILD_DIR)/config.h diff --git a/lib/termcap/grot/ChangeLog b/lib/termcap/grot/ChangeLog index 3a8b844..e8c4751 100644 --- a/lib/termcap/grot/ChangeLog +++ b/lib/termcap/grot/ChangeLog @@ -1,3 +1,92 @@ +Wed Aug 16 20:45:44 1995 David J. MacKenzie + + * version.c: Version 1.3. + + * termcap.c (tgetent): Use the user-supplied buffer even if we + don't find a matching terminal, so the program can set the buffer + if they want (`less' does this). From Bob Pegram + . + +Wed Jul 26 11:44:51 1995 David J. MacKenzie + + * termcap.c: TERMCAP_NAME -> TERMCAP_FILE. + + * configure.in: Add --enable-install-termcap and --with-termcap + options. + + * Makefile.in: Add hooks for new configure options. + + * Makefile.in (DISTFILES): Add termcap.src. + (DEFS): Remove -DNO_ARG_ARRAY. + (install-data, uninstall-data): New targets. + + * tparam.c (tparam): Remove arg array version and the #ifdef. + + * termcap.c: Move #define of bcopy to after #include . + + * termcap.h: Prototype the arg to the tputs outfun arg. + + * Makefile.in: realclean -> maintainer-clean. Use @prefix@ and + @exec_prefix@. + + * Makefile.in (DISTFILES): Add install-sh. + +Fri Apr 7 14:57:45 1995 Richard Stallman + + * termcap.c (tgetent): Don't try to return the allocated address. + Always return 1 if successful. + +Tue Feb 14 02:34:43 1995 Richard Stallman + + * termcap.c (speeds): Make it ints. Add some higher speeds. + (tputs) [emacs]: If speed is high, convert to smaller units. + (tputs): Really use SPEED to calculate PADCOUNT. + +Sat Dec 17 07:20:24 1994 Richard Stallman + + * termcap.c (tgetst1): Let ^? stand for DEL character. + +Thu Jun 30 04:35:50 1994 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * configure.in: Use AC_HAVE_HEADERS instead of AC_UNISTD_H. + Add AC_PROG_RANLIB. + * Makefile.in (AR, RANLIB): New variables. + (install, libtermcap.a): Use them instead of hard-wired commands. + +Sat Jun 4 12:21:41 1994 Roland McGrath (roland@geech.gnu.ai.mit.edu) + + * termcap.c [HAVE_CONFIG_H]: Include , and include + #ifdef USG5, so we get O_* defns. + +Wed May 25 19:05:30 1994 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * termcap.c (O_RDONLY): Define to 0 if not already defined. + (tgetent): Use O_RDONLY instead of explicit 0 in call to open. + +Wed Jan 5 22:20:15 1993 Morten Welinder (terra@diku.dk) + + * termcap.c (tgetent) [INTERNAL_TERMINAL]: Fake internal terminal + without reading any files. + (valid_file_name, tgetent) [MSDOS]: Drive letter support. + (tgetent) [MSDOS]: Use text mode for database. + +Fri Dec 17 00:22:43 1993 Mike Long (mike.long@analog.com) + + * termcap.c (tgetent): Replaced literal filenames for termcap + database with preprocessor symbol TERMCAP_NAME. + (TERMCAP_NAME): Define if not defined. + +Fri Sep 10 00:35:07 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * Makefile.in (.c.o): Put -I. before -I$(srcdir). + * termcap.c: Include instead of "config.h". + * tparam.c: Likewise. + +Thu Jul 29 20:53:30 1993 David J. MacKenzie (djm@wookumz.gnu.ai.mit.edu) + + * Makefile.in (config.status): Run config.status --recheck, not + configure, to get the right args passed. + Thu Apr 15 12:45:10 1993 David J. MacKenzie (djm@kropotkin.gnu.ai.mit.edu) * Version 1.2. diff --git a/lib/termcap/grot/INSTALL b/lib/termcap/grot/INSTALL index 014e0f7..95d84c8 100644 --- a/lib/termcap/grot/INSTALL +++ b/lib/termcap/grot/INSTALL @@ -1,117 +1,176 @@ -This is a generic INSTALL file for utilities distributions. -If this package does not come with, e.g., installable documentation or -data files, please ignore the references to them below. - -To compile this package: - -1. Configure the package for your system. In the directory that this -file is in, type `./configure'. If you're using `csh' on an old -version of System V, you might need to type `sh configure' instead to -prevent `csh' from trying to execute `configure' itself. - -The `configure' shell script attempts to guess correct values for -various system-dependent variables used during compilation, and -creates the Makefile(s) (one in each subdirectory of the source -directory). In some packages it creates a C header file containing -system-dependent definitions. It also creates a file `config.status' -that you can run in the future to recreate the current configuration. - -Running `configure' takes a minute or two. While it is running, it -prints some messages that tell what it is doing. If you don't want to -see the messages, run `configure' with its standard output redirected -to `/dev/null'; for example, `./configure >/dev/null'. - -To compile the package in a different directory from the one -containing the source code, you must use a version of `make' that -supports the VPATH variable, such as GNU `make'. `cd' to the directory -where you want the object files and executables to go and run -`configure'. `configure' automatically checks for the source code in -the directory that `configure' is in and in `..'. If for some reason -`configure' is not in the source code directory that you are -configuring, then it will report that it can't find the source code. -In that case, run `configure' with the option `--srcdir=DIR', where -DIR is the directory that contains the source code. - -By default, `make install' will install the package's files in -/usr/local/bin, /usr/local/lib, /usr/local/man, etc. You can specify -an installation prefix other than /usr/local by giving `configure' the -option `--prefix=PATH'. Alternately, you can do so by giving a value -for the `prefix' variable when you run `make', e.g., - make prefix=/usr/gnu - -You can specify separate installation prefixes for -architecture-specific files and architecture-independent files. If -you give `configure' the option `--exec-prefix=PATH' or set the -`make' variable `exec_prefix' to PATH, the package will use PATH as -the prefix for installing programs and libraries. Data files and -documentation will still use the regular prefix. Normally, all files -are installed using the regular prefix. - -Another `configure' option is useful mainly in `Makefile' rules for -updating `config.status' and `Makefile'. The `--no-create' option -figures out the configuration for your system and records it in -`config.status', without actually configuring the package (creating -`Makefile's and perhaps a configuration header file). Later, you can -run `./config.status' to actually configure the package. You can also -give `config.status' the `--recheck' option, which makes it re-run -`configure' with the same arguments you used before. This option is -useful if you change `configure'. - -Some packages pay attention to `--with-PACKAGE' options to `configure', -where PACKAGE is something like `gnu-libc' or `x' (for the X Window System). -The README should mention any --with- options that the package recognizes. - -`configure' ignores any other arguments that you give it. - -If your system requires unusual options for compilation or linking -that `configure' doesn't know about, you can give `configure' initial -values for some variables by setting them in the environment. In -Bourne-compatible shells, you can do that on the command line like +Basic Installation +================== + + These are generic installation instructions. + + The `configure' shell script attempts to guess correct values for +various system-dependent variables used during compilation. It uses +those values to create a `Makefile' in each directory of the package. +It may also create one or more `.h' files containing system-dependent +definitions. Finally, it creates a shell script `config.status' that +you can run in the future to recreate the current configuration, a file +`config.cache' that saves the results of its tests to speed up +reconfiguring, and a file `config.log' containing compiler output +(useful mainly for debugging `configure'). + + If you need to do unusual things to compile the package, please try +to figure out how `configure' could check whether to do them, and mail +diffs or instructions to the address given in the `README' so they can +be considered for the next release. If at some point `config.cache' +contains results you don't want to keep, you may remove or edit it. + + The file `configure.in' is used to create `configure' by a program +called `autoconf'. You only need `configure.in' if you want to change +it or regenerate `configure' using a newer version of `autoconf'. + +The simplest way to compile this package is: + + 1. `cd' to the directory containing the package's source code and type + `./configure' to configure the package for your system. If you're + using `csh' on an old version of System V, you might need to type + `sh ./configure' instead to prevent `csh' from trying to execute + `configure' itself. + + Running `configure' takes awhile. While running, it prints some + messages telling which features it is checking for. + + 2. Type `make' to compile the package. + + 3. Optionally, type `make check' to run any self-tests that come with + the package. + + 4. Type `make install' to install the programs and any data files and + documentation. + + 5. You can remove the program binaries and object files from the + source code directory by typing `make clean'. To also remove the + files that `configure' created (so you can compile the package for + a different kind of computer), type `make distclean'. There is + also a `make maintainer-clean' target, but that is intended mainly + for the package's developers. If you use it, you may have to get + all sorts of other programs in order to regenerate files that came + with the distribution. + +Compilers and Options +===================== + + Some systems require unusual options for compilation or linking that +the `configure' script does not know about. You can give `configure' +initial values for variables by setting them in the environment. Using +a Bourne-compatible shell, you can do that on the command line like this: - CC='gcc -traditional' DEFS=-D_POSIX_SOURCE ./configure - -The `make' variables that you might want to override with environment -variables when running `configure' are: - -(For these variables, any value given in the environment overrides the -value that `configure' would choose:) -CC C compiler program. - Default is `cc', or `gcc' if `gcc' is in your PATH. -INSTALL Program to use to install files. - Default is `install' if you have it, `cp' otherwise. - -(For these variables, any value given in the environment is added to -the value that `configure' chooses:) -DEFS Configuration options, in the form `-Dfoo -Dbar ...' - Do not use this variable in packages that create a - configuration header file. -LIBS Libraries to link with, in the form `-lfoo -lbar ...' - -If you need to do unusual things to compile the package, we encourage -you to figure out how `configure' could check whether to do them, and -mail diffs or instructions to the address given in the README so we -can include them in the next release. - -2. Type `make' to compile the package. If you want, you can override -the `make' variables CFLAGS and LDFLAGS like this: - - make CFLAGS=-O2 LDFLAGS=-s - -3. If the package comes with self-tests and you want to run them, -type `make check'. If you're not sure whether there are any, try it; -if `make' responds with something like - make: *** No way to make target `check'. Stop. -then the package does not come with self-tests. - -4. Type `make install' to install programs, data files, and -documentation. - -5. You can remove the program binaries and object files from the -source directory by typing `make clean'. To also remove the -Makefile(s), the header file containing system-dependent definitions -(if the package uses one), and `config.status' (all the files that -`configure' created), type `make distclean'. - -The file `configure.in' is used as a template to create `configure' by -a program called `autoconf'. You will only need it if you want to -regenerate `configure' using a newer version of `autoconf'. + CC=c89 CFLAGS=-O2 LIBS=-lposix ./configure + +Or on systems that have the `env' program, you can do it like this: + env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure + +Compiling For Multiple Architectures +==================================== + + You can compile the package for more than one kind of computer at the +same time, by placing the object files for each architecture in their +own directory. To do this, you must use a version of `make' that +supports the `VPATH' variable, such as GNU `make'. `cd' to the +directory where you want the object files and executables to go and run +the `configure' script. `configure' automatically checks for the +source code in the directory that `configure' is in and in `..'. + + If you have to use a `make' that does not supports the `VPATH' +variable, you have to compile the package for one architecture at a time +in the source code directory. After you have installed the package for +one architecture, use `make distclean' before reconfiguring for another +architecture. + +Installation Names +================== + + By default, `make install' will install the package's files in +`/usr/local/bin', `/usr/local/man', etc. You can specify an +installation prefix other than `/usr/local' by giving `configure' the +option `--prefix=PATH'. + + You can specify separate installation prefixes for +architecture-specific files and architecture-independent files. If you +give `configure' the option `--exec-prefix=PATH', the package will use +PATH as the prefix for installing programs and libraries. +Documentation and other data files will still use the regular prefix. + + If the package supports it, you can cause programs to be installed +with an extra prefix or suffix on their names by giving `configure' the +option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. + +Optional Features +================= + + Some packages pay attention to `--enable-FEATURE' options to +`configure', where FEATURE indicates an optional part of the package. +They may also pay attention to `--with-PACKAGE' options, where PACKAGE +is something like `gnu-as' or `x' (for the X Window System). The +`README' should mention any `--enable-' and `--with-' options that the +package recognizes. + + For packages that use the X Window System, `configure' can usually +find the X include and library files automatically, but if it doesn't, +you can use the `configure' options `--x-includes=DIR' and +`--x-libraries=DIR' to specify their locations. + +Specifying the System Type +========================== + + There may be some features `configure' can not figure out +automatically, but needs to determine by the type of host the package +will run on. Usually `configure' can figure that out, but if it prints +a message saying it can not guess the host type, give it the +`--host=TYPE' option. TYPE can either be a short name for the system +type, such as `sun4', or a canonical name with three fields: + CPU-COMPANY-SYSTEM + +See the file `config.sub' for the possible values of each field. If +`config.sub' isn't included in this package, then this package doesn't +need to know the host type. + + If you are building compiler tools for cross-compiling, you can also +use the `--target=TYPE' option to select the type of system they will +produce code for and the `--build=TYPE' option to select the type of +system on which you are compiling the package. + +Sharing Defaults +================ + + If you want to set default values for `configure' scripts to share, +you can create a site shell script called `config.site' that gives +default values for variables like `CC', `cache_file', and `prefix'. +`configure' looks for `PREFIX/share/config.site' if it exists, then +`PREFIX/etc/config.site' if it exists. Or, you can set the +`CONFIG_SITE' environment variable to the location of the site script. +A warning: not all `configure' scripts look for a site script. + +Operation Controls +================== + + `configure' recognizes the following options to control how it +operates. + +`--cache-file=FILE' + Use and save the results of the tests in FILE instead of + `./config.cache'. Set FILE to `/dev/null' to disable caching, for + debugging `configure'. + +`--help' + Print a summary of the options to `configure', and exit. + +`--quiet' +`--silent' +`-q' + Do not print messages saying which checks are being made. + +`--srcdir=DIR' + Look for the package's source code in directory DIR. Usually + `configure' can determine that directory automatically. + +`--version' + Print the version of Autoconf used to generate the `configure' + script, and exit. + +`configure' also accepts some other, not widely useful, options. + diff --git a/lib/termcap/grot/Makefile.in b/lib/termcap/grot/Makefile.in index 309603d..66e5d02 100644 --- a/lib/termcap/grot/Makefile.in +++ b/lib/termcap/grot/Makefile.in @@ -1,5 +1,5 @@ # Makefile for GNU termcap library. -# Copyright (C) 1992, 1993 Free Software Foundation, Inc. +# Copyright (C) 1992, 1993, 1994 Free Software Foundation, Inc. # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -21,26 +21,20 @@ srcdir = @srcdir@ VPATH = @srcdir@ CC = @CC@ +AR = ar +RANLIB = @RANLIB@ -# If you don't have a BSD or GNU install program, use cp. INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ MAKEINFO = makeinfo -# Things you might add to DEFS: -# -DHAVE_STRING_H If you have memcpy instead of bcopy. -# -DNO_ARG_ARRAY If you can't take the address of the first of -# a group of arguments and treat it as an array. -# We always define this, because it's not a big loss -# and can't be detected when cross-autoconfiguring. - -DEFS = @DEFS@ -DNO_ARG_ARRAY +DEFS = @DEFS@ -DTERMCAP_FILE=\"$(termcapfile)\" CFLAGS = -g -prefix = /usr/local -exec_prefix = $(prefix) +prefix = @prefix@ +exec_prefix = @exec_prefix@ # Directory in which to install libtermcap.a. libdir = $(exec_prefix)/lib @@ -57,6 +51,10 @@ oldincludedir = /usr/include # Directory in which to install the documentation info files. infodir = $(prefix)/info +# File to which `install-data' should install the data file +# if --enable-install-termcap was given. +termcapfile = @termcapfile@ + #### End of system configuration section. #### SHELL = /bin/sh @@ -65,35 +63,55 @@ SRCS = termcap.c tparam.c version.c OBJS = termcap.o tparam.o version.o HDRS = termcap.h DISTFILES = $(SRCS) $(HDRS) ChangeLog COPYING README INSTALL NEWS \ -termcap.texi termcap.info* \ -texinfo.tex Makefile.in configure configure.in +termcap.src termcap.texi termcap.info* \ +texinfo.tex Makefile.in configure configure.in mkinstalldirs install-sh -all: libtermcap.a termcap.info +all: libtermcap.a info .c.o: - $(CC) -c $(CPPFLAGS) $(DEFS) -I$(srcdir) $(CFLAGS) $< + $(CC) -c $(CPPFLAGS) $(DEFS) -I. -I$(srcdir) $(CFLAGS) $< -install: all +install: all installdirs @installdata@ $(INSTALL_DATA) libtermcap.a $(libdir)/libtermcap.a - -ranlib $(libdir)/libtermcap.a - test -d $(includedir) || mkdir $(includedir) + -$(RANLIB) $(libdir)/libtermcap.a cd $(srcdir); $(INSTALL_DATA) termcap.h $(includedir)/termcap.h -cd $(srcdir); test -z "$(oldincludedir)" || \ $(INSTALL_DATA) termcap.h $(oldincludedir)/termcap.h cd $(srcdir); for f in termcap.info*; \ do $(INSTALL_DATA) $$f $(infodir)/$$f; done -uninstall: +uninstall: @uninstalldata@ rm -f $(libdir)/libtermcap.a $(includedir)/termcap.h test -z "$(oldincludedir)" || rm -f $(oldincludedir)/termcap.h rm -f $(infodir)/termcap.info* +# These are separate targets to avoid trashing the user's existing +# termcap file unexpectedly. +install-data: + $(INSTALL_DATA) ${srcdir}/termcap.src ${termcapfile} + +uninstall-data: + rm -f ${termcapfile} + +installdirs: + $(SHELL) ${srcdir}/mkinstalldirs $(bindir) $(libdir) \ + $(includedir) $(infodir) + +Makefile: Makefile.in config.status + $(SHELL) config.status +config.status: configure + $(SHELL) config.status --recheck +configure: configure.in + cd $(srcdir) && autoconf + libtermcap.a: $(OBJS) - ar rc $@ $(OBJS) - -ranlib $@ + $(AR) rc $@ $(OBJS) + -$(RANLIB) $@ + +info: termcap.info termcap.info: termcap.texi - $(MAKEINFO) $(srcdir)/termcap.texi --output=$(srcdir)/termcap.info + $(MAKEINFO) $(srcdir)/termcap.texi --output=$@ TAGS: $(SRCS) etags $(SRCS) @@ -104,9 +122,11 @@ clean: mostlyclean: clean distclean: clean - rm -f Makefile config.status + rm -f Makefile config.status config.cache config.log -realclean: distclean +maintainer-clean: distclean + @echo "This command is intended for maintainers to use;" + @echo "rebuilding the deleted files requires makeinfo." rm -f TAGS *.info* dist: $(DISTFILES) @@ -114,5 +134,5 @@ dist: $(DISTFILES) rm -rf `cat .fname` mkdir `cat .fname` ln $(DISTFILES) `cat .fname` - tar chzf `cat .fname`.tar.z `cat .fname` + tar chzf `cat .fname`.tar.gz `cat .fname` rm -rf `cat .fname` .fname diff --git a/lib/termcap/grot/NEWS b/lib/termcap/grot/NEWS index c696fdf..e5d58b9 100644 --- a/lib/termcap/grot/NEWS +++ b/lib/termcap/grot/NEWS @@ -1,3 +1,11 @@ +Major changes in release 1.3: + +Termcap data file is now included in distribution and may optionally + be installed, or used in a non-default location. +Support for a fake internal terminal (no external files). +Higher tty speeds supported. +Portability tweaks. + Major changes in release 1.2: For `%.', only set the high bit on NUL. diff --git a/lib/termcap/grot/README b/lib/termcap/grot/README index 9db9095..ba1a19c 100644 --- a/lib/termcap/grot/README +++ b/lib/termcap/grot/README @@ -1,13 +1,33 @@ This is the GNU termcap library -- a library of C functions that enable programs to send control strings to terminals in a way -independent of the terminal type. Most of this package is also -distributed with GNU Emacs, but it is available in this separate -distribution to make it easier to install as -ltermcap. +independent of the terminal type. The GNU termcap library does not +place an arbitrary limit on the size of termcap entries, unlike most +other termcap libraries. -The GNU termcap library does not place an arbitrary limit on the size -of termcap entries, unlike most other termcap libraries. +Most of this package is also distributed with GNU Emacs, but it is +available in this separate distribution to make it easier to install +as -ltermcap. However, use of termcap is discouraged. Termcap is +being phased out in favor of the terminfo-based ncurses library, which +contains an emulation of the termcap library routines in addition to +an excellent curses implementation. ncurses is available from the +usual GNU archive sites. See the file INSTALL for compilation and installation instructions. +Additionally: + +This package contains termcap.src, the latest official termcap data +file. By default, it is not installed. The current version contains +some entries that are more than 1023 bytes long, which is the largest +value that is safe to use with the many historical applications that +only allocate a 1024 byte termcap buffer (telnet, for example). If +you make sure that all of your programs allocate buffers of at least +2500 bytes, or let the termcap library do it by passing a NULL +pointer, then it is safe to install the new termcap file, as described +below. + +You can give configure two special options: + --enable-install-termcap install the termcap data file + --with-termcap=FILE use data file FILE instead of /etc/termcap Please report any bugs in this library to bug-gnu-emacs@prep.ai.mit.edu. You can check which version of the library you have by using the RCS diff --git a/lib/termcap/grot/configure b/lib/termcap/grot/configure index bc34d0a..8a885fa 100755 --- a/lib/termcap/grot/configure +++ b/lib/termcap/grot/configure @@ -1,346 +1,998 @@ -#!/bin/sh +#! /bin/sh + # Guess values for system-dependent variables and create Makefiles. -# Generated automatically using autoconf. -# Copyright (C) 1991, 1992, 1993 Free Software Foundation, Inc. +# Generated automatically using autoconf version 2.4 +# Copyright (C) 1992, 1993, 1994 Free Software Foundation, Inc. +# +# This configure script is free software; the Free Software Foundation +# gives unlimited permission to copy, distribute and modify it. + +# Defaults: +ac_help= +ac_default_prefix=/usr/local +# Any additions from configure.in: +ac_help="$ac_help + --enable-install-termcap install the termcap data file" +ac_help="$ac_help + --with-termcap=FILE use data file FILE instead of /etc/termcap" + +# Initialize some variables set by options. +# The variables have the same names as the options, with +# dashes changed to underlines. +build=NONE +cache_file=./config.cache +exec_prefix=NONE +host=NONE +no_create= +nonopt=NONE +no_recursion= +prefix=NONE +program_prefix=NONE +program_suffix=NONE +program_transform_name=s,x,x, +silent= +site= +srcdir= +target=NONE +verbose= +x_includes=NONE +x_libraries=NONE + +# Initialize some other variables. +subdirs= + +ac_prev= +for ac_option +do -# This program 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. + # If the previous option needs an argument, assign it. + if test -n "$ac_prev"; then + eval "$ac_prev=\$ac_option" + ac_prev= + continue + fi -# This program 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. + case "$ac_option" in + -*=*) ac_optarg=`echo "$ac_option" | sed 's/[-_a-zA-Z0-9]*=//'` ;; + *) ac_optarg= ;; + esac -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + # Accept the important Cygnus configure options, so we can diagnose typos. -# Usage: configure [--srcdir=DIR] [--host=HOST] [--gas] [--nfp] [--no-create] -# [--prefix=PREFIX] [--exec-prefix=PREFIX] [--with-PACKAGE] [TARGET] -# Ignores all args except --srcdir, --prefix, --exec-prefix, --no-create, and -# --with-PACKAGE unless this script has special code to handle it. + case "$ac_option" in + -build | --build | --buil | --bui | --bu | --b) + ac_prev=build ;; + -build=* | --build=* | --buil=* | --bui=* | --bu=* | --b=*) + build="$ac_optarg" ;; -for arg -do - # Handle --exec-prefix with a space before the argument. - if test x$next_exec_prefix = xyes; then exec_prefix=$arg; next_exec_prefix= - # Handle --host with a space before the argument. - elif test x$next_host = xyes; then next_host= - # Handle --prefix with a space before the argument. - elif test x$next_prefix = xyes; then prefix=$arg; next_prefix= - # Handle --srcdir with a space before the argument. - elif test x$next_srcdir = xyes; then srcdir=$arg; next_srcdir= - else - case $arg in - # For backward compatibility, also recognize exact --exec_prefix. - -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* | --exec=* | --exe=* | --ex=* | --e=*) - exec_prefix=`echo $arg | sed 's/[-a-z_]*=//'` ;; - -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- | --exec | --exe | --ex | --e) - next_exec_prefix=yes ;; - - -gas | --gas | --ga | --g) ;; - - -host=* | --host=* | --hos=* | --ho=* | --h=*) ;; - -host | --host | --hos | --ho | --h) - next_host=yes ;; - - -nfp | --nfp | --nf) ;; - - -no-create | --no-create | --no-creat | --no-crea | --no-cre | --no-cr | --no-c | --no- | --no) - no_create=1 ;; - - -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) - prefix=`echo $arg | sed 's/[-a-z_]*=//'` ;; - -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) - next_prefix=yes ;; - - -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=* | --s=*) - srcdir=`echo $arg | sed 's/[-a-z_]*=//'` ;; - -srcdir | --srcdir | --srcdi | --srcd | --src | --sr | --s) - next_srcdir=yes ;; - - -with-* | --with-*) - package=`echo $arg|sed 's/-*with-//'` - # Delete all the valid chars; see if any are left. - if test -n "`echo $package|sed 's/[-a-zA-Z0-9_]*//g'`"; then - echo "configure: $package: invalid package name" >&2; exit 1 - fi - eval "with_`echo $package|sed s/-/_/g`=1" ;; - - -v | -verbose | --verbose | --verbos | --verbo | --verb | --ver | --ve | --v) - verbose=yes ;; - - *) ;; + -cache-file | --cache-file | --cache-fil | --cache-fi \ + | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) + ac_prev=cache_file ;; + -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ + | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) + cache_file="$ac_optarg" ;; + + -disable-* | --disable-*) + ac_feature=`echo $ac_option|sed -e 's/-*disable-//'` + # Reject names that are not valid shell variable names. + if test -n "`echo $ac_feature| sed 's/[-a-zA-Z0-9_]//g'`"; then + { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; } + fi + ac_feature=`echo $ac_feature| sed 's/-/_/g'` + eval "enable_${ac_feature}=no" ;; + + -enable-* | --enable-*) + ac_feature=`echo $ac_option|sed -e 's/-*enable-//' -e 's/=.*//'` + # Reject names that are not valid shell variable names. + if test -n "`echo $ac_feature| sed 's/[-_a-zA-Z0-9]//g'`"; then + { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; } + fi + ac_feature=`echo $ac_feature| sed 's/-/_/g'` + case "$ac_option" in + *=*) ;; + *) ac_optarg=yes ;; esac - fi + eval "enable_${ac_feature}='$ac_optarg'" ;; + + -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ + | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ + | --exec | --exe | --ex) + ac_prev=exec_prefix ;; + -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ + | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ + | --exec=* | --exe=* | --ex=*) + exec_prefix="$ac_optarg" ;; + + -gas | --gas | --ga | --g) + # Obsolete; use --with-gas. + with_gas=yes ;; + + -help | --help | --hel | --he) + # Omit some internal or obsolete options to make the list less imposing. + # This message is too long to be a string in the A/UX 3.1 sh. + cat << EOF +Usage: configure [options] [host] +Options: [defaults in brackets after descriptions] +Configuration: + --cache-file=FILE cache test results in FILE + --help print this message + --no-create do not create output files + --quiet, --silent do not print \`checking...' messages + --version print the version of autoconf that created configure +Directory and file names: + --prefix=PREFIX install architecture-independent files in PREFIX + [$ac_default_prefix] + --exec-prefix=PREFIX install architecture-dependent files in PREFIX + [same as prefix] + --srcdir=DIR find the sources in DIR [configure dir or ..] + --program-prefix=PREFIX prepend PREFIX to installed program names + --program-suffix=SUFFIX append SUFFIX to installed program names + --program-transform-name=PROGRAM run sed PROGRAM on installed program names +Host type: + --build=BUILD configure for building on BUILD [BUILD=HOST] + --host=HOST configure for HOST [guessed] + --target=TARGET configure for TARGET [TARGET=HOST] +Features and packages: + --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) + --enable-FEATURE[=ARG] include FEATURE [ARG=yes] + --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] + --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) + --x-includes=DIR X include files are in DIR + --x-libraries=DIR X library files are in DIR +--enable and --with options recognized:$ac_help +EOF + exit 0 ;; + + -host | --host | --hos | --ho) + ac_prev=host ;; + -host=* | --host=* | --hos=* | --ho=*) + host="$ac_optarg" ;; + + -nfp | --nfp | --nf) + # Obsolete; use --without-fp. + with_fp=no ;; + + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c) + no_create=yes ;; + + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) + no_recursion=yes ;; + + -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) + ac_prev=prefix ;; + -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) + prefix="$ac_optarg" ;; + + -program-prefix | --program-prefix | --program-prefi | --program-pref \ + | --program-pre | --program-pr | --program-p) + ac_prev=program_prefix ;; + -program-prefix=* | --program-prefix=* | --program-prefi=* \ + | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) + program_prefix="$ac_optarg" ;; + + -program-suffix | --program-suffix | --program-suffi | --program-suff \ + | --program-suf | --program-su | --program-s) + ac_prev=program_suffix ;; + -program-suffix=* | --program-suffix=* | --program-suffi=* \ + | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) + program_suffix="$ac_optarg" ;; + + -program-transform-name | --program-transform-name \ + | --program-transform-nam | --program-transform-na \ + | --program-transform-n | --program-transform- \ + | --program-transform | --program-transfor \ + | --program-transfo | --program-transf \ + | --program-trans | --program-tran \ + | --progr-tra | --program-tr | --program-t) + ac_prev=program_transform_name ;; + -program-transform-name=* | --program-transform-name=* \ + | --program-transform-nam=* | --program-transform-na=* \ + | --program-transform-n=* | --program-transform-=* \ + | --program-transform=* | --program-transfor=* \ + | --program-transfo=* | --program-transf=* \ + | --program-trans=* | --program-tran=* \ + | --progr-tra=* | --program-tr=* | --program-t=*) + program_transform_name="$ac_optarg" ;; + + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + silent=yes ;; + + -site | --site | --sit) + ac_prev=site ;; + -site=* | --site=* | --sit=*) + site="$ac_optarg" ;; + + -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) + ac_prev=srcdir ;; + -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) + srcdir="$ac_optarg" ;; + + -target | --target | --targe | --targ | --tar | --ta | --t) + ac_prev=target ;; + -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) + target="$ac_optarg" ;; + + -v | -verbose | --verbose | --verbos | --verbo | --verb) + verbose=yes ;; + + -version | --version | --versio | --versi | --vers) + echo "configure generated by autoconf version 2.4" + exit 0 ;; + + -with-* | --with-*) + ac_package=`echo $ac_option|sed -e 's/-*with-//' -e 's/=.*//'` + # Reject names that are not valid shell variable names. + if test -n "`echo $ac_package| sed 's/[-_a-zA-Z0-9]//g'`"; then + { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; } + fi + ac_package=`echo $ac_package| sed 's/-/_/g'` + case "$ac_option" in + *=*) ;; + *) ac_optarg=yes ;; + esac + eval "with_${ac_package}='$ac_optarg'" ;; + + -without-* | --without-*) + ac_package=`echo $ac_option|sed -e 's/-*without-//'` + # Reject names that are not valid shell variable names. + if test -n "`echo $ac_package| sed 's/[-a-zA-Z0-9_]//g'`"; then + { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; } + fi + ac_package=`echo $ac_package| sed 's/-/_/g'` + eval "with_${ac_package}=no" ;; + + --x) + # Obsolete; use --with-x. + with_x=yes ;; + + -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ + | --x-incl | --x-inc | --x-in | --x-i) + ac_prev=x_includes ;; + -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ + | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) + x_includes="$ac_optarg" ;; + + -x-libraries | --x-libraries | --x-librarie | --x-librari \ + | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) + ac_prev=x_libraries ;; + -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ + | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) + x_libraries="$ac_optarg" ;; + + -*) { echo "configure: error: $ac_option: invalid option; use --help to show usage" 1>&2; exit 1; } + ;; + + *) + if test -n "`echo $ac_option| sed 's/[-a-z0-9.]//g'`"; then + echo "configure: warning: $ac_option: invalid host type" 1>&2 + fi + if test "x$nonopt" != xNONE; then + { echo "configure: error: can only configure for one host and one target at a time" 1>&2; exit 1; } + fi + nonopt="$ac_option" + ;; + + esac done -trap 'rm -f conftest* core; exit 1' 1 3 15 +if test -n "$ac_prev"; then + { echo "configure: error: missing argument to --`echo $ac_prev | sed 's/_/-/g'`" 1>&2; exit 1; } +fi -rm -f conftest* -compile='${CC-cc} $CFLAGS $DEFS conftest.c -o conftest $LIBS >/dev/null 2>&1' +trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15 + +# File descriptor usage: +# 0 standard input +# 1 file creation +# 2 errors and warnings +# 3 some systems may open it to /dev/tty +# 4 used on the Kubota Titan +# 6 checking for... messages and results +# 5 compiler messages saved in config.log +if test "$silent" = yes; then + exec 6>/dev/null +else + exec 6>&1 +fi +exec 5>./config.log + +echo "\ +This file contains any messages produced by compilers while +running configure, to aid debugging if configure makes a mistake. +" 1>&5 + +# Strip out --no-create and --no-recursion so they do not pile up. +# Also quote any args containing shell metacharacters. +ac_configure_args= +for ac_arg +do + case "$ac_arg" in + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c) ;; + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) ;; + *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?]*) + ac_configure_args="$ac_configure_args '$ac_arg'" ;; + *) ac_configure_args="$ac_configure_args $ac_arg" ;; + esac +done + +# NLS nuisances. +# Only set LANG and LC_ALL to C if already set. +# These must not be set unconditionally because not all systems understand +# e.g. LANG=C (notably SCO). +if test "${LC_ALL+set}" = set; then LC_ALL=C; export LC_ALL; fi +if test "${LANG+set}" = set; then LANG=C; export LANG; fi + +# confdefs.h avoids OS command line length limits that DEFS can exceed. +rm -rf conftest* confdefs.h +# AIX cpp loses on an empty file, so make sure it contains at least a newline. +echo > confdefs.h # A filename unique to this package, relative to the directory that # configure is in, which we can look for to find out if srcdir is correct. -unique_file=termcap.h +ac_unique_file=termcap.h # Find the source files, if location was not specified. if test -z "$srcdir"; then - srcdirdefaulted=yes - # Try the directory containing this script, then `..'. - prog=$0 - confdir=`echo $prog|sed 's%/[^/][^/]*$%%'` - test "X$confdir" = "X$prog" && confdir=. - srcdir=$confdir - if test ! -r $srcdir/$unique_file; then + ac_srcdir_defaulted=yes + # Try the directory containing this script, then its parent. + ac_prog=$0 + ac_confdir=`echo $ac_prog|sed 's%/[^/][^/]*$%%'` + test "x$ac_confdir" = "x$ac_prog" && ac_confdir=. + srcdir=$ac_confdir + if test ! -r $srcdir/$ac_unique_file; then srcdir=.. fi +else + ac_srcdir_defaulted=no fi -if test ! -r $srcdir/$unique_file; then - if test x$srcdirdefaulted = xyes; then - echo "configure: Can not find sources in \`${confdir}' or \`..'." 1>&2 +if test ! -r $srcdir/$ac_unique_file; then + if test "$ac_srcdir_defaulted" = yes; then + { echo "configure: error: can not find sources in $ac_confdir or .." 1>&2; exit 1; } else - echo "configure: Can not find sources in \`${srcdir}'." 1>&2 + { echo "configure: error: can not find sources in $srcdir" 1>&2; exit 1; } fi - exit 1 -fi -# Preserve a srcdir of `.' to avoid automounter screwups with pwd. -# But we can't avoid them for `..', to make subdirectories work. -case $srcdir in - .|/*|~*) ;; - *) srcdir=`cd $srcdir; pwd` ;; # Make relative path absolute. -esac - -if test -z "$CC"; then - echo checking for gcc - saveifs="$IFS"; IFS="${IFS}:" - for dir in $PATH; do - test -z "$dir" && dir=. - if test -f $dir/gcc; then - CC="gcc" +fi +srcdir=`echo "${srcdir}" | sed 's%\([^/]\)/*$%\1%'` + +# Prefer explicitly selected file to automatically selected ones. +if test -z "$CONFIG_SITE"; then + if test "x$prefix" != xNONE; then + CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site" + else + CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site" + fi +fi +for ac_site_file in $CONFIG_SITE; do + if test -r "$ac_site_file"; then + echo "loading site script $ac_site_file" + . "$ac_site_file" + fi +done + +if test -r "$cache_file"; then + echo "loading cache $cache_file" + . $cache_file +else + echo "creating cache $cache_file" + > $cache_file +fi + +ac_ext=c +# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CPP $CPPFLAGS' +ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5 2>&5' +ac_link='${CC-cc} -o conftest $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5 2>&5' + +if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null; then + # Stardent Vistra SVR4 grep lacks -e, says ghazi@caip.rutgers.edu. + if (echo -n testing; echo 1,2,3) | sed s/-n/xn/ | grep xn >/dev/null; then + ac_n= ac_c=' +' ac_t=' ' + else + ac_n=-n ac_c= ac_t= + fi +else + ac_n= ac_c='\c' ac_t= +fi + + + +# Check whether --enable-install-termcap or --disable-install-termcap was given. +enableval="$enable_install_termcap" +if test -n "$enableval"; then + if test $enableval = yes; then + installdata=install-data uninstalldata=uninstall-data + fi +fi + + +# Check whether --with-termcap or --without-termcap was given. +withval="$with_termcap" +if test -n "$withval"; then + termcapfile=$withval +else + termcapfile=/etc/termcap +fi + + +# Extract the first word of "gcc", so it can be a program name with args. +set dummy gcc; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:" + for ac_dir in $PATH; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_CC="gcc" break fi done - IFS="$saveifs" + IFS="$ac_save_ifs" + test -z "$ac_cv_prog_CC" && ac_cv_prog_CC="cc" +fi +fi +CC="$ac_cv_prog_CC" +if test -n "$CC"; then + echo "$ac_t""$CC" 1>&6 +else + echo "$ac_t""no" 1>&6 fi -test -z "$CC" && CC="cc" -# Find out if we are using GNU C, under whatever name. -cat > conftest.c <&6 +if eval "test \"`echo '$''{'ac_cv_prog_gcc'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.c < conftest.out 2>&1 -if egrep yes conftest.out >/dev/null 2>&1; then - GCC=1 # For later tests. +if ${CC-cc} -E conftest.c 2>&5 | egrep yes >/dev/null 2>&1; then + ac_cv_prog_gcc=yes +else + ac_cv_prog_gcc=no +fi +fi +echo "$ac_t""$ac_cv_prog_gcc" 1>&6 +if test $ac_cv_prog_gcc = yes; then + GCC=yes + if test "${CFLAGS+set}" != set; then + echo $ac_n "checking whether ${CC-cc} accepts -g""... $ac_c" 1>&6 +if eval "test \"`echo '$''{'ac_cv_prog_gcc_g'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + echo 'void f(){}' > conftest.c +if test -z "`${CC-cc} -g -c conftest.c 2>&1`"; then + ac_cv_prog_gcc_g=yes +else + ac_cv_prog_gcc_g=no fi rm -f conftest* -echo checking how to run the C preprocessor -if test -z "$CPP"; then - CPP='${CC-cc} -E' - cat > conftest.c < -EOF -err=`eval "($CPP $DEFS conftest.c >/dev/null) 2>&1"` -if test -z "$err"; then - : +fi + echo "$ac_t""$ac_cv_prog_gcc_g" 1>&6 + if test $ac_cv_prog_gcc_g = yes; then + CFLAGS="-g -O" + else + CFLAGS="-O" + fi + fi else - CPP=/lib/cpp + GCC= + test "${CFLAGS+set}" = set || CFLAGS="-g" +fi + +# Extract the first word of "ranlib", so it can be a program name with args. +set dummy ranlib; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +if eval "test \"`echo '$''{'ac_cv_prog_RANLIB'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$RANLIB"; then + ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:" + for ac_dir in $PATH; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_RANLIB="ranlib" + break + fi + done + IFS="$ac_save_ifs" + test -z "$ac_cv_prog_RANLIB" && ac_cv_prog_RANLIB=":" fi -rm -f conftest* +fi +RANLIB="$ac_cv_prog_RANLIB" +if test -n "$RANLIB"; then + echo "$ac_t""$RANLIB" 1>&6 +else + echo "$ac_t""no" 1>&6 fi -# Make sure to not get the incompatible SysV /etc/install and -# /usr/sbin/install, which might be in PATH before a BSD-like install, -# or the SunOS /usr/etc/install directory, or the AIX /bin/install, -# or the AFS install, which mishandles nonexistent args. (Sigh.) +ac_aux_dir= +for ac_dir in $srcdir $srcdir/.. $srcdir/../..; do + if test -f $ac_dir/install-sh; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install-sh -c" + break + elif test -f $ac_dir/install.sh; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install.sh -c" + break + fi +done +if test -z "$ac_aux_dir"; then + { echo "configure: error: can not find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." 1>&2; exit 1; } +fi +ac_config_guess=$ac_aux_dir/config.guess +ac_config_sub=$ac_aux_dir/config.sub +ac_configure=$ac_aux_dir/configure # This should be Cygnus configure. + +# Find a good install program. We prefer a C program (faster), +# so one script is as good as another. But avoid the broken or +# incompatible versions: +# SysV /etc/install, /usr/sbin/install +# SunOS /usr/etc/install +# IRIX /sbin/install +# AIX /bin/install +# AFS /usr/afsws/bin/install, which mishandles nonexistent args +# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" +# ./install, which can be erroneously created by make from ./install.sh. +echo $ac_n "checking for a BSD compatible install""... $ac_c" 1>&6 if test -z "$INSTALL"; then - echo checking for install - saveifs="$IFS"; IFS="${IFS}:" - for dir in $PATH; do - test -z "$dir" && dir=. - case $dir in - /etc|/usr/sbin|/usr/etc|/usr/afsws/bin) ;; +if eval "test \"`echo '$''{'ac_cv_path_install'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:" + for ac_dir in $PATH; do + # Account for people who put trailing slashes in PATH elements. + case "$ac_dir/" in + /|./|.//|/etc/*|/usr/sbin/*|/usr/etc/*|/sbin/*|/usr/afsws/bin/*|/usr/ucb/*) ;; *) - if test -f $dir/installbsd; then - INSTALL="$dir/installbsd -c" # OSF1 - INSTALL_PROGRAM='$(INSTALL)' - INSTALL_DATA='$(INSTALL) -m 644' - break - fi - if test -f $dir/install; then - if grep dspmsg $dir/install >/dev/null 2>&1; then - : # AIX - else - INSTALL="$dir/install -c" - INSTALL_PROGRAM='$(INSTALL)' - INSTALL_DATA='$(INSTALL) -m 644' - break + # OSF1 and SCO ODT 3.0 have their own names for install. + for ac_prog in ginstall installbsd scoinst install; do + if test -f $ac_dir/$ac_prog; then + if test $ac_prog = install && + grep dspmsg $ac_dir/$ac_prog >/dev/null 2>&1; then + # AIX install. It has an incompatible calling convention. + # OSF/1 installbsd also uses dspmsg, but is usable. + : + else + ac_cv_path_install="$ac_dir/$ac_prog -c" + break 2 + fi fi - fi + done ;; esac done - IFS="$saveifs" + IFS="$ac_save_ifs" + # As a last resort, use the slow shell script. + test -z "$ac_cv_path_install" && ac_cv_path_install="$ac_install_sh" fi -INSTALL=${INSTALL-cp} -INSTALL_PROGRAM=${INSTALL_PROGRAM-'$(INSTALL)'} -INSTALL_DATA=${INSTALL_DATA-'$(INSTALL)'} + INSTALL="$ac_cv_path_install" +fi +echo "$ac_t""$INSTALL" 1>&6 -for hdr in string.h -do -trhdr=HAVE_`echo $hdr | tr '[a-z]./' '[A-Z]__'` -echo checking for ${hdr} -cat > conftest.c < +# Use test -z because SunOS4 sh mishandles braces in ${var-val}. +# It thinks the first close brace ends the variable substitution. +test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' + +test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' + +echo $ac_n "checking how to run the C preprocessor""... $ac_c" 1>&6 +# On Suns, sometimes $CPP names a directory. +if test -n "$CPP" && test -d "$CPP"; then + CPP= +fi +if test -z "$CPP"; then +if eval "test \"`echo '$''{'ac_cv_prog_CPP'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + # This must be in double quotes, not single quotes, because CPP may get + # substituted into the Makefile and "${CC-cc}" will confuse make. + CPP="${CC-cc} -E" + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. + cat > conftest.$ac_ext < +Syntax Error +EOF +eval "$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +ac_err=`grep -v '^ *+' conftest.out` +if test -z "$ac_err"; then + : +else + echo "$ac_err" >&5 + rm -rf conftest* + CPP="${CC-cc} -E -traditional-cpp" + cat > conftest.$ac_ext < +Syntax Error EOF -err=`eval "($CPP $DEFS conftest.c >/dev/null) 2>&1"` -if test -z "$err"; then - { -test -n "$verbose" && \ -echo ' defining' ${trhdr} -DEFS="$DEFS -D${trhdr}=1" -} +eval "$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +ac_err=`grep -v '^ *+' conftest.out` +if test -z "$ac_err"; then + : +else + echo "$ac_err" >&5 + rm -rf conftest* + CPP=/lib/cpp +fi +rm -f conftest* +fi +rm -f conftest* + ac_cv_prog_CPP="$CPP" +fi + CPP="$ac_cv_prog_CPP" +else + ac_cv_prog_CPP="$CPP" +fi +echo "$ac_t""$CPP" 1>&6 +for ac_hdr in string.h unistd.h +do +ac_safe=`echo "$ac_hdr" | tr './\055' '___'` +echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 +if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +EOF +eval "$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +ac_err=`grep -v '^ *+' conftest.out` +if test -z "$ac_err"; then + rm -rf conftest* + eval "ac_cv_header_$ac_safe=yes" +else + echo "$ac_err" >&5 + rm -rf conftest* + eval "ac_cv_header_$ac_safe=no" fi rm -f conftest* +fi +if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_hdr=HAVE_`echo $ac_hdr | tr '[a-z]./\055' '[A-Z]___'` + cat >> confdefs.h <&6 +fi done -echo checking for unistd.h -cat > conftest.c < +# If we cannot run a trivial program, we must be cross compiling. +echo $ac_n "checking whether cross-compiling""... $ac_c" 1>&6 +if eval "test \"`echo '$''{'ac_cv_c_cross'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test "$cross_compiling" = yes; then + ac_cv_c_cross=yes +else +cat > conftest.$ac_ext </dev/null) 2>&1"` -if test -z "$err"; then - { -test -n "$verbose" && \ -echo ' defining' HAVE_UNISTD_H -DEFS="$DEFS -DHAVE_UNISTD_H=1" -} - +eval $ac_link +if test -s conftest && (./conftest; exit) 2>/dev/null; then + ac_cv_c_cross=no +else + ac_cv_c_cross=yes fi -rm -f conftest* +fi +rm -fr conftest* +fi +cross_compiling=$ac_cv_c_cross +echo "$ac_t""$ac_cv_c_cross" 1>&6 -echo checking for ANSI C header files -cat > conftest.c <&6 +if eval "test \"`echo '$''{'ac_cv_header_stdc'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < #include #include #include EOF -err=`eval "($CPP $DEFS conftest.c >/dev/null) 2>&1"` -if test -z "$err"; then +eval "$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +ac_err=`grep -v '^ *+' conftest.out` +if test -z "$ac_err"; then + rm -rf conftest* + ac_cv_header_stdc=yes +else + echo "$ac_err" >&5 + rm -rf conftest* + ac_cv_header_stdc=no +fi +rm -f conftest* + +if test $ac_cv_header_stdc = yes; then # SunOS 4.x string.h does not declare mem*, contrary to ANSI. -echo '#include ' > conftest.c -eval "$CPP $DEFS conftest.c > conftest.out 2>&1" -if egrep "memchr" conftest.out >/dev/null 2>&1; then - # SGI's /bin/cc from Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. -cat > conftest.c < conftest.$ac_ext < +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "memchr" >/dev/null 2>&1; then + : +else + rm -rf conftest* + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. +cat > conftest.$ac_ext < +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "free" >/dev/null 2>&1; then + : +else + rm -rf conftest* + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. +if test "$cross_compiling" = yes; then + ac_cv_header_stdc=no +else +cat > conftest.$ac_ext < #define ISLOWER(c) ('a' <= (c) && (c) <= 'z') #define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) -#define XOR(e,f) (((e) && !(f)) || (!(e) && (f))) +#define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) int main () { int i; for (i = 0; i < 256; i++) if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) exit(2); exit (0); } EOF -eval $compile +eval $ac_link if test -s conftest && (./conftest; exit) 2>/dev/null; then - { -test -n "$verbose" && \ -echo ' defining' STDC_HEADERS -DEFS="$DEFS -DSTDC_HEADERS=1" -} - + : +else + ac_cv_header_stdc=no fi -rm -f conftest* fi -rm -f conftest* +rm -fr conftest* +fi +fi +echo "$ac_t""$ac_cv_header_stdc" 1>&6 +if test $ac_cv_header_stdc = yes; then + cat >> confdefs.h <<\EOF +#define STDC_HEADERS 1 +EOF fi -rm -f conftest* -if test -n "$prefix"; then - test -z "$exec_prefix" && exec_prefix='${prefix}' - prsub="s%^prefix\\([ ]*\\)=\\([ ]*\\).*$%prefix\\1=\\2$prefix%" + +trap '' 1 2 15 +cat > confcache <<\EOF +# This file is a shell script that caches the results of configure +# tests run on this system so they can be shared between configure +# scripts and configure runs. It is not useful on other systems. +# If it contains results you don't want to keep, you may remove or edit it. +# +# By default, configure uses ./config.cache as the cache file, +# creating it if it does not exist already. You can give configure +# the --cache-file=FILE option to use a different cache file; that is +# what configure does when it calls configure scripts in +# subdirectories, so they share the cache. +# Giving --cache-file=/dev/null disables caching, for debugging configure. +# config.status only pays attention to the cache file if you give it the +# --recheck option to rerun configure. +# +EOF +# Ultrix sh set writes to stderr and can't be redirected directly, +# and sets the high bit in the cache file unless we assign to the vars. +(set) 2>&1 | + sed -n "s/^\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\)=\(.*\)/\1=\${\1='\2'}/p" \ + >> confcache +if cmp -s $cache_file confcache; then + : +else + if test -w $cache_file; then + echo "updating cache $cache_file" + cat confcache > $cache_file + else + echo "not updating unwritable cache $cache_file" + fi fi -if test -n "$exec_prefix"; then - prsub="$prsub -s%^exec_prefix\\([ ]*\\)=\\([ ]*\\).*$%\ -exec_prefix\\1=\\2$exec_prefix%" +rm -f confcache + +trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15 + +test "x$prefix" = xNONE && prefix=$ac_default_prefix +# Let make expand exec_prefix. +test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' + +# Any assignment to VPATH causes Sun make to only execute +# the first set of double-colon rules, so remove it if not needed. +# If there is a colon in the path, we need to keep it. +if test "x$srcdir" = x.; then + ac_vpsub='/^[ ]*VPATH[ ]*=[^:]*$/d' fi -trap 'rm -f config.status; exit 1' 1 3 15 -echo creating config.status -rm -f config.status -cat > config.status < conftest.defs <<\EOF +s%#define \([A-Za-z_][A-Za-z0-9_]*\) \(.*\)%-D\1=\2%g +s%[ `~#$^&*(){}\\|;'"<>?]%\\&%g +s%\[%\\&%g +s%\]%\\&%g +s%\$%$$%g +EOF +DEFS=`sed -f conftest.defs confdefs.h | tr '\012' ' '` +rm -f conftest.defs + + +# Without the "./", some shells look in PATH for config.status. +: ${CONFIG_STATUS=./config.status} + +echo creating $CONFIG_STATUS +rm -f $CONFIG_STATUS +cat > $CONFIG_STATUS </dev/null | sed 1q`: # -# $0 $* +# $0 $ac_configure_args +# +# Compiler output produced by configure, useful for debugging +# configure, is in ./config.log if it exists. -for arg +ac_cs_usage="Usage: $CONFIG_STATUS [--recheck] [--version] [--help]" +for ac_option do - case "\$arg" in - -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) - exec /bin/sh $0 $* ;; - *) echo "Usage: config.status --recheck" 2>&1; exit 1 ;; + case "\$ac_option" in + -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) + echo "running \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion" + exec \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion ;; + -version | --version | --versio | --versi | --vers | --ver | --ve | --v) + echo "$CONFIG_STATUS generated by autoconf version 2.4" + exit 0 ;; + -help | --help | --hel | --he | --h) + echo "\$ac_cs_usage"; exit 0 ;; + *) echo "\$ac_cs_usage"; exit 1 ;; esac done -trap 'rm -f Makefile; exit 1' 1 3 15 -PROGS='$PROGS' -CC='$CC' -CPP='$CPP' -INSTALL='$INSTALL' -INSTALL_PROGRAM='$INSTALL_PROGRAM' -INSTALL_DATA='$INSTALL_DATA' -LIBS='$LIBS' -srcdir='$srcdir' -DEFS='$DEFS' -prefix='$prefix' -exec_prefix='$exec_prefix' -prsub='$prsub' +ac_given_srcdir=$srcdir +ac_given_INSTALL="$INSTALL" + +trap 'rm -fr `echo "Makefile" | sed "s/:[^ ]*//g"` conftest*; exit 1' 1 2 15 + +# Protect against being on the right side of a sed subst in config.status. +sed 's/%@/@@/; s/@%/@@/; s/%g$/@g/; /@g$/s/[\\\\&%]/\\\\&/g; + s/@@/%@/; s/@@/@%/; s/@g$/%g/' > conftest.subs <<\CEOF +$ac_vpsub +$extrasub +s%@CFLAGS@%$CFLAGS%g +s%@CPPFLAGS@%$CPPFLAGS%g +s%@CXXFLAGS@%$CXXFLAGS%g +s%@DEFS@%$DEFS%g +s%@LDFLAGS@%$LDFLAGS%g +s%@LIBS@%$LIBS%g +s%@exec_prefix@%$exec_prefix%g +s%@prefix@%$prefix%g +s%@program_transform_name@%$program_transform_name%g +s%@installdata@%$installdata%g +s%@uninstalldata@%$uninstalldata%g +s%@termcapfile@%$termcapfile%g +s%@CC@%$CC%g +s%@RANLIB@%$RANLIB%g +s%@INSTALL_PROGRAM@%$INSTALL_PROGRAM%g +s%@INSTALL_DATA@%$INSTALL_DATA%g +s%@CPP@%$CPP%g + +CEOF EOF -cat >> config.status <<\EOF +cat >> $CONFIG_STATUS <> $CONFIG_STATUS <<\EOF +for ac_file in .. $CONFIG_FILES; do if test "x$ac_file" != x..; then + # Support "outfile[:infile]", defaulting infile="outfile.in". + case "$ac_file" in + *:*) ac_file_in=`echo "$ac_file"|sed 's%.*:%%'` + ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;; + *) ac_file_in="${ac_file}.in" ;; + esac + + # Adjust relative srcdir, etc. for subdirectories. -top_srcdir=$srcdir -for file in .. Makefile; do if [ "x$file" != "x.." ]; then - srcdir=$top_srcdir # Remove last slash and all that follows it. Not all systems have dirname. - dir=`echo $file|sed 's%/[^/][^/]*$%%'` - if test "$dir" != "$file"; then - test "$top_srcdir" != . && srcdir=$top_srcdir/$dir - test ! -d $dir && mkdir $dir + ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'` + if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then + # The file is in a subdirectory. + test ! -d "$ac_dir" && mkdir "$ac_dir" + ac_dir_suffix="/`echo $ac_dir|sed 's%^\./%%'`" + # A "../" for each directory in $ac_dir_suffix. + ac_dots=`echo $ac_dir_suffix|sed 's%/[^/]*%../%g'` + else + ac_dir_suffix= ac_dots= fi - echo creating $file - rm -f $file - echo "# Generated automatically from `echo $file|sed 's|.*/||'`.in by configure." > $file - sed -e " -$prsub -s%@PROGS@%$PROGS%g -s%@CC@%$CC%g -s%@CPP@%$CPP%g -s%@INSTALL@%$INSTALL%g -s%@INSTALL_PROGRAM@%$INSTALL_PROGRAM%g -s%@INSTALL_DATA@%$INSTALL_DATA%g -s%@LIBS@%$LIBS%g + + case "$ac_given_srcdir" in + .) srcdir=. + if test -z "$ac_dots"; then top_srcdir=. + else top_srcdir=`echo $ac_dots|sed 's%/$%%'`; fi ;; + /*) srcdir="$ac_given_srcdir$ac_dir_suffix"; top_srcdir="$ac_given_srcdir" ;; + *) # Relative path. + srcdir="$ac_dots$ac_given_srcdir$ac_dir_suffix" + top_srcdir="$ac_dots$ac_given_srcdir" ;; + esac + + case "$ac_given_INSTALL" in + [/$]*) INSTALL="$ac_given_INSTALL" ;; + *) INSTALL="$ac_dots$ac_given_INSTALL" ;; + esac + echo creating "$ac_file" + rm -f "$ac_file" + configure_input="Generated automatically from `echo $ac_file_in|sed 's%.*/%%'` by configure." + case "$ac_file" in + *Makefile*) ac_comsub="1i\\ +# $configure_input" ;; + *) ac_comsub= ;; + esac + sed -e "$ac_comsub +s%@configure_input@%$configure_input%g s%@srcdir@%$srcdir%g -s%@DEFS@%$DEFS% -" $top_srcdir/${file}.in >> $file +s%@top_srcdir@%$top_srcdir%g +s%@INSTALL@%$INSTALL%g +" -f conftest.subs $ac_given_srcdir/$ac_file_in > $ac_file fi; done +rm -f conftest.subs + + exit 0 EOF -chmod +x config.status -test -n "$no_create" || ./config.status +chmod +x $CONFIG_STATUS +rm -fr confdefs* $ac_clean_files +test "$no_create" = yes || ${CONFIG_SHELL-/bin/sh} $CONFIG_STATUS || exit 1 diff --git a/lib/termcap/grot/configure.in b/lib/termcap/grot/configure.in index 1c2aaf2..f3f944f 100644 --- a/lib/termcap/grot/configure.in +++ b/lib/termcap/grot/configure.in @@ -1,10 +1,23 @@ dnl Process this file with autoconf to produce a configure script. AC_INIT(termcap.h) -AC_SUBST(PROGS)dnl + +AC_ARG_ENABLE(install-termcap, +[ --enable-install-termcap install the termcap data file], +[if test $enableval = yes; then + installdata=install-data uninstalldata=uninstall-data + fi]) +AC_SUBST(installdata)dnl +AC_SUBST(uninstalldata)dnl + +AC_ARG_WITH(termcap, +[ --with-termcap=FILE use data file FILE instead of /etc/termcap], +termcapfile=$withval, termcapfile=/etc/termcap) +AC_SUBST(termcapfile)dnl + AC_PROG_CC -AC_PROG_CPP +AC_PROG_RANLIB AC_PROG_INSTALL -AC_HAVE_HEADERS(string.h) -AC_UNISTD_H +AC_HAVE_HEADERS(string.h unistd.h) AC_STDC_HEADERS + AC_OUTPUT(Makefile) diff --git a/lib/termcap/grot/termcap.info b/lib/termcap/grot/termcap.info index f8515f1..f663195 100644 --- a/lib/termcap/grot/termcap.info +++ b/lib/termcap/grot/termcap.info @@ -1,5 +1,5 @@ -This is Info file /home/gd/gnu/termcap/termcap.info, produced by -Makeinfo-1.52 from the input file /home/gd/gnu/termcap/termcap.texi. +This is Info file ./termcap.info, produced by Makeinfo-1.55 from the +input file ./termcap.texi. This file documents the termcap library of the GNU system. @@ -21,60 +21,60 @@ translation approved by the Foundation.  Indirect: -termcap.info-1: 912 -termcap.info-2: 47539 -termcap.info-3: 90314 -termcap.info-4: 138449 +termcap.info-1: 874 +termcap.info-2: 47411 +termcap.info-3: 90390 +termcap.info-4: 138827  Tag Table: (Indirect) -Node: Top912 -Node: Introduction4143 -Node: Library5870 -Node: Preparation6889 -Node: Find8072 -Node: Interrogate11620 -Node: Initialize16928 -Node: Padding18568 -Node: Why Pad19274 -Node: Not Enough20896 -Node: Describe Padding23464 -Node: Output Padding24954 -Node: Parameters28569 -Node: Encode Parameters30229 -Node: Using Parameters36313 -Node: tparam36908 -Node: tgoto38934 -Node: Data Base41489 -Node: Format42385 -Node: Capability Format44474 -Node: Naming47539 -Node: Inheriting52108 -Node: Changing54352 -Node: Capabilities55516 -Node: Basic58255 -Node: Screen Size62308 -Node: Cursor Motion64048 -Node: Wrapping74190 -Node: Scrolling77015 -Node: Windows82904 -Node: Clearing83638 -Node: Insdel Line85402 -Node: Insdel Char90314 -Node: Standout100299 -Node: Underlining109357 -Node: Cursor Visibility111776 -Node: Bell112524 -Node: Keypad113073 -Node: Meta Key117794 -Node: Initialization118748 -Node: Pad Specs121112 -Node: Status Line123165 -Node: Half-Line125049 -Node: Printer125851 -Node: Summary127530 -Node: Var Index137736 -Node: Cap Index138449 -Node: Index145507 +Node: Top874 +Node: Introduction4105 +Node: Library5832 +Node: Preparation6851 +Node: Find8034 +Node: Interrogate11492 +Node: Initialize16800 +Node: Padding18440 +Node: Why Pad19146 +Node: Not Enough20768 +Node: Describe Padding23336 +Node: Output Padding24826 +Node: Parameters28441 +Node: Encode Parameters30101 +Node: Using Parameters36185 +Node: tparam36780 +Node: tgoto38806 +Node: Data Base41361 +Node: Format42257 +Node: Capability Format44346 +Node: Naming47411 +Node: Inheriting51980 +Node: Changing54224 +Node: Capabilities55388 +Node: Basic58127 +Node: Screen Size62180 +Node: Cursor Motion63920 +Node: Wrapping74062 +Node: Scrolling77091 +Node: Windows82980 +Node: Clearing83714 +Node: Insdel Line85478 +Node: Insdel Char90390 +Node: Standout100375 +Node: Underlining109433 +Node: Cursor Visibility111852 +Node: Bell112600 +Node: Keypad113149 +Node: Meta Key117864 +Node: Initialization118818 +Node: Pad Specs121369 +Node: Status Line123422 +Node: Half-Line125306 +Node: Printer126108 +Node: Summary127787 +Node: Var Index138114 +Node: Cap Index138827 +Node: Index145991  End Tag Table diff --git a/lib/termcap/grot/termcap.info-1 b/lib/termcap/grot/termcap.info-1 index 8390359..a5b5da0 100644 --- a/lib/termcap/grot/termcap.info-1 +++ b/lib/termcap/grot/termcap.info-1 @@ -1,5 +1,5 @@ -This is Info file /home/gd/gnu/termcap/termcap.info, produced by -Makeinfo-1.52 from the input file /home/gd/gnu/termcap/termcap.texi. +This is Info file ./termcap.info, produced by Makeinfo-1.55 from the +input file ./termcap.texi. This file documents the termcap library of the GNU system. @@ -218,10 +218,9 @@ variable `TERM' using `getenv ("TERM")'. If you are using the GNU version of termcap, you can alternatively ask `tgetent' to allocate enough space. Pass a null pointer for -BUFFER, and `tgetent' itself allocates the storage using `malloc'. In -this case the returned value on success is the address of the storage, -cast to `int'. But normally there is no need for you to look at the -address. Do not free the storage yourself. +BUFFER, and `tgetent' itself allocates the storage using `malloc'. +There is no way to get the address that was allocated, and you +shouldn't try to free the storage. With the Unix version of termcap, you must allocate space for the description yourself and pass the address of the space as the argument @@ -881,7 +880,7 @@ preferable for cursor motion. File: termcap.info, Node: tparam, Next: tgoto, Up: Using Parameters `tparam' --------- +........ The function `tparam' can encode display commands with any number of parameters and allows you to specify the buffer space. It is the @@ -930,7 +929,7 @@ capability. File: termcap.info, Node: tgoto, Prev: tparam, Up: Using Parameters `tgoto' -------- +....... The special case of cursor motion is handled by `tgoto'. There are two reasons why you might choose to use `tgoto': diff --git a/lib/termcap/grot/termcap.info-2 b/lib/termcap/grot/termcap.info-2 index 7142dc8..6098d62 100644 --- a/lib/termcap/grot/termcap.info-2 +++ b/lib/termcap/grot/termcap.info-2 @@ -1,5 +1,5 @@ -This is Info file /home/gd/gnu/termcap/termcap.info, produced by -Makeinfo-1.52 from the input file /home/gd/gnu/termcap/termcap.texi. +This is Info file ./termcap.info, produced by Makeinfo-1.55 from the +input file ./termcap.texi. This file documents the termcap library of the GNU system. @@ -663,6 +663,11 @@ column. carriage-return newline, which will leave the cursor at the beginning of the following line. +`LP' + Flag whose presence means that it is safe to write in the last + column of the last line without worrying about undesired + scrolling. `LP' indicates the DEC flavor of `xn' strangeness. +  File: termcap.info, Node: Scrolling, Next: Windows, Prev: Wrapping, Up: Capabilities diff --git a/lib/termcap/grot/termcap.info-3 b/lib/termcap/grot/termcap.info-3 index c1e6af9..d5b309f 100644 --- a/lib/termcap/grot/termcap.info-3 +++ b/lib/termcap/grot/termcap.info-3 @@ -1,5 +1,5 @@ -This is Info file /home/gd/gnu/termcap/termcap.info, produced by -Makeinfo-1.52 from the input file /home/gd/gnu/termcap/termcap.texi. +This is Info file ./termcap.info, produced by Makeinfo-1.55 from the +input file ./termcap.texi. This file documents the termcap library of the GNU system. @@ -566,12 +566,12 @@ a `ks' capability and send it, to make the keypad actually transmit. Such programs should also send the `ke' string when exiting. `ks' - String of commands to make the function keys transmit. If this + String of commands to make the keypad keys transmit. If this capability is not provided, but the others in this section are, - programs may assume that the function keys always transmit. + programs may assume that the keypad keys always transmit. `ke' - String of commands to make the function keys work locally. This + String of commands to make the keypad keys work locally. This capability is provided only if `ks' is. `kl' @@ -784,6 +784,11 @@ Initialization String of commands to set tab stop at current cursor column on all lines. +`NF' + Flag whose presence means that the terminal does not support + XON/XOFF flow control. Programs should not send XON (`C-q') or + XOFF (`C-s') characters to the terminal. +  File: termcap.info, Node: Pad Specs, Next: Status Line, Prev: Initialization, Up: Capabilities @@ -1266,6 +1271,9 @@ definitions, see the index of capability names (*note Cap Index::.). `lm' Number: lines of display memory. +`LP' + Flag: writing to last column of last line will not scroll. + `mb' String to enter blinking mode. @@ -1305,6 +1313,9 @@ definitions, see the index of capability names (*note Cap Index::.). `nd' String to move the cursor right one column. +`NF' + Flag: do not use XON/XOFF flow control. + `nl' Obsolete alternative name for the `do' and `sf' capabilities. diff --git a/lib/termcap/grot/termcap.info-4 b/lib/termcap/grot/termcap.info-4 index 21dd81c..4b8bf79 100644 --- a/lib/termcap/grot/termcap.info-4 +++ b/lib/termcap/grot/termcap.info-4 @@ -1,5 +1,5 @@ -This is Info file /home/gd/gnu/termcap/termcap.info, produced by -Makeinfo-1.52 from the input file /home/gd/gnu/termcap/termcap.texi. +This is Info file ./termcap.info, produced by Makeinfo-1.55 from the +input file ./termcap.texi. This file documents the termcap library of the GNU system. @@ -28,8 +28,8 @@ Capability Index * Menu: * ae: Standout. -* AL: Insdel Line. * al: Insdel Line. +* AL: Insdel Line. * am: Wrapping. * as: Standout. * bc: Cursor Motion. @@ -42,8 +42,8 @@ Capability Index * ce: Clearing. * ch: Cursor Motion. * cl: Clearing. -* CM: Cursor Motion. * cm: Cursor Motion. +* CM: Cursor Motion. * co: Screen Size. * cr: Cursor Motion. * cS: Scrolling. @@ -61,8 +61,8 @@ Capability Index * DL: Insdel Line. * dm: Insdel Char. * dN: Pad Specs. -* DO: Cursor Motion. * do: Cursor Motion. +* DO: Cursor Motion. * ds: Status Line. * dT: Pad Specs. * ec: Clearing. @@ -100,6 +100,7 @@ Capability Index * li: Screen Size. * ll: Cursor Motion. * lm: Scrolling. +* LP: Wrapping. * mb: Standout. * md: Standout. * me: Standout. @@ -114,6 +115,7 @@ Capability Index * ms: Underlining. * nc: Cursor Motion. * nd: Cursor Motion. +* NF: Initialization. * nl: Cursor Motion. * ns: Scrolling. * nw: Cursor Motion. @@ -131,12 +133,12 @@ Capability Index * sa: Standout. * sc: Cursor Motion. * se: Standout. -* sf: Scrolling. * SF: Scrolling. +* sf: Scrolling. * sg: Standout. * so: Standout. -* sr: Scrolling. * SR: Scrolling. +* sr: Scrolling. * st: Initialization. * ta: Cursor Motion. * te: Initialization. @@ -158,8 +160,8 @@ Capability Index * xb: Basic. * xn: Wrapping. * xs: Standout. -* xt: Standout. * xt: Cursor Motion. +* xt: Standout.  File: termcap.info, Node: Index, Prev: Cap Index, Up: Top @@ -199,8 +201,8 @@ Concept Index * repeat output: Basic. * reset: Initialization. * screen size: Screen Size. -* screen size: Screen Size. * screen size: Naming. +* screen size: Screen Size. * scrolling: Scrolling. * standout: Standout. * status line: Status Line. @@ -212,7 +214,7 @@ Concept Index * visibility: Cursor Visibility. * visible bell: Bell. * window: Windows. -* wrapping: Naming. * wrapping: Wrapping. +* wrapping: Naming. diff --git a/lib/termcap/grot/termcap.texi b/lib/termcap/grot/termcap.texi index d991838..7a6cd56 100644 --- a/lib/termcap/grot/termcap.texi +++ b/lib/termcap/grot/termcap.texi @@ -1,5 +1,5 @@ \input texinfo @c -*-texinfo-*- -@setfilename termcap +@setfilename termcap.info @settitle The Termcap Library @smallbook @@ -286,9 +286,8 @@ variable @code{TERM} using @code{getenv ("TERM")}. If you are using the GNU version of termcap, you can alternatively ask @code{tgetent} to allocate enough space. Pass a null pointer for @var{buffer}, and @code{tgetent} itself allocates the storage using -@code{malloc}. In this case the returned value on success is the address -of the storage, cast to @code{int}. But normally there is no need for you -to look at the address. Do not free the storage yourself.@refill +@code{malloc}. There is no way to get the address that was allocated, +and you shouldn't try to free the storage.@refill With the Unix version of termcap, you must allocate space for the description yourself and pass the address of the space as the argument @@ -1890,6 +1889,12 @@ flag, output a @samp{cm} absolute positioning command after writing in the last column. Another safe thing to do is to output carriage-return newline, which will leave the cursor at the beginning of the following line. + +@item LP +@kindex LP +Flag whose presence means that it is safe to write in the last column of +the last line without worrying about undesired scrolling. @samp{LP} +indicates the DEC flavor of @samp{xn} strangeness. @end table @node Scrolling, Windows, Wrapping, Capabilities @@ -2830,12 +2835,12 @@ Such programs should also send the @samp{ke} string when exiting. @table @asis @item @samp{ks} @kindex ka@dots{}ku -String of commands to make the function keys transmit. If this +String of commands to make the keypad keys transmit. If this capability is not provided, but the others in this section are, -programs may assume that the function keys always transmit. +programs may assume that the keypad keys always transmit. @item @samp{ke} -String of commands to make the function keys work locally. This +String of commands to make the keypad keys work locally. This capability is provided only if @samp{ks} is. @item @samp{kl} @@ -3065,6 +3070,12 @@ String of commands to clear all tab stops. @kindex st String of commands to set tab stop at current cursor column on all lines. + +@item NF +@kindex NF +Flag whose presence means that the terminal does not support XON/XOFF +flow control. Programs should not send XON (@kbd{C-q}) or XOFF +(@kbd{C-s}) characters to the terminal. @end table @node Pad Specs, Status Line, Initialization, Capabilities @@ -3460,6 +3471,8 @@ Number: height of the screen. String to position cursor at lower left corner. @item lm Number: lines of display memory. +@item LP +Flag: writing to last column of last line will not scroll. @item mb String to enter blinking mode. @item md @@ -3486,6 +3499,8 @@ Flag: cursor motion in standout mode is safe. Obsolete flag: do not use ASCII carriage-return on this terminal. @item nd String to move the cursor right one column. +@item NF +Flag: do not use XON/XOFF flow control. @item nl Obsolete alternative name for the @samp{do} and @samp{sf} capabilities. @item ns diff --git a/lib/termcap/grot/texinfo.tex b/lib/termcap/grot/texinfo.tex index d10917e..f62e9f5 100644 --- a/lib/termcap/grot/texinfo.tex +++ b/lib/termcap/grot/texinfo.tex @@ -1,6 +1,6 @@ %% TeX macros to handle texinfo files -% Copyright (C) 1985, 86, 88, 90, 91, 92, 1993 Free Software Foundation, Inc. +% Copyright (C) 1985, 86, 88, 90, 91, 92, 93, 1994 Free Software Foundation, Inc. %This texinfo.tex file is free software; you can redistribute it and/or %modify it under the terms of the GNU General Public License as @@ -22,15 +22,30 @@ %You are forbidden to forbid anyone else to use, share and improve %what you give them. Help stamp out software-hoarding! -\def\texinfoversion{2.104} + +% Send bug reports to bug-texinfo@prep.ai.mit.edu. +% Please include a *precise* test case in each bug report. + + +% Make it possible to create a .fmt file just by loading this file: +% if the underlying format is not loaded, start by loading it now. +% Added by gildea November 1993. +\expandafter\ifx\csname fmtname\endcsname\relax\input plain\fi + +% This automatically updates the version number based on RCS. +\def\deftexinfoversion$#1: #2 ${\def\texinfoversion{#2}} +\deftexinfoversion$Revision: 2.146 $ \message{Loading texinfo package [Version \texinfoversion]:} -\message{} -% Print the version number if in a .fmt file. -\everyjob{\message{[Texinfo version \texinfoversion]}\message{}} +% If in a .fmt file, print the version number +% and turn on active characters that we couldn't do earlier because +% they might have appeared in the input file name. +\everyjob{\message{[Texinfo version \texinfoversion]}\message{} + \catcode`+=\active \catcode`\_=\active} % Save some parts of plain tex whose names we will redefine. +\let\ptextilde=\~ \let\ptexlbrace=\{ \let\ptexrbrace=\} \let\ptexdots=\dots @@ -45,7 +60,15 @@ \let\ptexl=\l \let\ptexL=\L -\def\tie{\penalty 10000\ } % Save plain tex definition of ~. +% Be sure we're in horizontal mode when doing a tie, since we make space +% equivalent to this in @example-like environments. Otherwise, a space +% at the beginning of a line will start with \penalty -- and +% since \penalty is valid in vertical mode, we'd end up putting the +% penalty on the vertical list instead of in the new paragraph. +{\catcode`@ = 11 + \gdef\tie{\leavevmode\penalty\@M\ } +} +\let\~ = \tie % And make it available as @~. \message{Basics,} \chardef\other=12 @@ -54,8 +77,21 @@ % starts a new line in the output. \newlinechar = `^^J +% Set up fixed words for English. +\ifx\putwordChapter\undefined{\gdef\putwordChapter{Chapter}}\fi% +\def\putwordInfo{Info}% +\ifx\putwordSee\undefined{\gdef\putwordSee{See}}\fi% +\ifx\putwordsee\undefined{\gdef\putwordsee{see}}\fi% +\ifx\putwordfile\undefined{\gdef\putwordfile{file}}\fi% +\ifx\putwordpage\undefined{\gdef\putwordpage{page}}\fi% +\ifx\putwordsection\undefined{\gdef\putwordsection{section}}\fi% +\ifx\putwordSection\undefined{\gdef\putwordSection{Section}}\fi% +\ifx\putwordTableofContents\undefined{\gdef\putwordTableofContents{Table of Contents}}\fi% +\ifx\putwordShortContents\undefined{\gdef\putwordShortContents{Short Contents}}\fi% +\ifx\putwordAppendix\undefined{\gdef\putwordAppendix{Appendix}}\fi% + % Ignore a token. -% +% \def\gobble#1{} \hyphenation{ap-pen-dix} @@ -73,9 +109,9 @@ % since that produces some useless output on the terminal. % \def\gloggingall{\begingroup \globaldefs = 1 \loggingall \endgroup}% -\def\loggingall{\tracingcommands2 \tracingstats2 - \tracingpages1 \tracingoutput1 \tracinglostchars1 - \tracingmacros2 \tracingparagraphs1 \tracingrestores1 +\def\loggingall{\tracingcommands2 \tracingstats2 + \tracingpages1 \tracingoutput1 \tracinglostchars1 + \tracingmacros2 \tracingparagraphs1 \tracingrestores1 \showboxbreadth\maxdimen\showboxdepth\maxdimen }% @@ -139,15 +175,20 @@ \nointerlineskip \vbox{\line{\ewbot\hfill\ewbot}} }} - \advancepageno + \advancepageno \ifnum\outputpenalty>-20000 \else\dosupereject\fi} % % Do @cropmarks to get crop marks \def\cropmarks{\let\onepageout=\croppageout } +\newinsert\margin \dimen\margin=\maxdimen + \def\pagebody#1{\vbox to\pageheight{\boxmaxdepth=\maxdepth #1}} {\catcode`\@ =11 \gdef\pagecontents#1{\ifvoid\topins\else\unvbox\topins\fi +% marginal hacks, juha@viisa.uucp (Juha Takala) +\ifvoid\margin\else % marginal info is present + \rlap{\kern\hsize\vbox to\z@{\kern1pt\box\margin \vss}}\fi \dimen@=\dp#1 \unvbox#1 \ifvoid\footins\else\vskip\skip\footins\footnoterule \unvbox\footins\fi \ifr@ggedbottom \kern-\dimen@ \vfil \fi} @@ -225,7 +266,7 @@ % here.) But this means we cannot call \removeactivespaces as part of % \argremovec{,omment}, since @c uses \parsearg, and thus the argument % that \parsearg gets might well have any character at all in it. -% +% \def\removeactivespaces#1{% \begingroup \ignoreactivespaces @@ -235,7 +276,7 @@ } % Change the active space to expand to nothing. -% +% \begingroup \obeyspaces \gdef\ignoreactivespaces{\obeyspaces\let =\empty} @@ -283,26 +324,28 @@ } % There is an environment #1, but it hasn't been started. Give an error. -% +% \def\unmatchedenderror#1{% \errhelp = \EMsimple \errmessage{This `@end #1' doesn't have a matching `@#1'}% } % Define the control sequence \E#1 to give an unmatched @end error. -% +% \def\defineunmatchedend#1{% \expandafter\def\csname E#1\endcsname{\unmatchedenderror{#1}}% } -% Single-spacing is done by various environments. - -\newskip\singlespaceskip \singlespaceskip = \baselineskip +% Single-spacing is done by various environments (specifically, in +% \nonfillstart and \quotations). +\newskip\singlespaceskip \singlespaceskip = 12.5pt \def\singlespace{% -{\advance \baselineskip by -\singlespaceskip -\kern \baselineskip}% -\baselineskip=\singlespaceskip + % Why was this kern here? It messes up equalizing space above and below + % environments. --karl, 6may93 + %{\advance \baselineskip by -\singlespaceskip + %\kern \baselineskip}% + \setleading \singlespaceskip } %% Simple single-character @ commands @@ -334,6 +377,15 @@ % @. is an end-of-sentence period. \def\.{.\spacefactor=3000 } +% @enddots{} is an end-of-sentence ellipsis. +\gdef\enddots{$\mathinner{\ldotp\ldotp\ldotp\ldotp}$\spacefactor=3000} + +% @! is an end-of-sentence bang. +\gdef\!{!\spacefactor=3000 } + +% @? is an end-of-sentence query. +\gdef\?{?\spacefactor=3000 } + % @w prevents a word break. Without the \leavevmode, @w at the % beginning of a paragraph, when TeX is still in vertical mode, would % produce a whole line of output instead of starting the paragraph. @@ -346,7 +398,7 @@ % max (\topskip - \ht (first item), 0). If that height is large, % therefore, no glue is inserted, and the space between the headline and % the text is small, which looks bad. -% +% \def\group{\begingroup \ifnum\catcode13=\active \else \errhelp = \groupinvalidhelp @@ -356,8 +408,8 @@ % The \vtop we start below produces a box with normal height and large % depth; thus, TeX puts \baselineskip glue before it, and (when the % next line of text is done) \lineskip glue after it. (See p.82 of - % the TeXbook.) But the next line of text also gets us \parskip glue. - % Final result: space below is slightly more than space above. + % the TeXbook.) Thus, space below is not quite equal to space + % above. But it's pretty close. \def\Egroup{% \egroup % End the \vtop. \endgroup % End the \group. @@ -372,8 +424,24 @@ % Hence this just inserts a strut at the beginning of each line. \everypar = {\strut}% % - % We do @comment here in case we are called inside an environment, - % such as @example, where each end-of-line in the input causes an + % Since we have a strut on every line, we don't need any of TeX's + % normal interline spacing. + \offinterlineskip + % + % OK, but now we have to do something about blank + % lines in the input in @example-like environments, which normally + % just turn into \lisppar, which will insert no space now that we've + % turned off the interline space. Simplest is to make them be an + % empty paragraph. + \ifx\par\lisppar + \edef\par{\leavevmode \par}% + % + % Reset ^^M's definition to new definition of \par. + \obeylines + \fi + % + % Do @comment since we are called inside an environment such as + % @example, where each end-of-line in the input causes an % end-of-line in the output. We don't want the end-of-line after % the `@group' to put extra space in the output. Since @group % should appear on a line by itself (according to the Texinfo @@ -383,7 +451,7 @@ % % TeX puts in an \escapechar (i.e., `@') at the beginning of the help % message, so this ends up printing `@group can only ...'. -% +% \newhelp\groupinvalidhelp{% group can only be used in environments such as @example,^^J% where each line of input produces a line of output.} @@ -414,13 +482,13 @@ where each line of input produces a line of output.} \allowbreak \nointerlineskip \vtop to #1\mil{\vfil}% - % + % % TeX does not even consider page breaks if a penalty added to the % main vertical list is 10000 or more. But in order to see if the % empty box we just added fits on the page, we must make it consider % page breaks. On the other hand, we don't want to actually break the % page after the empty box. So we use a penalty of 9999. - % + % % There is an extremely small chance that TeX will actually break the % page at this \penalty, if there are no other feasible breakpoints in % sight. (If the user is using lots of big @group commands, which @@ -534,8 +602,8 @@ where each line of input produces a line of output.} % Used in nested conditionals, where we have to parse the Texinfo source % and so want to turn off most commands, in case they are used -% incorrectly. -% +% incorrectly. +% \def\ignoremorecommands{% \let\defcv = \relax \let\deffn = \relax @@ -561,20 +629,30 @@ where each line of input produces a line of output.} \let\pxref = \relax \let\settitle = \relax \let\include = \relax + \let\lowersections = \relax + \let\down = \relax + \let\raisesections = \relax + \let\up = \relax + \let\set = \relax + \let\clear = \relax + \let\item = \relax + \let\message = \relax } % Ignore @ignore ... @end ignore. -% +% \def\ignore{\doignore{ignore}} -% Also ignore @ifinfo, @menu, and @direntry text. -% +% Also ignore @ifinfo, @ifhtml, @html, @menu, and @direntry text. +% \def\ifinfo{\doignore{ifinfo}} +\def\ifhtml{\doignore{ifhtml}} +\def\html{\doignore{html}} \def\menu{\doignore{menu}} \def\direntry{\doignore{direntry}} % Ignore text until a line `@end #1'. -% +% \def\doignore#1{\begingroup % Don't complain about control sequences we have declared \outer. \ignoresections @@ -590,7 +668,7 @@ where each line of input produces a line of output.} } % What we do to finish off ignored text. -% +% \def\enddoignore{\endgroup\ignorespaces}% \newif\ifwarnedobs\warnedobsfalse @@ -619,7 +697,7 @@ where each line of input produces a line of output.} % Ignore text, except that we keep track of conditional commands for % purposes of nesting, up to an `@end #1' command. -% +% \def\nestedignore#1{% \obstexwarn % We must actually expand the ignored text to look for the @end @@ -627,7 +705,7 @@ where each line of input produces a line of output.} % text into a \vbox and then do nothing with the result. To minimize % the change of memory overflow, we follow the approach outlined on % page 401 of the TeXbook: make the current font be a dummy font. - % + % \setbox0 = \vbox\bgroup % Don't complain about control sequences we have declared \outer. \ignoresections @@ -644,7 +722,7 @@ where each line of input produces a line of output.} % We can't do anything about stray @-signs, unfortunately; % they'll produce `undefined control sequence' errors. \ignoremorecommands - % + % % Set the current font to be \nullfont, a TeX primitive, and define % all the font commands to also use \nullfont. We don't use % dummy.tfm, as suggested in the TeXbook, because not all sites @@ -656,6 +734,11 @@ where each line of input produces a line of output.} \let\tenrm = \nullfont \let\tenit = \nullfont \let\tensl = \nullfont \let\tenbf = \nullfont \let\tentt = \nullfont \let\smallcaps = \nullfont \let\tensf = \nullfont + % Similarly for index fonts (mostly for their use in + % smallexample) + \let\indrm = \nullfont \let\indit = \nullfont \let\indsl = \nullfont + \let\indbf = \nullfont \let\indtt = \nullfont \let\indsc = \nullfont + \let\indsf = \nullfont % % Don't complain when characters are missing from the fonts. \tracinglostchars = 0 @@ -675,7 +758,7 @@ where each line of input produces a line of output.} % @set VAR sets the variable VAR to an empty value. % @set VAR REST-OF-LINE sets VAR to the value REST-OF-LINE. -% +% % Since we want to separate VAR from REST-OF-LINE (which might be % empty), we can't just use \parsearg; we have to insert a space of our % own to delimit the rest of the line, and then take it out again if we @@ -689,7 +772,10 @@ where each line of input produces a line of output.} \else \setzzz{#1}#2\endsetzzz % Remove the trailing space \setxxx inserted. \fi } -\def\setzzz#1#2 \endsetzzz{\expandafter\xdef\csname SET#1\endcsname{#2}} +% Can't use \xdef to pre-expand #2 and save some time, since \temp or +% \next or other control sequences that we've defined might get us into +% an infinite loop. Consider `@set foo @cite{bar}'. +\def\setzzz#1#2 \endsetzzz{\expandafter\gdef\csname SET#1\endcsname{#2}} % @clear VAR clears (i.e., unsets) the variable VAR. % @@ -705,7 +791,7 @@ where each line of input produces a line of output.} % @ifset VAR ... @end ifset reads the `...' iff VAR has been defined % with @set. -% +% \def\ifset{\parsearg\ifsetxxx} \def\ifsetxxx #1{% \expandafter\ifx\csname SET#1\endcsname\relax @@ -720,7 +806,7 @@ where each line of input produces a line of output.} % @ifclear VAR ... @end ifclear reads the `...' iff VAR has never been % defined with @set, or has been undefined with @clear. -% +% \def\ifclear{\parsearg\ifclearxxx} \def\ifclearxxx #1{% \expandafter\ifx\csname SET#1\endcsname\relax @@ -735,7 +821,7 @@ where each line of input produces a line of output.} % @iftex always succeeds; we read the text following, through @end % iftex). But `@end iftex' should be valid only after an @iftex. -% +% \def\iftex{\conditionalsucceed{iftex}} \defineunmatchedend{iftex} @@ -745,7 +831,7 @@ where each line of input produces a line of output.} % define \Eiftex to redefine itself to be its previous value. (We can't % just define it to fail again with an ``unmatched end'' error, since % the @ifset might be nested.) -% +% \def\conditionalsucceed#1{% \edef\temp{% % Remember the current value of \E#1. @@ -763,7 +849,7 @@ where each line of input produces a line of output.} \def\nece#1{\expandafter\noexpand\csname#1\endcsname} % @asis just yields its argument. Used with @table, for example. -% +% \def\asis#1{#1} % @math means output in math mode. @@ -772,10 +858,10 @@ where each line of input produces a line of output.} % we read the toc file back, the $'s will be normal characters (as they % should be, according to the definition of Texinfo). So we must use a % control sequence to switch into and out of math mode. -% +% % This isn't quite enough for @math to work properly in indices, but it % seems unlikely it will ever be needed there. -% +% \let\implicitmath = $ \def\math#1{\implicitmath #1\implicitmath} @@ -791,18 +877,18 @@ where each line of input produces a line of output.} \def\donoderef{\ifx\lastnode\relax\else \expandafter\expandafter\expandafter\setref{\lastnode}\fi -\let\lastnode=\relax} +\global\let\lastnode=\relax} \def\unnumbnoderef{\ifx\lastnode\relax\else \expandafter\expandafter\expandafter\unnumbsetref{\lastnode}\fi -\let\lastnode=\relax} +\global\let\lastnode=\relax} \def\appendixnoderef{\ifx\lastnode\relax\else \expandafter\expandafter\expandafter\appendixsetref{\lastnode}\fi -\let\lastnode=\relax} +\global\let\lastnode=\relax} \let\refill=\relax - + % @setfilename is done at the beginning of every texinfo file. % So open here the files we need to have open while reading the input. % This makes it possible to make a .fmt file for texinfo. @@ -818,7 +904,7 @@ where each line of input produces a line of output.} \outer\def\bye{\pagealignmacro\tracingstats=1\ptexend} \def\inforef #1{\inforefzzz #1,,,,**} -\def\inforefzzz #1,#2,#3,#4**{See Info file \file{\ignorespaces #3{}}, +\def\inforefzzz #1,#2,#3,#4**{\putwordSee{} \putwordInfo{} \putwordfile{} \file{\ignorespaces #3{}}, node \samp{\ignorespaces#1{}}} \message{fonts,} @@ -834,95 +920,106 @@ where each line of input produces a line of output.} %% Try out Computer Modern fonts at \magstephalf \let\mainmagstep=\magstephalf +% Set the font macro #1 to the font named #2, adding on the +% specified font prefix (normally `cm'). +\def\setfont#1#2{\font#1=\fontprefix#2} + +% Use cm as the default font prefix. +% To specify the font prefix, you must define \fontprefix +% before you read in texinfo.tex. +\ifx\fontprefix\undefined +\def\fontprefix{cm} +\fi + \ifx\bigger\relax \let\mainmagstep=\magstep1 -\font\textrm=cmr12 -\font\texttt=cmtt12 +\setfont\textrm{r12} +\setfont\texttt{tt12} \else -\font\textrm=cmr10 scaled \mainmagstep -\font\texttt=cmtt10 scaled \mainmagstep +\setfont\textrm{r10 scaled \mainmagstep} +\setfont\texttt{tt10 scaled \mainmagstep} \fi % Instead of cmb10, you many want to use cmbx10. % cmbx10 is a prettier font on its own, but cmb10 % looks better when embedded in a line with cmr10. -\font\textbf=cmb10 scaled \mainmagstep -\font\textit=cmti10 scaled \mainmagstep -\font\textsl=cmsl10 scaled \mainmagstep -\font\textsf=cmss10 scaled \mainmagstep -\font\textsc=cmcsc10 scaled \mainmagstep +\setfont\textbf{b10 scaled \mainmagstep} +\setfont\textit{ti10 scaled \mainmagstep} +\setfont\textsl{sl10 scaled \mainmagstep} +\setfont\textsf{ss10 scaled \mainmagstep} +\setfont\textsc{csc10 scaled \mainmagstep} \font\texti=cmmi10 scaled \mainmagstep \font\textsy=cmsy10 scaled \mainmagstep % A few fonts for @defun, etc. -\font\defbf=cmbx10 scaled \magstep1 %was 1314 -\font\deftt=cmtt10 scaled \magstep1 +\setfont\defbf{bx10 scaled \magstep1} %was 1314 +\setfont\deftt{tt10 scaled \magstep1} \def\df{\let\tentt=\deftt \let\tenbf = \defbf \bf} % Fonts for indices and small examples. -% We actually use the slanted font rather than the italic, +% We actually use the slanted font rather than the italic, % because texinfo normally uses the slanted fonts for that. % Do not make many font distinctions in general in the index, since they % aren't very useful. -\font\ninett=cmtt9 -\font\indrm=cmr9 -\font\indit=cmsl9 +\setfont\ninett{tt9} +\setfont\indrm{r9} +\setfont\indit{sl9} \let\indsl=\indit \let\indtt=\ninett \let\indsf=\indrm \let\indbf=\indrm -\let\indsc=\indrm +\setfont\indsc{csc10 at 9pt} \font\indi=cmmi9 \font\indsy=cmsy9 % Fonts for headings -\font\chaprm=cmbx12 scaled \magstep2 -\font\chapit=cmti12 scaled \magstep2 -\font\chapsl=cmsl12 scaled \magstep2 -\font\chaptt=cmtt12 scaled \magstep2 -\font\chapsf=cmss12 scaled \magstep2 +\setfont\chaprm{bx12 scaled \magstep2} +\setfont\chapit{ti12 scaled \magstep2} +\setfont\chapsl{sl12 scaled \magstep2} +\setfont\chaptt{tt12 scaled \magstep2} +\setfont\chapsf{ss12 scaled \magstep2} \let\chapbf=\chaprm -\font\chapsc=cmcsc10 scaled\magstep3 +\setfont\chapsc{csc10 scaled\magstep3} \font\chapi=cmmi12 scaled \magstep2 \font\chapsy=cmsy10 scaled \magstep3 -\font\secrm=cmbx12 scaled \magstep1 -\font\secit=cmti12 scaled \magstep1 -\font\secsl=cmsl12 scaled \magstep1 -\font\sectt=cmtt12 scaled \magstep1 -\font\secsf=cmss12 scaled \magstep1 -\font\secbf=cmbx12 scaled \magstep1 -\font\secsc=cmcsc10 scaled\magstep2 +\setfont\secrm{bx12 scaled \magstep1} +\setfont\secit{ti12 scaled \magstep1} +\setfont\secsl{sl12 scaled \magstep1} +\setfont\sectt{tt12 scaled \magstep1} +\setfont\secsf{ss12 scaled \magstep1} +\setfont\secbf{bx12 scaled \magstep1} +\setfont\secsc{csc10 scaled\magstep2} \font\seci=cmmi12 scaled \magstep1 \font\secsy=cmsy10 scaled \magstep2 -% \font\ssecrm=cmbx10 scaled \magstep1 % This size an font looked bad. -% \font\ssecit=cmti10 scaled \magstep1 % The letters were too crowded. -% \font\ssecsl=cmsl10 scaled \magstep1 -% \font\ssectt=cmtt10 scaled \magstep1 -% \font\ssecsf=cmss10 scaled \magstep1 +% \setfont\ssecrm{bx10 scaled \magstep1} % This size an font looked bad. +% \setfont\ssecit{cmti10 scaled \magstep1} % The letters were too crowded. +% \setfont\ssecsl{sl10 scaled \magstep1} +% \setfont\ssectt{tt10 scaled \magstep1} +% \setfont\ssecsf{ss10 scaled \magstep1} -%\font\ssecrm=cmb10 scaled 1315 % Note the use of cmb rather than cmbx. -%\font\ssecit=cmti10 scaled 1315 % Also, the size is a little larger than -%\font\ssecsl=cmsl10 scaled 1315 % being scaled magstep1. -%\font\ssectt=cmtt10 scaled 1315 -%\font\ssecsf=cmss10 scaled 1315 +%\setfont\ssecrm{b10 scaled 1315} % Note the use of cmb rather than cmbx. +%\setfont\ssecit{ti10 scaled 1315} % Also, the size is a little larger than +%\setfont\ssecsl{sl10 scaled 1315} % being scaled magstep1. +%\setfont\ssectt{tt10 scaled 1315} +%\setfont\ssecsf{ss10 scaled 1315} %\let\ssecbf=\ssecrm -\font\ssecrm=cmbx12 scaled \magstephalf -\font\ssecit=cmti12 scaled \magstephalf -\font\ssecsl=cmsl12 scaled \magstephalf -\font\ssectt=cmtt12 scaled \magstephalf -\font\ssecsf=cmss12 scaled \magstephalf -\font\ssecbf=cmbx12 scaled \magstephalf -\font\ssecsc=cmcsc10 scaled \magstep1 +\setfont\ssecrm{bx12 scaled \magstephalf} +\setfont\ssecit{ti12 scaled \magstephalf} +\setfont\ssecsl{sl12 scaled \magstephalf} +\setfont\ssectt{tt12 scaled \magstephalf} +\setfont\ssecsf{ss12 scaled \magstephalf} +\setfont\ssecbf{bx12 scaled \magstephalf} +\setfont\ssecsc{csc10 scaled \magstep1} \font\sseci=cmmi12 scaled \magstephalf \font\ssecsy=cmsy10 scaled \magstep1 % The smallcaps and symbol fonts should actually be scaled \magstep1.5, % but that is not a standard magnification. % Fonts for title page: -\font\titlerm = cmbx12 scaled \magstep3 +\setfont\titlerm{bx12 scaled \magstep3} \let\authorrm = \secrm % In order for the font changes to affect most math symbols and letters, @@ -930,7 +1027,7 @@ where each line of input produces a line of output.} % texinfo doesn't allow for producing subscripts and superscripts, we % don't bother to reset \scriptfont and \scriptscriptfont (which would % also require loading a lot more fonts). -% +% \def\resetmathfonts{% \textfont0 = \tenrm \textfont1 = \teni \textfont2 = \tensy \textfont\itfam = \tenit \textfont\slfam = \tensl \textfont\bffam = \tenbf @@ -943,14 +1040,14 @@ where each line of input produces a line of output.} % in math mode, where it is the current \fam that is relevant in most % cases, not the current. Plain TeX does, for example, % \def\bf{\fam=\bffam \tenbf} By redefining \tenbf, we obviate the need -% to redefine \bf itself. +% to redefine \bf itself. \def\textfonts{% \let\tenrm=\textrm \let\tenit=\textit \let\tensl=\textsl \let\tenbf=\textbf \let\tentt=\texttt \let\smallcaps=\textsc \let\tensf=\textsf \let\teni=\texti \let\tensy=\textsy \resetmathfonts} \def\chapfonts{% - \let\tenrm=\chaprm \let\tenit=\chapit \let\tensl=\chapsl + \let\tenrm=\chaprm \let\tenit=\chapit \let\tensl=\chapsl \let\tenbf=\chapbf \let\tentt=\chaptt \let\smallcaps=\chapsc \let\tensf=\chapsf \let\teni=\chapi \let\tensy=\chapsy \resetmathfonts} @@ -971,16 +1068,16 @@ where each line of input produces a line of output.} \resetmathfonts} % Set up the default fonts, so we can use them for creating boxes. -% +% \textfonts % Count depth in font-changes, for error checks \newcount\fontdepth \fontdepth=0 % Fonts for short table of contents. -\font\shortcontrm=cmr12 -\font\shortcontbf=cmbx12 -\font\shortcontsl=cmsl12 +\setfont\shortcontrm{r12} +\setfont\shortcontbf{bx12} +\setfont\shortcontsl{sl12} %% Add scribe-like font environments, plus @l for inline lisp (usually sans %% serif) and @ii for TeX italic @@ -1002,16 +1099,15 @@ where each line of input produces a line of output.} % We can't just use \exhyphenpenalty, because that only has effect at % the end of a paragraph. Restore normal hyphenation at the end of the % group within which \nohyphenation is presumably called. -% +% \def\nohyphenation{\hyphenchar\font = -1 \aftergroup\restorehyphenation} \def\restorehyphenation{\hyphenchar\font = `- } \def\t#1{% - {\tt \nohyphenation \rawbackslash \frenchspacing #1}% + {\tt \rawbackslash \frenchspacing #1}% \null } -\let\ttfont = \t -%\def\samp #1{`{\tt \rawbackslash \frenchspacing #1}'\null} +\let\ttfont=\t \def\samp #1{`\tclose{#1}'\null} \def\key #1{{\tt \nohyphenation \uppercase{#1}}\null} \def\ctrl #1{{\tt \rawbackslash \hat}#1} @@ -1033,17 +1129,43 @@ where each line of input produces a line of output.} % % Turn off hyphenation. \nohyphenation - % + % \rawbackslash \frenchspacing #1% }% \null } -\let\code=\tclose + +% We *must* turn on hyphenation at `-' and `_' in \code. +% Otherwise, it is too hard to avoid overful hboxes +% in the Emacs manual, the Library manual, etc. + +% Unfortunately, TeX uses one parameter (\hyphenchar) to control +% both hyphenation at - and hyphenation within words. +% We must therefore turn them both off (\tclose does that) +% and arrange explicitly to hyphenate an a dash. +% -- rms. +{ +\catcode`\-=\active +\catcode`\_=\active +\global\def\code{\begingroup \catcode`\-=\active \let-\codedash \catcode`\_=\active \let_\codeunder \codex} +% The following is used by \doprintindex to insure that long function names +% wrap around. It is necessary for - and _ to be active before the index is +% read from the file, as \entry parses the arguments long before \code is +% ever called. -- mycroft +\global\def\indexbreaks{\catcode`\-=\active \let-\realdash \catcode`\_=\active \let_\realunder} +} + +\def\realdash{-} +\def\realunder{_} +\def\codedash{-\discretionary{}{}{}} +\def\codeunder{\normalunderscore\discretionary{}{}{}} +\def\codex #1{\tclose{#1}\endgroup} + %\let\exp=\tclose %Was temporary -% @kbd is like @code, except that if the argument is just one @key command, +% @kbd is like @code, except that if the argument is just one @key command, % then @kbd has no effect. \def\xkey{\key} @@ -1055,12 +1177,12 @@ where each line of input produces a line of output.} % Typeset a dimension, e.g., `in' or `pt'. The only reason for the % argument is to make the input look right: @dmn{pt} instead of % @dmn{}pt. -% +% \def\dmn#1{\thinspace #1} \def\kbd#1{\def\look{#1}\expandafter\kbdfoo\look??\par} -\def\l#1{{\li #1}\null} % +\def\l#1{{\li #1}\null} % \def\r#1{{\rm #1}} % roman font % Use of \lowercase was suggested. @@ -1099,7 +1221,7 @@ where each line of input produces a line of output.} \def\titlezzz##1{\leftline{\titlefont{##1}} % print a rule at the page bottom also. \finishedtitlepagefalse - \vskip4pt \hrule height 4pt \vskip4pt}% + \vskip4pt \hrule height 4pt width \hsize \vskip4pt}% % No rule at page bottom unless we print one at the top with @title. \finishedtitlepagetrue % @@ -1111,7 +1233,7 @@ where each line of input produces a line of output.} \def\author{\parsearg\authorzzz}% \def\authorzzz##1{\ifseenauthor\else\vskip 0pt plus 1filll\seenauthortrue\fi {\authorfont \leftline{##1}}}% - % + % % Most title ``pages'' are actually two pages long, with space % at the top of the second. We don't want the ragged left on the second. \let\oldpage = \page @@ -1139,7 +1261,7 @@ where each line of input produces a line of output.} } \def\finishtitlepage{% - \vskip4pt \hrule height 2pt + \vskip4pt \hrule height 2pt width \hsize \vskip\titlepagebottomglue \finishedtitlepagetrue } @@ -1313,14 +1435,18 @@ July\or August\or September\or October\or November\or December\fi % They also define \itemindex % to index the item name in whatever manner is desired (perhaps none). +\newif\ifitemxneedsnegativevskip + +\def\itemxpar{\par\ifitemxneedsnegativevskip\vskip-\parskip\nobreak\fi} + \def\internalBitem{\smallbreak \parsearg\itemzzz} -\def\internalBitemx{\par \parsearg\itemzzz} +\def\internalBitemx{\itemxpar \parsearg\itemzzz} \def\internalBxitem "#1"{\def\xitemsubtopix{#1} \smallbreak \parsearg\xitemzzz} -\def\internalBxitemx "#1"{\def\xitemsubtopix{#1} \par \parsearg\xitemzzz} +\def\internalBxitemx "#1"{\def\xitemsubtopix{#1} \itemxpar \parsearg\xitemzzz} \def\internalBkitem{\smallbreak \parsearg\kitemzzz} -\def\internalBkitemx{\par \parsearg\kitemzzz} +\def\internalBkitemx{\itemxpar \parsearg\kitemzzz} \def\kitemzzz #1{\dosubind {kw}{\code{#1}}{for {\bf \lastfunction}}% \itemzzz {#1}} @@ -1336,8 +1462,9 @@ July\or August\or September\or October\or November\or December\fi \nobreak % This prevents a break before @itemx. % % Be sure we are not still in the middle of a paragraph. - \parskip=0in - \par + %{\parskip = 0in + %\par + %}% % % If the item text does not fit in the space we have, put it on a line % by itself, and do not allow a page break either before or after that @@ -1345,17 +1472,36 @@ July\or August\or September\or October\or November\or December\fi % command is, e.g., @kindex, the whatsit would get put into the % horizontal list on a line by itself, resulting in extra blank space. \ifdim \wd0>\itemmax - \setbox0=\hbox{\hskip \leftskip \hskip -\tableindent \unhbox0}\box0 + % + % Make this a paragraph so we get the \parskip glue and wrapping, + % but leave it ragged-right. + \begingroup + \advance\leftskip by-\tableindent + \advance\hsize by\tableindent + \advance\rightskip by0pt plus1fil + \leavevmode\unhbox0\par + \endgroup + % + % We're going to be starting a paragraph, but we don't want the + % \parskip glue -- logically it's part of the @item we just started. + \nobreak \vskip-\parskip + % + % Stop a page break at the \parskip glue coming up. Unfortunately + % we can't prevent a possible page break at the following + % \baselineskip glue. \nobreak + \endgroup + \itemxneedsnegativevskipfalse \else % The item text fits into the space. Start a paragraph, so that the % following text (if any) will end up on the same line. Since that % text will be indented by \tableindent, we make the item text be in % a zero-width box. \noindent - \rlap{\hskip -\tableindent\box0}% + \rlap{\hskip -\tableindent\box0}\ignorespaces% + \endgroup% + \itemxneedsnegativevskiptrue% \fi - \endgroup } \def\item{\errmessage{@item while not in a table}} @@ -1377,14 +1523,14 @@ July\or August\or September\or October\or November\or December\fi {\obeylines\obeyspaces% \gdef\ftablex #1^^M{% \tabley\fnitemindex#1 \endtabley -\def\Eftable{\endgraf\endgroup\afterenvbreak}% +\def\Eftable{\endgraf\afterenvbreak\endgroup}% \let\Etable=\relax}} \def\vtable{\begingroup\inENV\obeylines\obeyspaces\vtablex} {\obeylines\obeyspaces% \gdef\vtablex #1^^M{% \tabley\vritemindex#1 \endtabley -\def\Evtable{\endgraf\endgroup\afterenvbreak}% +\def\Evtable{\endgraf\afterenvbreak\endgroup}% \let\Etable=\relax}} \def\dontindex #1{} @@ -1411,7 +1557,7 @@ July\or August\or September\or October\or November\or December\fi \parindent = 0pt \parskip = \smallskipamount \ifdim \parskip=0pt \parskip=2pt \fi% -\def\Etable{\endgraf\endgroup\afterenvbreak}% +\def\Etable{\endgraf\afterenvbreak\endgroup}% \let\item = \internalBitem % \let\itemx = \internalBitemx % \let\kitem = \internalBkitem % @@ -1440,7 +1586,7 @@ July\or August\or September\or October\or November\or December\fi \parindent = 0pt % \parskip = \smallskipamount % \ifdim \parskip=0pt \parskip=2pt \fi% -\def#2{\endgraf\endgroup\afterenvbreak}% +\def#2{\endgraf\afterenvbreak\endgroup}% \def\itemcontents{#1}% \let\item=\itemizeitem} @@ -1451,13 +1597,13 @@ July\or August\or September\or October\or November\or December\fi % \splitoff TOKENS\endmark defines \first to be the first token in % TOKENS, and \rest to be the remainder. -% +% \def\splitoff#1#2\endmark{\def\first{#1}\def\rest{#2}}% % Allow an optional argument of an uppercase letter, lowercase letter, % or number, to specify the first label in the enumerated list. No % argument is the same as `1'. -% +% \def\enumerate{\parsearg\enumeratezzz} \def\enumeratezzz #1{\enumeratey #1 \endenumeratey} \def\enumeratey #1 #2\endenumeratey{% @@ -1479,11 +1625,11 @@ July\or August\or September\or October\or November\or December\fi % An ``uppercase letter'' is one whose \lccode is both nonzero, and % not equal to itself. % Otherwise, we assume it's a number. - % + % % We need the \relax at the end of the \ifnum lines to stop TeX from % continuing to look for a . - % - \ifnum\lccode\expandafter`\thearg=0\relax + % + \ifnum\lccode\expandafter`\thearg=0\relax \numericenumerate % a number (we hope) \else % It's a letter. @@ -1501,7 +1647,7 @@ July\or August\or September\or October\or November\or December\fi % An @enumerate whose labels are integers. The starting integer is % given in \thearg. -% +% \def\numericenumerate{% \itemno = \thearg \startenumeration{\the\itemno}% @@ -1536,7 +1682,7 @@ July\or August\or September\or October\or November\or December\fi % Call itemizey, adding a period to the first argument and supplying the % common last two arguments. Also subtract one from the initial value in % \itemno, since @item increments \itemno. -% +% \def\startenumeration#1{% \advance\itemno by -1 \itemizey{#1.}\Eenumerate\flushcr @@ -1544,7 +1690,7 @@ July\or August\or September\or October\or November\or December\fi % @alphaenumerate and @capsenumerate are abbreviations for giving an arg % to @enumerate. -% +% \def\alphaenumerate{\enumerate{a}} \def\capsenumerate{\enumerate{A}} \def\Ealphaenumerate{\Eenumerate} @@ -1561,6 +1707,159 @@ July\or August\or September\or October\or November\or December\fi \vadjust{\penalty 1200}}% \flushcr} +% @multitable macros +% Amy Hendrickson, 8/18/94 +% +% @multitable ... @endmultitable will make as many columns as desired. +% Contents of each column will wrap at width given in preamble. Width +% can be specified either with sample text given in a template line, +% or in percent of \hsize, the current width of text on page. + +% Table can continue over pages but will only break between lines. + +% To make preamble: +% +% Either define widths of columns in terms of percent of \hsize: +% @multitable @percentofhsize .2 .3 .5 +% @item ... +% +% Numbers following @percentofhsize are the percent of the total +% current hsize to be used for each column. You may use as many +% columns as desired. + +% Or use a template: +% @multitable {Column 1 template} {Column 2 template} {Column 3 template} +% @item ... +% using the widest term desired in each column. + + +% Each new table line starts with @item, each subsequent new column +% starts with @tab. Empty columns may be produced by supplying @tab's +% with nothing between them for as many times as empty columns are needed, +% ie, @tab@tab@tab will produce two empty columns. + +% @item, @tab, @multicolumn or @endmulticolumn do not need to be on their +% own lines, but it will not hurt if they are. + +% Sample multitable: + +% @multitable {Column 1 template} {Column 2 template} {Column 3 template} +% @item first col stuff @tab second col stuff @tab third col +% @item +% first col stuff +% @tab +% second col stuff +% @tab +% third col +% @item first col stuff @tab second col stuff +% @tab Many paragraphs of text may be used in any column. +% +% They will wrap at the width determined by the template. +% @item@tab@tab This will be in third column. +% @endmultitable + +% Default dimensions may be reset by user. +% @intableparskip will set vertical space between paragraphs in table. +% @intableparindent will set paragraph indent in table. +% @spacebetweencols will set horizontal space to be left between columns. +% @spacebetweenlines will set vertical space to be left between lines. + +%%%% +% Dimensions + +\newdimen\intableparskip +\newdimen\intableparindent +\newdimen\spacebetweencols +\newdimen\spacebetweenlines +\intableparskip=0pt +\intableparindent=6pt +\spacebetweencols=12pt +\spacebetweenlines=12pt + +%%%% +% Macros used to set up halign preamble: +\let\endsetuptable\relax +\def\xendsetuptable{\endsetuptable} +\let\percentofhsize\relax +\def\xpercentofhsize{\percentofhsize} +\newif\ifsetpercent + +\newcount\colcount +\def\setuptable#1{\def\firstarg{#1}% +\ifx\firstarg\xendsetuptable\let\go\relax% +\else + \ifx\firstarg\xpercentofhsize\global\setpercenttrue% + \else + \ifsetpercent + \if#1.\else% + \global\advance\colcount by1 % + \expandafter\xdef\csname col\the\colcount\endcsname{.#1\hsize}% + \fi + \else + \global\advance\colcount by1 + \setbox0=\hbox{#1}% + \expandafter\xdef\csname col\the\colcount\endcsname{\the\wd0}% + \fi% + \fi% + \let\go\setuptable% +\fi\go} +%%%% +% multitable syntax +\def\tab{&} + +%%%% +% @multitable ... @endmultitable definitions: + +\def\multitable#1\item{\bgroup +\let\item\cr +\tolerance=9500 +\hbadness=9500 +\parskip=\intableparskip +\parindent=\intableparindent +\overfullrule=0pt +\global\colcount=0\relax% +\def\Emultitable{\global\setpercentfalse\global\everycr{}\cr\egroup\egroup}% + % To parse everything between @multitable and @item : +\def\one{#1}\expandafter\setuptable\one\endsetuptable + % Need to reset this to 0 after \setuptable. +\global\colcount=0\relax% + % + % This preamble sets up a generic column definition, which will + % be used as many times as user calls for columns. + % \vtop will set a single line and will also let text wrap and + % continue for many paragraphs if desired. +\halign\bgroup&\global\advance\colcount by 1\relax% +\vtop{\hsize=\expandafter\csname col\the\colcount\endcsname + % In order to keep entries from bumping into each other + % we will add a \leftskip of \spacebetweencols to all columns after + % the first one. + % If a template has been used, we will add \spacebetweencols + % to the width of each template entry. + % If user has set preamble in terms of percent of \hsize + % we will use that dimension as the width of the column, and + % the \leftskip will keep entries from bumping into each other. + % Table will start at left margin and final column will justify at + % right margin. +\ifnum\colcount=1 +\else + \ifsetpercent + \else + % If user has set preamble in terms of percent of \hsize + % we will advance \hsize by \spacebetweencols + \advance\hsize by \spacebetweencols + \fi + % In either case we will make \leftskip=\spacebetweencols: +\leftskip=\spacebetweencols +\fi +\noindent##}\cr% + % \everycr will reset column counter, \colcount, at the end of + % each line. Every column entry will cause \colcount to advance by one. + % The table preamble + % looks at the current \colcount to find the correct column width. +\global\everycr{\noalign{\nointerlineskip\vskip\spacebetweenlines +\filbreak%% keeps underfull box messages off when table breaks over pages. +\global\colcount=0\relax}}} + \message{indexing,} % Index generation facilities @@ -1635,6 +1934,32 @@ July\or August\or September\or October\or November\or December\fi \def\singlecodeindexer #1{\doind{\indexname}{\code{#1}}} \def\indexdummies{% +% Take care of the plain tex accent commands. +\def\"{\realbackslash "}% +\def\`{\realbackslash `}% +\def\'{\realbackslash '}% +\def\^{\realbackslash ^}% +\def\~{\realbackslash ~}% +\def\={\realbackslash =}% +\def\b{\realbackslash b}% +\def\c{\realbackslash c}% +\def\d{\realbackslash d}% +\def\u{\realbackslash u}% +\def\v{\realbackslash v}% +\def\H{\realbackslash H}% +% Take care of the plain tex special European modified letters. +\def\oe{\realbackslash oe}% +\def\ae{\realbackslash ae}% +\def\aa{\realbackslash aa}% +\def\OE{\realbackslash OE}% +\def\AE{\realbackslash AE}% +\def\AA{\realbackslash AA}% +\def\o{\realbackslash o}% +\def\O{\realbackslash O}% +\def\l{\realbackslash l}% +\def\L{\realbackslash L}% +\def\ss{\realbackslash ss}% +% Take care of texinfo commands likely to appear in an index entry. \def\_{{\realbackslash _}}% \def\w{\realbackslash w }% \def\bf{\realbackslash bf }% @@ -1672,6 +1997,31 @@ July\or August\or September\or October\or November\or December\fi \def\indexdummydots{...} \def\indexnofonts{% +% Just ignore accents. +\let\"=\indexdummyfont +\let\`=\indexdummyfont +\let\'=\indexdummyfont +\let\^=\indexdummyfont +\let\~=\indexdummyfont +\let\==\indexdummyfont +\let\b=\indexdummyfont +\let\c=\indexdummyfont +\let\d=\indexdummyfont +\let\u=\indexdummyfont +\let\v=\indexdummyfont +\let\H=\indexdummyfont +% Take care of the plain tex special European modified letters. +\def\oe{oe}% +\def\ae{ae}% +\def\aa{aa}% +\def\OE{OE}% +\def\AE{AE}% +\def\AA{AA}% +\def\o{o}% +\def\O{O}% +\def\l{l}% +\def\L{L}% +\def\ss{ss}% \let\w=\indexdummyfont \let\t=\indexdummyfont \let\r=\indexdummyfont @@ -1704,7 +2054,14 @@ July\or August\or September\or October\or November\or December\fi \let\indexbackslash=0 %overridden during \printindex. +\let\SETmarginindex=\relax %initialize! +% workhorse for all \fooindexes +% #1 is name of index, #2 is stuff to put there \def\doind #1#2{% +% Put the index entry in the margin if desired. +\ifx\SETmarginindex\relax\else% +\insert\margin{\hbox{\vrule height8pt depth3pt width0pt #2}}% +\fi% {\count10=\lastpenalty % {\indexdummies % Must do this here, since \bf, etc expand at this stage \escapechar=`\\% @@ -1760,7 +2117,7 @@ July\or August\or September\or October\or November\or December\fi % \secondary {subtopic}{pagelist} % for each subtopic. -% Define the user-accessible indexing commands +% Define the user-accessible indexing commands % @findex, @vindex, @kindex, @cindex. \def\findex {\fnindex} @@ -1788,8 +2145,9 @@ July\or August\or September\or October\or November\or December\fi \tex \dobreak \chapheadingskip {10000} \catcode`\%=\other\catcode`\&=\other\catcode`\#=\other - \catcode`\$=\other\catcode`\_=\other + \catcode`\$=\other \catcode`\~=\other + \indexbreaks % % The following don't help, since the chars were translated % when the raw index was written, and their fonts were discarded @@ -1807,7 +2165,7 @@ July\or August\or September\or October\or November\or December\fi % % See if the index file exists and is nonempty. \openin 1 \jobname.#1s - \ifeof 1 + \ifeof 1 % \enddoublecolumns gets confused if there is no text in the index, % and it loses the chapter title and the aux file entries for the % index. The easiest way to prevent this problem is to make sure @@ -1846,7 +2204,7 @@ July\or August\or September\or October\or November\or December\fi % This typesets a paragraph consisting of #1, dot leaders, and then #2 % flush to the right margin. It is used for index and table of contents % entries. The paragraph is indented by \leftskip. -% +% \def\entry #1#2{\begingroup % % Start a new paragraph if necessary, so our assignments below can't @@ -1867,7 +2225,7 @@ July\or August\or September\or October\or November\or December\fi % dots pretty far over on the line. Unfortunately, a large % indentation looks wrong when the entry text itself is broken across % lines. So we use a small indentation and put up with long leaders. - % + % % \hangafter is reset to 1 (which is the value we want) at the start % of each paragraph, so we need not do anything with that. \hangindent=2em @@ -1882,23 +2240,32 @@ July\or August\or September\or October\or November\or December\fi % % Insert the text of the index entry. TeX will do line-breaking on it. #1% - % - % If we must, put the page number on a line of its own, and fill out - % this line with blank space. (The \hfil is overwhelmed with the - % fill leaders glue in \indexdotfill if the page number does fit.) - \hfil\penalty50 - \null\nobreak\indexdotfill % Have leaders before the page number. - % - % The `\ ' here is removed by the implicit \unskip that TeX does as - % part of (the primitive) \par. Without it, a spurious underfull - % \hbox ensues. - \ #2% The page number ends the paragraph. + % The following is kluged to not output a line of dots in the index if + % there are no page numbers. The next person who breaks this will be + % cursed by a Unix daemon. + \def\tempa{{\rm }}% + \def\tempb{#2}% + \edef\tempc{\tempa}% + \edef\tempd{\tempb}% + \ifx\tempc\tempd\ \else% + % + % If we must, put the page number on a line of its own, and fill out + % this line with blank space. (The \hfil is overwhelmed with the + % fill leaders glue in \indexdotfill if the page number does fit.) + \hfil\penalty50 + \null\nobreak\indexdotfill % Have leaders before the page number. + % + % The `\ ' here is removed by the implicit \unskip that TeX does as + % part of (the primitive) \par. Without it, a spurious underfull + % \hbox ensues. + \ #2% The page number ends the paragraph. + \fi% \par \endgroup} % Like \dotfill except takes at least 1 em. \def\indexdotfill{\cleaders - \hbox{$\mathsurround=0pt \mkern1.5mu . \mkern1.5mu$}\hskip 1em plus 1fill} + \hbox{$\mathsurround=0pt \mkern1.5mu ${\it .}$ \mkern1.5mu$}\hskip 1em plus 1fill} \def\primary #1{\line{#1\hfil}} @@ -1932,17 +2299,17 @@ July\or August\or September\or October\or November\or December\fi % format, but then we repeat the same computation. Repeating a couple % of assignments once per index is clearly meaningless for the % execution time, so we may as well do it once. - % + % % First we halve the line length, less a little for the gutter between % the columns. We compute the gutter based on the line length, so it % changes automatically with the paper format. The magic constant % below is chosen so that the gutter has the same value (well, +- < % 1pt) as it did when we hard-coded it. - % + % % We put the result in a separate register, \doublecolumhsize, so we % can restore it in \pagesofar, after \hsize itself has (potentially) % been clobbered. - % + % \doublecolumnhsize = \hsize \advance\doublecolumnhsize by -.04154\hsize \divide\doublecolumnhsize by 2 @@ -2130,13 +2497,13 @@ July\or August\or September\or October\or November\or December\fi \def\chapteryyy #1{\numhead0{#1}} % normally numhead0 calls chapterzzz \def\chapterzzz #1{\seccheck{chapter}% \secno=0 \subsecno=0 \subsubsecno=0 -\global\advance \chapno by 1 \message{Chapter \the\chapno}% +\global\advance \chapno by 1 \message{\putwordChapter \the\chapno}% \chapmacro {#1}{\the\chapno}% \gdef\thissection{#1}% \gdef\thischaptername{#1}% % We don't substitute the actual chapter name into \thischapter % because we don't want its macros evaluated now. -\xdef\thischapter{Chapter \the\chapno: \noexpand\thischaptername}% +\xdef\thischapter{\putwordChapter{} \the\chapno: \noexpand\thischaptername}% {\chapternofonts% \edef\temp{{\realbackslash chapentry {#1}{\the\chapno}{\noexpand\folio}}}% \escapechar=`\\% @@ -2152,13 +2519,13 @@ July\or August\or September\or October\or November\or December\fi \def\appendixzzz #1{\seccheck{appendix}% \secno=0 \subsecno=0 \subsubsecno=0 \global\advance \appendixno by 1 \message{Appendix \appendixletter}% -\chapmacro {#1}{Appendix \appendixletter}% +\chapmacro {#1}{\putwordAppendix{} \appendixletter}% \gdef\thissection{#1}% \gdef\thischaptername{#1}% -\xdef\thischapter{Appendix \appendixletter: \noexpand\thischaptername}% +\xdef\thischapter{\putwordAppendix{} \appendixletter: \noexpand\thischaptername}% {\chapternofonts% -\edef\temp{{\realbackslash chapentry - {#1}{Appendix \appendixletter}{\noexpand\folio}}}% +\edef\temp{{\realbackslash chapentry + {#1}{\putwordAppendix{} \appendixletter}{\noexpand\folio}}}% \escapechar=`\\% \write \contentsfile \temp % \appendixnoderef % @@ -2177,8 +2544,8 @@ July\or August\or September\or October\or November\or December\fi % argument to \message. Therefore, if #1 contained @-commands, TeX % expanded them. For example, in `@unnumbered The @cite{Book}', TeX % expanded @cite (which turns out to cause errors because \cite is meant -% to be executed, not expanded). -% +% to be executed, not expanded). +% % Anyway, we don't want the fully-expanded definition of @cite to appear % as a result of the \message, we just want `@cite' itself. We use % \the to achieve this: TeX expands \the only once, @@ -2465,7 +2832,7 @@ July\or August\or September\or October\or November\or December\fi \let\paragraphindent=\comment % Section fonts are the base font at magstep2, which produces -% a size a bit more than 14 points in the default situation. +% a size a bit more than 14 points in the default situation. \def\secheading #1#2#3{\secheadingi {#2.#3\enspace #1}} \def\plainsecheading #1{\secheadingi {#1}} @@ -2477,7 +2844,7 @@ July\or August\or September\or October\or November\or December\fi \ifdim \parskip<10pt \kern 10pt\kern -\parskip\fi \penalty 10000 } -% Subsection fonts are the base font at magstep1, +% Subsection fonts are the base font at magstep1, % which produces a size of 12 points. \def\subsecheading #1#2#3#4{\subsecheadingi {#2.#3.#4\enspace #1}} @@ -2512,19 +2879,20 @@ July\or August\or September\or October\or November\or December\fi \ifnum \pageno>0 \pageno = -1 % Request roman numbered pages. \fi - % Don't need to put `Contents' or `Short Contents' in the headline. + % Don't need to put `Contents' or `Short Contents' in the headline. % It is abundantly clear what they are. \unnumbchapmacro{#1}\def\thischapter{}% \begingroup % Set up to handle contents files properly. \catcode`\\=0 \catcode`\{=1 \catcode`\}=2 \catcode`\@=11 + \catcode`\^=7 % to see ^^e4 as \"a etc. juha@piuha.ydi.vtt.fi \raggedbottom % Worry more about breakpoints than the bottom. \advance\hsize by -\contentsrightmargin % Don't use the full line length. } - + % Normal (long) toc. \outer\def\contents{% - \startcontents{Table of Contents}% + \startcontents{\putwordTableofContents}% \input \jobname.toc \endgroup \vfill \eject @@ -2532,7 +2900,7 @@ July\or August\or September\or October\or November\or December\fi % And just the chapters. \outer\def\summarycontents{% - \startcontents{Short Contents}% + \startcontents{\putwordShortContents}% % \let\chapentry = \shortchapentry \let\unnumbchapentry = \shortunnumberedentry @@ -2571,7 +2939,7 @@ July\or August\or September\or October\or November\or December\fi % We could simplify the code here by writing out an \appendixentry % command in the toc file for appendices, instead of using \chapentry % for both, but it doesn't seem worth it. -\setbox0 = \hbox{\shortcontrm Appendix } +\setbox0 = \hbox{\shortcontrm \putwordAppendix } \newdimen\shortappendixwidth \shortappendixwidth = \wd0 \def\shortchaplabel#1{% @@ -2608,10 +2976,10 @@ July\or August\or September\or October\or November\or December\fi % This parameter controls the indentation of the various levels. \newdimen\tocindent \tocindent = 3pc -% Now for the actual typesetting. In all these, #1 is the text and #2 is the +% Now for the actual typesetting. In all these, #1 is the text and #2 is the % page number. % -% If the toc has to be broken over pages, we would want to be at chapters +% If the toc has to be broken over pages, we would want to be at chapters % if at all possible; hence the \penalty. \def\dochapentry#1#2{% \penalty-300 \vskip\baselineskip @@ -2641,10 +3009,11 @@ July\or August\or September\or October\or November\or December\fi % the index entries, but we want to suppress hyphenation here. (We % can't do that in the \entry macro, since index entries might consist % of hyphenated-identifiers-that-do-not-fit-on-a-line-and-nothing-else.) -% +% +% \turnoffactive is for the sake of @" used for umlauts. \def\tocentry#1#2{\begingroup \hyphenpenalty = 10000 - \entry{#1}{#2}% + \entry{\turnoffactive #1}{\turnoffactive #2}% \endgroup} % Space between chapter (or whatever) number and the title. @@ -2661,7 +3030,7 @@ July\or August\or September\or October\or November\or December\fi \message{environments,} -% Since these characters are used in examples, it should be an even number of +% Since these characters are used in examples, it should be an even number of % \tt widths. Each \tt character is 1en, so two makes it 1em. % Furthermore, these definitions must come after we define our fonts. \newbox\dblarrowbox \newbox\longdblarrowbox @@ -2725,6 +3094,7 @@ July\or August\or September\or October\or November\or December\fi \catcode`\>=12 \escapechar=`\\ % +\let\~=\ptextilde \let\{=\ptexlbrace \let\}=\ptexrbrace \let\.=\ptexdot @@ -2744,28 +3114,32 @@ July\or August\or September\or October\or November\or December\fi % Amount to narrow the margins by for @lisp. \newskip\lispnarrowing \lispnarrowing=0.4in -% This is the definition that ^M gets inside @lisp -% phr: changed space to \null, to avoid overfull hbox problems. -{\obeyspaces% -\gdef\lisppar{\null\endgraf}} +% This is the definition that ^^M gets inside @lisp, @example, and other +% such environments. \null is better than a space, since it doesn't +% have any width. +\def\lisppar{\null\endgraf} % Make each space character in the input produce a normal interword % space in the output. Don't allow a line break at this space, as this % is used only in environments like @example, where each line of input % should produce a line of output anyway. -% +% {\obeyspaces % \gdef\sepspaces{\obeyspaces\let =\tie}} % Define \obeyedspace to be our active space, whatever it is. This is % for use in \parsearg. -{\sepspaces % +{\sepspaces% \global\let\obeyedspace= } % This space is always present above and below environments. \newskip\envskipamount \envskipamount = 0pt -% Make spacing and below environment symmetrical. +% Make spacing and below environment symmetrical. We use \parskip here +% to help in doing that, since in @example-like environments \parskip +% is reset to zero; thus the \afterenvbreak inserts no space -- but the +% start of the next paragraph will insert \parskip +% \def\aboveenvbreak{{\advance\envskipamount by \parskip \endgraf \ifdim\lastskip<\envskipamount \removelastskip \penalty-50 \vskip\envskipamount \fi}} @@ -2800,7 +3174,7 @@ July\or August\or September\or October\or November\or December\fi \begingroup \lskip=\leftskip \rskip=\rightskip \leftskip=0pt\rightskip=0pt %we want these *outside*. - \cartinner=\hsize \advance\cartinner by-\lskip + \cartinner=\hsize \advance\cartinner by-\lskip \advance\cartinner by-\rskip \cartouter=\hsize \advance\cartouter by 18pt % allow for 3pt kerns on either @@ -2833,7 +3207,7 @@ July\or August\or September\or October\or November\or December\fi \cartbot \egroup \endgroup -}} +}} % This macro is called at the beginning of all the @example variants, @@ -2843,7 +3217,7 @@ July\or August\or September\or October\or November\or December\fi \inENV % This group ends at the end of the body \hfuzz = 12pt % Don't be fussy \sepspaces % Make spaces be word-separators rather than space tokens. - \singlespace % single space lines + \singlespace \let\par = \lisppar % don't ignore blank lines \obeylines % each line of input is a line of output \parskip = 0pt @@ -2859,37 +3233,45 @@ July\or August\or September\or October\or November\or December\fi \fi } -\def\Elisp{\endgroup\afterenvbreak}% +% To ending an @example-like environment, we first end the paragraph +% (via \afterenvbreak's vertical glue), and then the group. That way we +% keep the zero \parskip that the environments set -- \parskip glue +% will be inserted at the beginning of the next paragraph in the +% document, after the environment. +% +\def\nonfillfinish{\afterenvbreak\endgroup}% +% This macro is \def\lisp{\begingroup \nonfillstart - \def\Elisp{\endgroup\afterenvbreak}% + \let\Elisp = \nonfillfinish \tt - \rawbackslash % output the \ character from the current font + \rawbackslash % have \ input char produce \ char from current font \gobble } % Define the \E... control sequence only if we are inside the % environment, so the error checking in \end will work. -% +% % We must call \lisp last in the definition, since it reads the % return following the @example (or whatever) command. % -\def\example{\begingroup \def\Eexample{\Elisp\endgroup}\lisp} -\def\smallexample{\begingroup \def\Esmallexample{\Elisp\endgroup}\lisp} +\def\example{\begingroup \def\Eexample{\nonfillfinish\endgroup}\lisp} +\def\smallexample{\begingroup \def\Esmallexample{\nonfillfinish\endgroup}\lisp} +\def\smalllisp{\begingroup \def\Esmalllisp{\nonfillfinish\endgroup}\lisp} -% Macro for 9 pt. examples, necessary to print with 5" lines. From -% Pavel@xerox. This is not used for @smallexamples unless the -% @smallbook command is given. +% @smallexample and @smalllisp. This is not used unless the @smallbook +% command is given. Originally contributed by Pavel@xerox. % \def\smalllispx{\begingroup \nonfillstart - \def\Esmalllisp{\endgroup\afterenvbreak}% + \let\Esmalllisp = \nonfillfinish + \let\Esmallexample = \nonfillfinish % % Smaller interline space and fonts for small examples. - \baselineskip 10pt + \setleading{10pt}% \indexfonts \tt - \rawbackslash % output the \ character from the current font + \rawbackslash % make \ output the \ character from the current font (tt) \gobble } @@ -2897,7 +3279,7 @@ July\or August\or September\or October\or November\or December\fi % \def\display{\begingroup \nonfillstart - \def\Edisplay{\endgroup\afterenvbreak}% + \let\Edisplay = \nonfillfinish \gobble } @@ -2906,7 +3288,7 @@ July\or August\or September\or October\or November\or December\fi \def\format{\begingroup \let\nonarrowing = t \nonfillstart - \def\Eformat{\endgroup\afterenvbreak} + \let\Eformat = \nonfillfinish \gobble } @@ -2915,33 +3297,36 @@ July\or August\or September\or October\or November\or December\fi \def\flushleft{\begingroup \let\nonarrowing = t \nonfillstart - \def\Eflushleft{\endgroup\afterenvbreak}% + \let\Eflushleft = \nonfillfinish \gobble } \def\flushright{\begingroup \let\nonarrowing = t \nonfillstart - \def\Eflushright{\endgroup\afterenvbreak}% + \let\Eflushright = \nonfillfinish \advance\leftskip by 0pt plus 1fill \gobble} -% @quotation does normal linebreaking and narrows the margins. +% @quotation does normal linebreaking (hence we can't use \nonfillstart) +% and narrows the margins. % \def\quotation{% -\begingroup\inENV %This group ends at the end of the @quotation body -{\parskip=0pt % because we will skip by \parskip too, later -\aboveenvbreak}% -\singlespace -\parindent=0pt -\def\Equotation{\par\endgroup\afterenvbreak}% -% @cartouche defines \nonarrowing to inhibit narrowing -% at next level down. -\ifx\nonarrowing\relax -\advance \leftskip by \lispnarrowing -\advance \rightskip by \lispnarrowing -\exdentamount=\lispnarrowing -\let\nonarrowing=\relax -\fi} + \begingroup\inENV %This group ends at the end of the @quotation body + {\parskip=0pt \aboveenvbreak}% because \aboveenvbreak inserts \parskip + \singlespace + \parindent=0pt + % We have retained a nonzero parskip for the environment, since we're + % doing normal filling. So to avoid extra space below the environment... + \def\Equotation{\parskip = 0pt \nonfillfinish}% + % + % @cartouche defines \nonarrowing to inhibit narrowing at next level down. + \ifx\nonarrowing\relax + \advance\leftskip by \lispnarrowing + \advance\rightskip by \lispnarrowing + \exdentamount = \lispnarrowing + \let\nonarrowing = \relax + \fi +} \message{defuns,} % Define formatter for defuns @@ -2973,6 +3358,9 @@ July\or August\or September\or October\or November\or December\fi \gdef\functionparens{\boldbrax\let&=\amprm\parencount=0 } \gdef\boldbrax{\let(=\opnr\let)=\clnr\let[=\lbrb\let]=\rbrb} +% This is used to turn on special parens +% but make & act ordinary (given that it's active). +\gdef\boldbraxnoamp{\let(=\opnr\let)=\clnr\let[=\lbrb\let]=\rbrb\let&=\ampnr} % Definitions of (, ) and & used in args for functions. % This is the definition of ( outside of all parentheses. @@ -3020,7 +3408,7 @@ July\or August\or September\or October\or November\or December\fi \advance \hsize by -\dimen2 \advance \hsize by -\dimen3 \rlap{\rightline{{\rm #2}\hskip \deftypemargin}}}% % Make all lines underfull and no complaints: -\tolerance=10000 \hbadness=10000 +\tolerance=10000 \hbadness=10000 \advance\leftskip by -\defbodyindent \exdentamount=\defbodyindent {\df #1}\enskip % Generate function name @@ -3042,7 +3430,7 @@ July\or August\or September\or October\or November\or December\fi \advance\leftskip by \defbodyindent \advance \rightskip by \defbodyindent \exdentamount=\defbodyindent \begingroup % -\catcode 61=\active % +\catcode 61=\active % 61 is `=' \obeylines\activeparens\spacesplit#3} \def\defmethparsebody #1#2#3#4 {\begingroup\inENV % @@ -3085,55 +3473,54 @@ July\or August\or September\or October\or November\or December\fi \catcode 61=\active % \obeylines\spacesplit#3} -\def\defvrparsebody #1#2#3#4 {\begingroup\inENV % -\medbreak % -% Define the end token that this defining construct specifies -% so that it will exit this group. -\def#1{\endgraf\endgroup\medbreak}% -\def#2##1 {\begingroup\obeylines\spacesplit{#3{##1}}}% -\parindent=0in -\advance\leftskip by \defbodyindent \advance \rightskip by \defbodyindent -\exdentamount=\defbodyindent -\begingroup\obeylines\spacesplit{#3{#4}}} - -% This seems to work right in all cases. -\let\deftpparsebody=\defvrparsebody -% This fails to work. When given `@deftp {Data Type} foo_t', -% it thinks the type name is just `f'. -%%% This is the same as all the others except for the last line. We need -%%% to parse the arguments differently for @deftp, since the ``attributes'' -%%% there are optional. -%%% -%%\def\deftpparsebody #1#2#3#4 {\begingroup\inENV % -%%\medbreak % -%%% Define the end token that this defining construct specifies -%%% so that it will exit this group. -%%\def#1{\endgraf\endgroup\medbreak}% -%%\def#2##1 {\begingroup\obeylines\spacesplit{#3{##1}}}% -%%\parindent=0in -%%\advance\leftskip by \defbodyindent \advance \rightskip by \defbodyindent -%%\exdentamount=\defbodyindent -%%\begingroup\obeylines\parsetpheaderline{#3{#4}}} - -%%{\obeylines % -%% % Parse the type name and any attributes (field names, etc.). -%% % #1 is the beginning of the macro call that will produce the output, -%% % i.e., \deftpheader{CLASS}; this is passed from \deftpparsebody. -%% % #2 is the type name, e.g., `struct termios'. -%% % #3 is the (possibly empty) attribute list. -%% % -%% \gdef\parsetpheaderline#1#2#3^^M{% -%% \endgroup % Started in \deftpparsebody. -%% % -%% % If the attribute list is in fact empty, there will be no space after -%% % #2; so we can't put a space in our TeX parameter list. But if it -%% % isn't empty, then #3 will begin with an unwanted space. -%% \def\theargs{\ignorespaces #3}% -%% % -%% % Call the macro to produce the output. -%% #1{#2}\theargs % -%% }% -%%} +% This is used for \def{tp,vr}parsebody. It could probably be used for +% some of the others, too, with some judicious conditionals. +% +\def\parsebodycommon#1#2#3{% + \begingroup\inENV % + \medbreak % + % Define the end token that this defining construct specifies + % so that it will exit this group. + \def#1{\endgraf\endgroup\medbreak}% + \def#2##1 {\begingroup\obeylines\spacesplit{#3{##1}}}% + \parindent=0in + \advance\leftskip by \defbodyindent \advance \rightskip by \defbodyindent + \exdentamount=\defbodyindent + \begingroup\obeylines +} + +\def\defvrparsebody#1#2#3#4 {% + \parsebodycommon{#1}{#2}{#3}% + \spacesplit{#3{#4}}% +} + +% This loses on `@deftp {Data Type} {struct termios}' -- it thinks the +% type is just `struct', because we lose the braces in `{struct +% termios}' when \spacesplit reads its undelimited argument. Sigh. +% \let\deftpparsebody=\defvrparsebody +% +% So, to get around this, we put \empty in with the type name. That +% way, TeX won't find exactly `{...}' as an undelimited argument, and +% won't strip off the braces. +% +\def\deftpparsebody #1#2#3#4 {% + \parsebodycommon{#1}{#2}{#3}% + \spacesplit{\parsetpheaderline{#3{#4}}}\empty +} + +% Fine, but then we have to eventually remove the \empty *and* the +% braces (if any). That's what this does, putting the result in \tptemp. +% +\def\removeemptybraces\empty#1\relax{\def\tptemp{#1}}% + +% After \spacesplit has done its work, this is called -- #1 is the final +% thing to call, #2 the type name (which starts with \empty), and #3 +% (which might be empty) the arguments. +% +\def\parsetpheaderline#1#2#3{% + \removeemptybraces#2\relax + #1{\tptemp}{#3}% +}% \def\defopvarparsebody #1#2#3#4#5 {\begingroup\inENV % \medbreak % @@ -3182,8 +3569,9 @@ July\or August\or September\or October\or November\or December\fi \def\deftypefunargs #1{% % Expand, preventing hyphenation at `-' chars. % Note that groups don't affect changes in \hyphenchar. -\functionparens -\code{#1}% +% Use \boldbraxnoamp, not \functionparens, so that & is not special. +\boldbraxnoamp +\tclose{#1}% avoid \code because of side effects on active chars \interlinepenalty=10000 \advance\rightskip by 0pt plus 1fil \endgraf\penalty 10000\vskip -\parskip\penalty 10000% @@ -3219,7 +3607,7 @@ July\or August\or September\or October\or November\or December\fi % #1 is the data type, #2 the name, #3 the args. \def\deftypefunheaderx #1#2 #3\relax{% \doind {fn}{\code{#2}}% Make entry in function index -\begingroup\defname {\code{#1} #2}{Function}% +\begingroup\defname {\defheaderxcond#1\relax$$$#2}{Function}% \deftypefunargs {#3}\endgroup % \catcode 61=\other % Turn off change made in \defparsebody } @@ -3228,12 +3616,19 @@ July\or August\or September\or October\or November\or December\fi \def\deftypefn{\defmethparsebody\Edeftypefn\deftypefnx\deftypefnheader} +% \defheaderxcond#1\relax$$$ +% puts #1 in @code, followed by a space, but does nothing if #1 is null. +\def\defheaderxcond#1#2$$${\ifx#1\relax\else\code{#1#2} \fi} + % #1 is the classification. #2 is the data type. #3 is the name and args. \def\deftypefnheader #1#2#3{\deftypefnheaderx{#1}{#2}#3 \relax} % #1 is the classification, #2 the data type, #3 the name, #4 the args. \def\deftypefnheaderx #1#2#3 #4\relax{% \doind {fn}{\code{#3}}% Make entry in function index -\begingroup\defname {\code{#2} #3}{#1}% +\begingroup +\normalparens % notably, turn off `&' magic, which prevents +% at least some C++ text from working +\defname {\defheaderxcond#2\relax$$$#3}{#1}% \deftypefunargs {#4}\endgroup % \catcode 61=\other % Turn off change made in \defparsebody } @@ -3361,7 +3756,7 @@ July\or August\or September\or October\or November\or December\fi % #1 is the data type. #2 is the name. \def\deftypevarheader #1#2{% \doind {vr}{\code{#2}}% Make entry in variables index -\begingroup\defname {\code{#1} #2}{Variable}% +\begingroup\defname {\defheaderxcond#1\relax$$$#2}{Variable}% \interlinepenalty=10000 \endgraf\penalty 10000\vskip -\parskip\penalty 10000 \endgroup} @@ -3371,7 +3766,7 @@ July\or August\or September\or October\or November\or December\fi \def\deftypevr{\defvrparsebody\Edeftypevr\deftypevrx\deftypevrheader} \def\deftypevrheader #1#2#3{\doind {vr}{\code{#3}}% -\begingroup\defname {\code{#2} #3}{#1} +\begingroup\defname {\defheaderxcond#2\relax$$$#3}{#1} \interlinepenalty=10000 \endgraf\penalty 10000\vskip -\parskip\penalty 10000 \endgroup} @@ -3412,17 +3807,17 @@ July\or August\or September\or October\or November\or December\fi % \setref{foo} defines a cross-reference point named foo. \def\setref#1{% -%\dosetq{#1-title}{Ytitle}% +\dosetq{#1-title}{Ytitle}% \dosetq{#1-pg}{Ypagenumber}% \dosetq{#1-snt}{Ysectionnumberandtype}} \def\unnumbsetref#1{% -%\dosetq{#1-title}{Ytitle}% +\dosetq{#1-title}{Ytitle}% \dosetq{#1-pg}{Ypagenumber}% \dosetq{#1-snt}{Ynothing}} \def\appendixsetref#1{% -%\dosetq{#1-title}{Ytitle}% +\dosetq{#1-title}{Ytitle}% \dosetq{#1-pg}{Ypagenumber}% \dosetq{#1-snt}{Yappendixletterandtype}} @@ -3431,44 +3826,64 @@ July\or August\or September\or October\or November\or December\fi % cross-reference, #3 the printed node name, #4 the name of the Info % file, #5 the name of the printed manual. All but the node name can be % omitted. -% -\def\pxref#1{see \xrefX[#1,,,,,,,]} -\def\xref#1{See \xrefX[#1,,,,,,,]} -\def\ref#1{\xrefX[#1,,,,,,,]} -\def\xrefX[#1,#2,#3,#4,#5,#6]{\begingroup% -\def\printedmanual{\ignorespaces #5}% -\def\printednodename{\ignorespaces #3}% -% -\setbox1=\hbox{\printedmanual}% -\setbox0=\hbox{\printednodename}% -\ifdim \wd0=0pt% -\def\printednodename{\ignorespaces #1}% -%%% Uncommment the following line to make the actual chapter or section title -%%% appear inside the square brackets. -%\def\printednodename{#1-title}% -\fi% -% % -% If we use \unhbox0 and \unhbox1 to print the node names, TeX does -% not insert empty discretionaries after hyphens, which means that it -% will not find a line break at a hyphen in a node names. Since some -% manuals are best written with fairly long node names, containing -% hyphens, this is a loss. Therefore, we simply give the text of -% the node name again, so it is as if TeX is seeing it for the first -% time. -\ifdim \wd1>0pt -section ``\printednodename'' in \cite{\printedmanual}% -\else% -\turnoffactive% -\refx{#1-snt}{} [\printednodename], page\tie\refx{#1-pg}{}% -\fi +\def\pxref#1{\putwordsee{} \xrefX[#1,,,,,,,]} +\def\xref#1{\putwordSee{} \xrefX[#1,,,,,,,]} +\def\ref#1{\xrefX[#1,,,,,,,]} +\def\xrefX[#1,#2,#3,#4,#5,#6]{\begingroup + \def\printedmanual{\ignorespaces #5}% + \def\printednodename{\ignorespaces #3}% + \setbox1=\hbox{\printedmanual}% + \setbox0=\hbox{\printednodename}% + \ifdim \wd0 = 0pt + % No printed node name was explicitly given. + \ifx\SETxref-automatic-section-title\relax % + % Use the actual chapter/section title appear inside + % the square brackets. Use the real section title if we have it. + \ifdim \wd1>0pt% + % It is in another manual, so we don't have it. + \def\printednodename{\ignorespaces #1}% + \else + \ifhavexrefs + % We know the real title if we have the xref values. + \def\printednodename{\refx{#1-title}}% + \else + % Otherwise just copy the Info node name. + \def\printednodename{\ignorespaces #1}% + \fi% + \fi + \def\printednodename{#1-title}% + \else + % Use the node name inside the square brackets. + \def\printednodename{\ignorespaces #1}% + \fi + \fi + % + % If we use \unhbox0 and \unhbox1 to print the node names, TeX does not + % insert empty discretionaries after hyphens, which means that it will + % not find a line break at a hyphen in a node names. Since some manuals + % are best written with fairly long node names, containing hyphens, this + % is a loss. Therefore, we give the text of the node name again, so it + % is as if TeX is seeing it for the first time. + \ifdim \wd1 > 0pt + \putwordsection{} ``\printednodename'' in \cite{\printedmanual}% + \else + % _ (for example) has to be the character _ for the purposes of the + % control sequence corresponding to the node, but it has to expand + % into the usual \leavevmode...\vrule stuff for purposes of + % printing. So we \turnoffactive for the \refx-snt, back on for the + % printing, back off for the \refx-pg. + {\turnoffactive \refx{#1-snt}{}}% + \space [\printednodename],\space + \turnoffactive \putwordpage\tie\refx{#1-pg}{}% + \fi \endgroup} % \dosetq is the interface for calls from other macros % Use \turnoffactive so that punctuation chars such as underscore % work in node names. -\def\dosetq #1#2{{\let\folio=0 \turnoffactive% +\def\dosetq #1#2{{\let\folio=0 \turnoffactive \auxhat% \edef\next{\write\auxfile{\internalsetq {#1}{#2}}}% \next}} @@ -3482,33 +3897,33 @@ section ``\printednodename'' in \cite{\printedmanual}% \def\Ypagenumber{\folio} -\def\Ytitle{\thischapter} +\def\Ytitle{\thissection} \def\Ynothing{} \def\Ysectionnumberandtype{% -\ifnum\secno=0 Chapter\xreftie\the\chapno % -\else \ifnum \subsecno=0 Section\xreftie\the\chapno.\the\secno % +\ifnum\secno=0 \putwordChapter\xreftie\the\chapno % +\else \ifnum \subsecno=0 \putwordSection\xreftie\the\chapno.\the\secno % \else \ifnum \subsubsecno=0 % -Section\xreftie\the\chapno.\the\secno.\the\subsecno % +\putwordSection\xreftie\the\chapno.\the\secno.\the\subsecno % \else % -Section\xreftie\the\chapno.\the\secno.\the\subsecno.\the\subsubsecno % +\putwordSection\xreftie\the\chapno.\the\secno.\the\subsecno.\the\subsubsecno % \fi \fi \fi } \def\Yappendixletterandtype{% -\ifnum\secno=0 Appendix\xreftie'char\the\appendixno{}% -\else \ifnum \subsecno=0 Section\xreftie'char\the\appendixno.\the\secno % +\ifnum\secno=0 \putwordAppendix\xreftie'char\the\appendixno{}% +\else \ifnum \subsecno=0 \putwordSection\xreftie'char\the\appendixno.\the\secno % \else \ifnum \subsubsecno=0 % -Section\xreftie'char\the\appendixno.\the\secno.\the\subsecno % +\putwordSection\xreftie'char\the\appendixno.\the\secno.\the\subsecno % \else % -Section\xreftie'char\the\appendixno.\the\secno.\the\subsecno.\the\subsubsecno % +\putwordSection\xreftie'char\the\appendixno.\the\secno.\the\subsecno.\the\subsubsecno % \fi \fi \fi } \gdef\xreftie{'tie} % Use TeX 3.0's \inputlineno to get the line number, for better error % messages, but if we're using an old version of TeX, don't do anything. -% +% \ifx\inputlineno\thisisundefined \let\linenumber = \empty % Non-3.0. \else @@ -3589,6 +4004,15 @@ Section\xreftie'char\the\appendixno.\the\secno.\the\subsecno.\the\subsubsecno % \catcode `\&=\other % `\+ does not work, so use 43. \catcode 43=\other +% Make the characters 128-255 be printing characters +{% + \count 1=128 + \def\loop{% + \catcode\count 1=\other + \advance\count 1 by 1 + \ifnum \count 1<256 \loop \fi + }% +}% % the aux file uses ' as the escape. % Turn off \ as an escape so we do not lose on % entries which were dumped with control sequences in their names. @@ -3598,6 +4022,7 @@ Section\xreftie'char\the\appendixno.\the\secno.\the\subsecno.\the\subsubsecno % \catcode `\{=1 \catcode `\}=2 \catcode `\%=\other \catcode `\'=0 +\catcode`\^=7 % to make ^^e4 etc usable in xref tags \catcode `\\=\other \openin 1 \jobname.aux \ifeof 1 \else \closein 1 \input \jobname.aux \global\havexrefstrue @@ -3643,7 +4068,7 @@ Section\xreftie'char\the\appendixno.\the\secno.\the\subsecno.\the\subsubsecno % % Don't bother with the trickery in plain.tex to not require the % footnote text as a parameter. Our footnotes don't need to be so general. -% +% \long\gdef\footnotezzz#1{\insert\footins{% % We want to typeset this text as a normal paragraph, even if the % footnote reference occurs in (for example) a display environment. @@ -3674,15 +4099,15 @@ Section\xreftie'char\the\appendixno.\the\secno.\the\subsecno.\the\subsubsecno % % Set the baselineskip to #1, and the lineskip and strut size % correspondingly. There is no deep meaning behind these magic numbers % used as factors; they just match (closely enough) what Knuth defined. -% -\def\lineskipfactor{.1} -\def\strutheightpercent{.71} -\def\strutdepthpercent{.29} +% +\def\lineskipfactor{.08333} +\def\strutheightpercent{.70833} +\def\strutdepthpercent {.29167} % \def\setleading#1{% - \baselineskip = #1\relax - \normalbaselineskip = \baselineskip - \lineskip = \lineskipfactor\baselineskip + \normalbaselineskip = #1\relax + \normallineskip = \lineskipfactor\normalbaselineskip + \normalbaselines \setbox\strutbox =\hbox{% \vrule width0pt height\strutheightpercent\baselineskip depth \strutdepthpercent \baselineskip @@ -3694,7 +4119,7 @@ Section\xreftie'char\the\appendixno.\the\secno.\the\subsecno.\the\subsubsecno % % change spans more than two lines of output. To handle that, we would % have adopt a much more difficult approach (putting marks into the main % vertical list for the beginning and end of each change). -% +% \def\|{% % \vadjust can only be used in horizontal mode. \leavevmode @@ -3721,7 +4146,7 @@ Section\xreftie'char\the\appendixno.\the\secno.\the\subsecno.\the\subsubsecno % % For a final copy, take out the rectangles % that mark overfull boxes (in case you have decided % that the text looks ok even though it passes the margin). -% +% \def\finalout{\overfullrule=0pt} @@ -3758,7 +4183,7 @@ Section\xreftie'char\the\appendixno.\the\secno.\the\subsecno.\the\subsubsecno % % using an old version of TeX, don't do anything. We want the amount of % stretch added to depend on the line length, hence the dependence on % \hsize. This makes it come to about 9pt for the 8.5x11 format. -% +% \ifx\emergencystretch\thisisundefined % Allow us to assign to \emergencystretch anyway. \def\emergencystretch{\dimen0}% @@ -3784,6 +4209,8 @@ Section\xreftie'char\the\appendixno.\the\secno.\the\subsecno.\the\subsubsecno % \global\tolerance=700 \global\hfuzz=1pt \global\contentsrightmargin=0pt +\global\deftypemargin=0pt +\global\defbodyindent=.5cm \global\pagewidth=\hsize \global\pageheight=\vsize @@ -3813,6 +4240,32 @@ Section\xreftie'char\the\appendixno.\the\secno.\the\subsecno.\the\subsubsecno % \global\pageheight=\vsize } +% Allow control of the text dimensions. Parameters in order: textheight; +% textwidth; \voffset; \hoffset (!); binding offset. All require a dimension; +% header is additional; added length extends the bottom of the page. + +\def\changepagesizes#1#2#3#4#5{ + \global\vsize= #1 + \advance\vsize by \topskip + \global\voffset= #3 + \global\hsize= #2 + \global\outerhsize=\hsize + \global\advance\outerhsize by 0.5in + \global\outervsize=\vsize + \global\advance\outervsize by 0.6in + \global\pagewidth=\hsize + \global\pageheight=\vsize + \global\normaloffset= #4 + \global\bindingoffset= #5} + +% This layout is compatible with Latex on A4 paper. + +\def\afourlatex{\changepagesizes{22cm}{15cm}{7mm}{4.6mm}{5mm}} + +% Use @afourwide to print on European A4 paper in wide format. +\def\afourwide{\afourpaper +\changepagesizes{9.5in}{6.5in}{\hoffset}{\normaloffset}{\bindingoffset}} + % Define macros to output various characters with catcode for normal text. \catcode`\"=\other \catcode`\~=\other @@ -3839,7 +4292,7 @@ Section\xreftie'char\the\appendixno.\the\secno.\the\subsecno.\the\subsubsecno % % otherwise. Since all the Computer Modern typewriter fonts have zero % interword stretch (and shrink), and it is reasonable to expect all % typewriter fonts to have this, we can check that font parameter. -% +% \def\ifusingtt#1#2{\ifdim \fontdimen3\the\font=0pt #1\else #2\fi} % Turn off all special characters except @ @@ -3854,6 +4307,7 @@ Section\xreftie'char\the\appendixno.\the\secno.\the\subsecno.\the\subsubsecno % \def~{{\tt \char '176}} \chardef\hat=`\^ \catcode`\^=\active +\def\auxhat{\def^{'hat}} \def^{{\tt \hat}} \catcode`\_=\active @@ -3881,21 +4335,19 @@ Section\xreftie'char\the\appendixno.\the\secno.\the\subsecno.\the\subsubsecno % %\catcode 27=\active %\def^^[{$\diamondsuit$} -% Used sometimes to turn off (effectively) the active characters -% even after parsing them. -\def\turnoffactive{\let"=\normaldoublequote -\let~=\normaltilde -\let^=\normalcaret -\let_=\normalunderscore -\let|=\normalverticalbar -\let<=\normalless -\let>=\normalgreater -\let+=\normalplus} - % Set up an active definition for =, but don't enable it most of the time. {\catcode`\==\active \global\def={{\tt \char 61}}} +\catcode`+=\active +\catcode`\_=\active + +% If a .fmt file is being used, characters that might appear in a file +% name cannot be active until we have parsed the command line. +% So turn them off again, and have \everyjob (or @setfilename) turn them on. +% \otherifyactive is called near the end of this file. +\def\otherifyactive{\catcode`+=\other \catcode`\_=\other} + \catcode`\@=0 % \rawbackslashxx output one backslash character in current font @@ -3916,18 +4368,47 @@ Section\xreftie'char\the\appendixno.\the\secno.\the\subsecno.\the\subsubsecno % % \catcode 17=0 % Define control-q \catcode`\\=\active +% Used sometimes to turn off (effectively) the active characters +% even after parsing them. +@def@turnoffactive{@let"=@normaldoublequote +@let\=@realbackslash +@let~=@normaltilde +@let^=@normalcaret +@let_=@normalunderscore +@let|=@normalverticalbar +@let<=@normalless +@let>=@normalgreater +@let+=@normalplus} + +@def@normalturnoffactive{@let"=@normaldoublequote +@let\=@normalbackslash +@let~=@normaltilde +@let^=@normalcaret +@let_=@normalunderscore +@let|=@normalverticalbar +@let<=@normalless +@let>=@normalgreater +@let+=@normalplus} + +% Make _ and + \other characters, temporarily. +% This is canceled by @fixbackslash. +@otherifyactive + % If a .fmt file is being used, we don't want the `\input texinfo' to show up. -% That is what \eatinput is for; after that, the `\' should revert to printing +% That is what \eatinput is for; after that, the `\' should revert to printing % a backslash. % @gdef@eatinput input texinfo{@fixbackslash} @global@let\ = @eatinput % On the other hand, perhaps the file did not have a `\input texinfo'. Then -% the first `\{ in the file would cause an error. This macro tries to fix +% the first `\{ in the file would cause an error. This macro tries to fix % that, assuming it is called before the first `\' could plausibly occur. -% -@gdef@fixbackslash{@ifx\@eatinput @let\ = @normalbackslash @fi} +% Also back turn on active characters that might appear in the input +% file name, in case not using a pre-dumped format. +% +@gdef@fixbackslash{@ifx\@eatinput @let\ = @normalbackslash @fi + @catcode`+=@active @catcode`@_=@active} %% These look ok in all fonts, so just make them not special. The @rm below %% makes sure that the current font starts out as the newly loaded cmr10 diff --git a/lib/termcap/termcap.c b/lib/termcap/termcap.c index 3d6125a..2a270c4 100644 --- a/lib/termcap/termcap.c +++ b/lib/termcap/termcap.c @@ -1,5 +1,5 @@ /* Work-alike for termcap, plus extra features. - Copyright (C) 1985, 1986, 1993 Free Software Foundation, Inc. + Copyright (C) 1985, 86, 93, 94, 95 Free Software Foundation, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -17,13 +17,17 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ /* Emacs config.h may rename various library functions such as malloc. */ #ifdef HAVE_CONFIG_H -#include "config.h" -#else /* not HAVE_CONFIG_H */ -#if defined(HAVE_STRING_H) || defined(STDC_HEADERS) -#define bcopy(s, d, n) memcpy ((d), (s), (n)) +#include + +/* Get the O_* definitions for open et al. */ +#include +#ifdef USG5 +#include #endif +#else /* not HAVE_CONFIG_H */ + #ifdef STDC_HEADERS #include #include @@ -33,6 +37,11 @@ char *malloc (); char *realloc (); #endif +/* Do this after the include, in case string.h prototypes bcopy. */ +#if (defined(HAVE_STRING_H) || defined(STDC_HEADERS)) && !defined(bcopy) +#define bcopy(s, d, n) memcpy ((d), (s), (n)) +#endif + #ifdef HAVE_UNISTD_H #include #endif @@ -46,6 +55,10 @@ char *realloc (); #define NULL (char *) 0 #endif +#ifndef O_RDONLY +#define O_RDONLY 0 +#endif + /* BUFSIZE is the initial size allocated for the buffer for reading the termcap file. It is not a limit. @@ -63,6 +76,10 @@ int bufsize = 128; #endif #endif +#ifndef TERMCAP_FILE +#define TERMCAP_FILE "/etc/termcap" +#endif + #ifndef emacs static void memory_out () @@ -203,7 +220,13 @@ tgetst1 (ptr, area) while ((c = *p++) && c != ':' && c != '\n') { if (c == '^') - c = *p++ & 037; + { + c = *p++; + if (c == '?') + c = 0177; + else + c &= 037; + } else if (c == '\\') { c = *p++; @@ -245,14 +268,14 @@ char PC; /* Actual baud rate if positive; - baud rate / 100 if negative. */ -static short speeds[] = +static int speeds[] = { #ifdef VMS 0, 50, 75, 110, 134, 150, -3, -6, -12, -18, -20, -24, -36, -48, -72, -96, -192 #else /* not VMS */ 0, 50, 75, 110, 135, 150, -2, -3, -6, -12, - -18, -24, -48, -96, -192, -384 + -18, -24, -48, -96, -192, -288, -384, -576, -1152 #endif /* not VMS */ }; @@ -268,6 +291,10 @@ tputs (str, nlines, outfun) #ifdef emacs extern baud_rate; speed = baud_rate; + /* For quite high speeds, convert to the smaller + units to avoid overflow. */ + if (speed > 10000) + speed = - speed / 100; #else if (ospeed == 0) speed = tputs_baud_rate; @@ -296,11 +323,14 @@ tputs (str, nlines, outfun) while (*str) (*outfun) (*str++); - /* padcount is now in units of tenths of msec. */ - padcount *= speeds[ospeed]; + /* PADCOUNT is now in units of tenths of msec. + SPEED is measured in characters per 10 seconds + or in characters per .1 seconds (if negative). + We use the smaller units for larger speeds to avoid overflow. */ + padcount *= speed; padcount += 500; padcount /= 1000; - if (speeds[ospeed] < 0) + if (speed < 0) padcount = -padcount; else { @@ -357,7 +387,16 @@ valid_filename_p (fn) #else /* !VMS */ +#ifdef MSDOS /* MW, May 1993 */ +static int +valid_filename_p (fn) + char *fn; +{ + return *fn == '/' || fn[1] == ':'; +} +#else #define valid_filename_p(fn) (*(fn) == '/') +#endif #endif /* !VMS */ @@ -388,9 +427,36 @@ tgetent (bp, name) char *indirect = NULL; /* Terminal type in :tc= in TERMCAP value. */ int filep; +#ifdef INTERNAL_TERMINAL + /* For the internal terminal we don't want to read any termcap file, + so fake it. */ + if (!strcmp (name, "internal")) + { + term = INTERNAL_TERMINAL; + if (!bp) + { + malloc_size = 1 + strlen (term); + bp = (char *) xmalloc (malloc_size); + } + strcpy (bp, term); + goto ret; + } +#endif /* INTERNAL_TERMINAL */ + + /* For compatibility with programs like `less' that want to + put data in the termcap buffer themselves as a fallback. */ + if (bp) + term_entry = bp; + termcap_name = getenv ("TERMCAP"); if (termcap_name && *termcap_name == '\0') termcap_name = NULL; +#if defined (MSDOS) && !defined (TEST) + if (termcap_name && (*termcap_name == '\\' + || *termcap_name == '/' + || termcap_name[1] == ':')) + dostounix_filename(termcap_name); +#endif filep = termcap_name && valid_filename_p (termcap_name); @@ -419,15 +485,15 @@ tgetent (bp, name) } if (!termcap_name || !filep) -#ifdef VMS - termcap_name = "emacs_library:[etc]termcap.dat"; -#else - termcap_name = "/etc/termcap"; -#endif + termcap_name = TERMCAP_FILE; /* Here we know we must search a file and termcap_name has its name. */ - fd = open (termcap_name, 0, 0); +#ifdef MSDOS + fd = open (termcap_name, O_RDONLY|O_TEXT, 0); +#else + fd = open (termcap_name, O_RDONLY, 0); +#endif if (fd < 0) return -1; @@ -501,8 +567,6 @@ tgetent (bp, name) ret: term_entry = bp; - if (malloc_size) - return (int) bp; return 1; } diff --git a/lib/termcap/termcap.h b/lib/termcap/termcap.h index e9d9361..b19fb0a 100644 --- a/lib/termcap/termcap.h +++ b/lib/termcap/termcap.h @@ -1,5 +1,5 @@ /* Declarations for termcap library. - Copyright (C) 1991, 1992 Free Software Foundation, Inc. + Copyright (C) 1991, 1992, 1995 Free Software Foundation, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -28,7 +28,7 @@ extern char *tgetstr (const char *name, char **area); extern char PC; extern short ospeed; -extern void tputs (const char *string, int nlines, int (*outfun) ()); +extern void tputs (const char *string, int nlines, int (*outfun) (int)); extern char *tparam (const char *ctlstring, char *buffer, int size, ...); diff --git a/lib/termcap/tparam.c b/lib/termcap/tparam.c index 4badb65..2470289 100644 --- a/lib/termcap/tparam.c +++ b/lib/termcap/tparam.c @@ -1,5 +1,5 @@ /* Merge parameters into a termcap entry string. - Copyright (C) 1985, 1987, 1993 Free Software Foundation, Inc. + Copyright (C) 1985, 87, 93, 95 Free Software Foundation, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -17,7 +17,7 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ /* Emacs config.h may rename various library functions such as malloc. */ #ifdef HAVE_CONFIG_H -#include "config.h" +#include #else /* not HAVE_CONFIG_H */ #if defined(HAVE_STRING_H) || defined(STDC_HEADERS) @@ -92,16 +92,13 @@ tparam (string, outstring, len, arg0, arg1, arg2, arg3) int len; int arg0, arg1, arg2, arg3; { -#ifdef NO_ARG_ARRAY int arg[4]; + arg[0] = arg0; arg[1] = arg1; arg[2] = arg2; arg[3] = arg3; return tparam1 (string, outstring, len, NULL, NULL, arg); -#else - return tparam1 (string, outstring, len, NULL, NULL, &arg0); -#endif } char *BC; diff --git a/lib/termcap/version.c b/lib/termcap/version.c index 51336db..f5623a2 100644 --- a/lib/termcap/version.c +++ b/lib/termcap/version.c @@ -1,2 +1,2 @@ /* Make the library identifiable with the RCS ident command. */ -static char *version_string = "\n$Version: GNU termcap 1.2 $\n"; +static char *version_string = "\n$Version: GNU termcap 1.3 $\n"; diff --git a/lib/tilde/Makefile b/lib/tilde/Makefile deleted file mode 100644 index 50b4285..0000000 --- a/lib/tilde/Makefile +++ /dev/null @@ -1,98 +0,0 @@ -## -*- text -*- #################################################### -# # -# Makefile for the GNU Tilde Library. # -# # -#################################################################### - -# This Makefile is hand made from a template file, found in -# ../template. Each library must provide several Makefile -# targets: `all', `clean', `documentation', `install', and -# `what-tar'. The `what-tar' target reports the names of the -# files that need to be included in a tarfile to build the full -# code and documentation for this library. - -# Please note that the values for INCLUDES, CC, AR, RM, CP, -# RANLIB, and selfdir are passed in from ../Makefile, and do -# not need to be defined here. -RM = rm -f -MV = mv -CP = cp - -srcdir = . -VPATH = .:$(srcdir) - -# Here is a rule for making .o files from .c files that doesn't force -# the type of the machine (like -sun3) into the flags. -.c.o: - $(CC) -c $(CFLAGS) $(INCLUDES) $(LOCAL_DEFINES) $(CPPFLAGS) $< - -# LOCAL_DEFINES are flags that are specific to this library. -# Define -DUSG if you are using a System V operating system. -LOCAL_DEFINES = $(LOCAL_INCLUDES) #-DUSG - -# For libraries which include headers from other libraries. -LOCAL_INCLUDES = -I.. - -# The name of the library target. -LIBRARY_NAME = libtilde.a - -# The C code source files for this library. -CSOURCES = $(srcdir)/tilde.c - -# The header files for this library. -HSOURCES = $(srcdir)/tilde.h - -OBJECTS = tilde.o - -# The texinfo files which document this library. -DOCSOURCE = doc/tilde.texi -DOCOBJECT = doc/tilde.dvi -DOCSUPPORT = doc/Makefile -DOCUMENTATION = $(DOCSOURCE) $(DOCOBJECT) $(DOCSUPPORT) - -SUPPORT = Makefile ChangeLog $(DOCSUPPORT) - -SOURCES = $(CSOURCES) $(HSOURCES) $(DOCSOURCE) - -THINGS_TO_TAR = $(SOURCES) $(SUPPORT) - -###################################################################### - -all: $(LIBRARY_NAME) - -$(LIBRARY_NAME): $(OBJECTS) - $(RM) $@ - $(AR) cq $@ $(OBJECTS) - -[ -n "$(RANLIB)" ] && $(RANLIB) $@ - -what-tar: - @for file in $(THINGS_TO_TAR); do \ - echo $(selfdir)$$file; \ - done - -documentation: force - -(cd doc; $(MAKE) $(MFLAGS)) -force: - -# The rule for 'includes' is written funny so that the if statement -# always returns TRUE unless there really was an error installing the -# include files. -install: - -$(MV) $(bindir)/$(LIBRARY_NAME) $(bindir)/$(LIBRARY_NAME)-old - $(CP) $(LIBRARY_NAME) $(bindir)/$(LIBRARY_NAME) - -[ -n "$(RANLIB)" ] && $(RANLIB) -t $(bindir)/$(LIBRARY_NAME) - -clean: - $(RM) $(OBJECTS) $(LIBRARY_NAME) - -(cd doc && $(MAKE) $(MFLAGS) $@) - -maintainer-clean realclean mostlyclean distclean: clean - - -###################################################################### -# # -# Dependencies for the object files which make up this library. # -# # -###################################################################### - -tilde.o: tilde.h tilde.c diff --git a/lib/tilde/Makefile.in b/lib/tilde/Makefile.in new file mode 100644 index 0000000..acecee3 --- /dev/null +++ b/lib/tilde/Makefile.in @@ -0,0 +1,98 @@ +## -*- text -*- #################################################### +# # +# Makefile for the GNU Tilde Library. # +# # +#################################################################### + +srcdir = @srcdir@ +VPATH = .:@srcdir@ +topdir = @top_srcdir@ +BUILD_DIR = @BUILD_DIR@ + +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_DATA = @INSTALL_DATA@ + +CC = @CC@ +RANLIB = @RANLIB@ +AR = @AR@ +RM = rm +CP = cp +MV = mv + +CFLAGS = @CFLAGS@ @LOCAL_CFLAGS@ +CPPFLAGS = @CPPFLAGS@ +LDFLAGS = @LDFLAGS@ @LOCAL_LDFLAGS@ + +DEFS = @DEFS@ + +INCLUDES = -I. -I../.. -I$(topdir) -I$(topdir)/lib + +CCFLAGS = $(CFLAGS) $(DEFS) $(CPPFLAGS) ${INCLUDES} + +.c.o: + $(CC) -c $(CCFLAGS) $< + +# The name of the library target. +LIBRARY_NAME = libtilde.a + +# The C code source files for this library. +CSOURCES = $(srcdir)/tilde.c + +# The header files for this library. +HSOURCES = $(srcdir)/tilde.h + +OBJECTS = tilde.o + +# The texinfo files which document this library. +DOCSOURCE = doc/tilde.texi +DOCOBJECT = doc/tilde.dvi +DOCSUPPORT = doc/Makefile +DOCUMENTATION = $(DOCSOURCE) $(DOCOBJECT) $(DOCSUPPORT) + +SUPPORT = Makefile ChangeLog $(DOCSUPPORT) + +SOURCES = $(CSOURCES) $(HSOURCES) $(DOCSOURCE) + +THINGS_TO_TAR = $(SOURCES) $(SUPPORT) + +###################################################################### + +all: $(LIBRARY_NAME) + +$(LIBRARY_NAME): $(OBJECTS) + $(RM) -f $@ + $(AR) cr $@ $(OBJECTS) + -test -n "$(RANLIB)" && $(RANLIB) $@ + +documentation: force + -(cd doc; $(MAKE) $(MFLAGS)) + +force: + +# The rule for 'includes' is written funny so that the if statement +# always returns TRUE unless there really was an error installing the +# include files. +install: + $(INSTALL_DATA) -c -m 644 $(LIBRARY_NAME) $(bindir)/$(LIBRARY_NAME) + -test -n "$(RANLIB)" && $(RANLIB) -t $(bindir)/$(LIBRARY_NAME) + +clean: + $(RM) -f $(OBJECTS) $(LIBRARY_NAME) + -( cd doc && $(MAKE) $(MFLAGS) $@ ) + +realclean distclean maintainer-clean: clean + -( cd doc && $(MAKE) $(MFLAGS) $@ ) + $(RM) -f Makefile + +mostlyclean: clean + -( cd doc && $(MAKE) $(MFLAGS) $@ ) + +###################################################################### +# # +# Dependencies for the object files which make up this library. # +# # +###################################################################### + +tilde.o: tilde.h tilde.c +tilde.o: $(BUILD_DIR)/config.h diff --git a/lib/tilde/doc/Makefile b/lib/tilde/doc/Makefile index 4e158bf..a2246db 100644 --- a/lib/tilde/doc/Makefile +++ b/lib/tilde/doc/Makefile @@ -1,5 +1,5 @@ +clean distclean mostlyclean maintainer-clean: + rm -f tilde.?? + all: cp tilde.texi tilde.info - -clean realclean maintainer-clean: - rm -f tilde.?? tilde.info diff --git a/lib/tilde/memalloc.h b/lib/tilde/memalloc.h deleted file mode 100644 index 750d53d..0000000 --- a/lib/tilde/memalloc.h +++ /dev/null @@ -1,56 +0,0 @@ -/* memalloc.h -- consolidate code for including alloca.h or malloc.h and - defining alloca. */ - -/* Copyright (C) 1993 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, 675 Mass Ave, Cambridge, MA 02139, USA. */ - -#if !defined (__MEMALLOC_H__) -# define __MEMALLOC_H__ - -#if defined (sparc) && defined (sun) && !defined (HAVE_ALLOCA_H) -# define HAVE_ALLOCA_H -#endif - -#if defined (__GNUC__) && !defined (HAVE_ALLOCA) -# define HAVE_ALLOCA -#endif - -#if defined (HAVE_ALLOCA_H) && !defined (HAVE_ALLOCA) -# define HAVE_ALLOCA -#endif /* HAVE_ALLOCA_H && !HAVE_ALLOCA */ - -#if !defined (BUILDING_MAKEFILE) - -#if defined (__GNUC__) -# undef alloca -# define alloca __builtin_alloca -#else /* !__GNUC__ */ -# if defined (HAVE_ALLOCA_H) -# if defined (IBMESA) -# include -# else /* !IBMESA */ -# include -# endif /* !IBMESA */ -# else -extern char *alloca (); -# endif /* !HAVE_ALLOCA_H */ -#endif /* !__GNUC__ */ - -#endif /* !BUILDING_MAKEFILE */ - -#endif /* __MEMALLOC_H__ */ diff --git a/lib/tilde/tilde.c b/lib/tilde/tilde.c index da75d95..69f5768 100644 --- a/lib/tilde/tilde.c +++ b/lib/tilde/tilde.c @@ -19,6 +19,10 @@ along with Readline; see the file COPYING. If not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ +#if defined (HAVE_CONFIG_H) +# include +#endif + #if defined (HAVE_STRING_H) # include #else /* !HAVE_STRING_H */ @@ -31,13 +35,14 @@ # include "ansi_stdlib.h" #endif /* HAVE_STDLIB_H */ -#include "tilde.h" #include #include -#if defined (USG) && !defined (HAVE_GETPW_DECLS) +#include "tilde.h" + +#if !defined (HAVE_GETPW_DECLS) extern struct passwd *getpwuid (), *getpwnam (); -#endif /* USG && !defined (HAVE_GETPW_DECLS) */ +#endif /* !HAVE_GETPW_DECLS */ #if !defined (savestring) extern char *xmalloc (); @@ -171,7 +176,7 @@ tilde_expand (string) /* Copy the skipped text into the result. */ if ((result_index + start + 1) > result_size) - result = (char *)xrealloc (result, 1 + (result_size += (start + 20))); + result = xrealloc (result, 1 + (result_size += (start + 20))); strncpy (result + result_index, string, start); result_index += start; @@ -188,7 +193,7 @@ tilde_expand (string) break; /* Expand the entire tilde word, and copy it into RESULT. */ - tilde_word = (char *)xmalloc (1 + end); + tilde_word = xmalloc (1 + end); strncpy (tilde_word, string, end); tilde_word[end] = '\0'; string += end; @@ -198,7 +203,7 @@ tilde_expand (string) len = strlen (expansion); if ((result_index + len + 1) > result_size) - result = (char *)xrealloc (result, 1 + (result_size += (len + 20))); + result = xrealloc (result, 1 + (result_size += (len + 20))); strcpy (result + result_index, expansion); result_index += len; @@ -217,85 +222,90 @@ tilde_expand_word (filename) char *filename; { char *dirname; + char *temp_name; - dirname = filename ? savestring (filename) : (char *)NULL; + if (filename == (char *)0) + return ((char *)NULL); - if (dirname && *dirname == '~') + dirname = savestring (filename); + + if (*dirname != '~') + return (dirname); + + if (!dirname[1] || dirname[1] == '/') { - char *temp_name; - if (!dirname[1] || dirname[1] == '/') + /* Prepend $HOME to the rest of the string. */ + char *temp_home = (char *)getenv ("HOME"); + int home_len; + + /* If there is no HOME variable, look up the directory in + the password database. */ + if (!temp_home) { - /* Prepend $HOME to the rest of the string. */ - char *temp_home = (char *)getenv ("HOME"); + struct passwd *entry; - /* If there is no HOME variable, look up the directory in - the password database. */ - if (!temp_home) - { - struct passwd *entry; + entry = getpwuid (getuid ()); + if (entry) + temp_home = entry->pw_dir; + } - entry = getpwuid (getuid ()); - if (entry) - temp_home = entry->pw_dir; - } + home_len = temp_home ? strlen (temp_home) : 0; + temp_name = xmalloc (1 + strlen (dirname + 1) + home_len); + + if (temp_home) + strcpy (temp_name, temp_home); + strcpy (temp_name + home_len, dirname + 1); + free (dirname); + dirname = temp_name; + } + else + { + char *username; + struct passwd *user_entry; + int i, len; - temp_name = xmalloc (1 + strlen (&dirname[1]) - + (temp_home ? strlen (temp_home) : 0)); - temp_name[0] = '\0'; - if (temp_home) - strcpy (temp_name, temp_home); - strcat (temp_name, dirname + 1); - free (dirname); - dirname = temp_name; - } - else + username = xmalloc (strlen (dirname)); + for (i = 1; dirname[i] && dirname[i] != '/'; i++) + username[i - 1] = dirname[i]; + username[i - 1] = '\0'; + + if ((user_entry = getpwnam (username)) == (struct passwd *)0) { - char *username; - struct passwd *user_entry; - int i; + /* If the calling program has a special syntax for + expanding tildes, and we couldn't find a standard + expansion, then let them try. */ + if (tilde_expansion_failure_hook) + { + char *expansion; - username = xmalloc (strlen (dirname)); - for (i = 1; dirname[i] && dirname[i] != '/'; i++) - username[i - 1] = dirname[i]; - username[i - 1] = '\0'; + expansion = (*tilde_expansion_failure_hook) (username); - if ((user_entry = getpwnam (username)) == 0) - { - /* If the calling program has a special syntax for - expanding tildes, and we couldn't find a standard - expansion, then let them try. */ - if (tilde_expansion_failure_hook) + if (expansion) { - char *expansion; - - expansion = (*tilde_expansion_failure_hook) (username); - - if (expansion) - { - temp_name = xmalloc (1 + strlen (expansion) - + strlen (&dirname[i])); - strcpy (temp_name, expansion); - strcat (temp_name, &dirname[i]); - free (expansion); - free (dirname); - dirname = temp_name; - } + len = strlen (expansion); + temp_name = xmalloc (1 + len + strlen (dirname + i)); + strcpy (temp_name, expansion); + strcpy (temp_name + len, dirname + i); + free (expansion); + free (dirname); + dirname = temp_name; } - /* We shouldn't report errors. */ - } - else - { - temp_name = xmalloc (1 + strlen (user_entry->pw_dir) - + strlen (&dirname[i])); - strcpy (temp_name, user_entry->pw_dir); - strcat (temp_name, &dirname[i]); - free (dirname); - dirname = temp_name; } - endpwent (); - free (username); + /* We shouldn't report errors. */ } + else + { + len = strlen (user_entry->pw_dir); + temp_name = xmalloc (1 + len + strlen (dirname + i)); + strcpy (temp_name, user_entry->pw_dir); + strcpy (temp_name + len, dirname + i); + free (dirname); + dirname = temp_name; + } + endpwent (); + free (username); } + return (dirname); } @@ -368,7 +378,7 @@ xrealloc (pointer, bytes) static void memory_error_and_abort () { - fprintf (stderr, "readline: Out of virtual memory!\n"); + fprintf (stderr, "readline: out of virtual memory\n"); abort (); } diff --git a/lib/tilde/tilde.h b/lib/tilde/tilde.h index 726d081..6f0898c 100644 --- a/lib/tilde/tilde.h +++ b/lib/tilde/tilde.h @@ -1,11 +1,32 @@ /* tilde.h: Externally available variables and function in libtilde.a. */ -#if !defined (__TILDE_H__) -# define __TILDE_H__ +/* Copyright (C) 1992 Free Software Foundation, Inc. + + This file contains the Readline Library (the Library), a set of + routines for providing Emacs style line input to programs that ask + for it. + + The 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 1, or (at your option) + any later version. + + The 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, + 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#if !defined (_TILDE_H_) +# define _TILDE_H_ /* Function pointers can be declared as (Function *)foo. */ -#if !defined (__FUNCTION_DEF) -# define __FUNCTION_DEF +#if !defined (_FUNCTION_DEF) +# define _FUNCTION_DEF typedef int Function (); typedef void VFunction (); typedef char *CPFunction (); @@ -35,4 +56,4 @@ extern char *tilde_expand (); tilde. If there is no expansion, call tilde_expansion_failure_hook. */ extern char *tilde_expand_word (); -#endif /* __TILDE_H__ */ +#endif /* _TILDE_H_ */ diff --git a/list.c b/list.c new file mode 100644 index 0000000..d70a67b --- /dev/null +++ b/list.c @@ -0,0 +1,128 @@ +/* list.c - Functions for manipulating linked lists of objects. */ + +/* Copyright (C) 1996 + 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, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "config.h" + +#if defined (HAVE_UNISTD_H) +# include +#endif + +#include "shell.h" + +/* A global variable which acts as a sentinel for an `error' list return. */ +GENERIC_LIST global_error_list; + +/* Call FUNCTION on every member of LIST, a generic list. */ +void +map_over_list (list, function) + GENERIC_LIST *list; + Function *function; +{ + for ( ; list; list = list->next) + (*function) (list); +} + +/* Call FUNCTION on every string in WORDS. */ +void +map_over_words (words, function) + WORD_LIST *words; + Function *function; +{ + for ( ; words; words = words->next) + (*function) (words->word->word); +} + +/* Reverse the chain of structures in LIST. Output the new head + of the chain. You should always assign the output value of this + function to something, or you will lose the chain. */ +GENERIC_LIST * +reverse_list (list) + GENERIC_LIST *list; +{ + register GENERIC_LIST *next, *prev; + + for (prev = (GENERIC_LIST *)NULL; list; ) + { + next = list->next; + list->next = prev; + prev = list; + list = next; + } + return (prev); +} + +/* Return the number of elements in LIST, a generic list. */ +int +list_length (list) + GENERIC_LIST *list; +{ + register int i; + + for (i = 0; list; list = list->next, i++); + return (i); +} + +/* Append TAIL to HEAD. Return the header of the list. */ +GENERIC_LIST * +list_append (head, tail) + GENERIC_LIST *head, *tail; +{ + register GENERIC_LIST *t_head; + + if (head == 0) + return (tail); + + for (t_head = head; t_head->next; t_head = t_head->next) + ; + t_head->next = tail; + return (head); +} + +/* Delete the element of LIST which satisfies the predicate function COMPARER. + Returns the element that was deleted, so you can dispose of it, or -1 if + the element wasn't found. COMPARER is called with the list element and + then ARG. Note that LIST contains the address of a variable which points + to the list. You might call this function like this: + + SHELL_VAR *elt = delete_element (&variable_list, check_var_has_name, "foo"); + dispose_variable (elt); +*/ +GENERIC_LIST * +delete_element (list, comparer, arg) + GENERIC_LIST **list; + Function *comparer; + char *arg; +{ + register GENERIC_LIST *prev, *temp; + + for (prev = (GENERIC_LIST *)NULL, temp = *list; temp; prev = temp, temp = temp->next) + { + if ((*comparer) (temp, arg)) + { + if (prev) + prev->next = temp->next; + else + *list = temp->next; + return (temp); + } + } + return ((GENERIC_LIST *)&global_error_list); +} diff --git a/locale.c b/locale.c new file mode 100644 index 0000000..7653f1f --- /dev/null +++ b/locale.c @@ -0,0 +1,249 @@ +/* locale.c - Miscellaneous internationalization functions. */ + +/* Copyright (C) 1996 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, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "config.h" + +#include "bashtypes.h" + +#if defined (HAVE_UNISTD_H) +# include +#endif + +#include "bashintl.h" +#include "bashansi.h" +#include +#include + +#include "shell.h" + +/* The current locale when the program begins */ +static char *default_locale; + +/* The current domain for textdomain(3). */ +static char *default_domain; +static char *default_dir; + +/* tracks the value of LC_ALL; used to override values for other locale + categories */ +static char *lc_all; + +/* Set the value of default_locale and make the current locale the + system default locale. This should be called very early in main(). */ +void +set_default_locale () +{ +#if defined (HAVE_SETLOCALE) + default_locale = setlocale (LC_ALL, ""); + if (default_locale) + default_locale = savestring (default_locale); +#endif /* HAVE_SETLOCALE */ +} + +/* Set default values for LC_CTYPE, LC_COLLATE, and LC_MESSAGES if they + are not specified in the environment, but LANG or LC_ALL is. This + should be called from main() after parsing the environment. */ +void +set_default_locale_vars () +{ + char *val; + +#if defined (HAVE_SETLOCALE) + val = get_string_value ("LC_CTYPE"); + if (val == 0 && lc_all && *lc_all) + setlocale (LC_CTYPE, lc_all); + +# if defined (LC_COLLATE) + val = get_string_value ("LC_COLLATE"); + if (val == 0 && lc_all && *lc_all) + setlocale (LC_COLLATE, lc_all); +# endif /* LC_COLLATE */ + +# if defined (LC_MESSAGES) + val = get_string_value ("LC_MESSAGES"); + if (val == 0 && lc_all && *lc_all) + setlocale (LC_MESSAGES, lc_all); +# endif /* LC_MESSAGES */ + +#endif /* HAVE_SETLOCALE */ + + val = get_string_value ("TEXTDOMAIN"); + if (val && *val) + { + FREE (default_domain); + default_domain = savestring (val); + textdomain (default_domain); + } + + val = get_string_value ("TEXTDOMAINDIR"); + if (val && *val) + { + FREE (default_dir); + default_dir = savestring (val); + bindtextdomain (default_domain, default_dir); + } +} + +/* Set one of the locale categories (specified by VAR) to VALUE. Returns 1 + if successful, 0 otherwise. */ +int +set_locale_var (var, value) + char *var, *value; +{ + if (var[0] == 'T' && var[10] == 0) /* TEXTDOMAIN */ + { + FREE (default_domain); + default_domain = value ? savestring (value) : (char *)NULL; + textdomain (default_domain); + return (1); + } + else if (var[0] == 'T') /* TEXTDOMAINDIR */ + { + FREE (default_dir); + default_dir = value ? savestring (value) : (char *)NULL; + bindtextdomain (default_domain, default_dir); + return (1); + } + + /* var[0] == 'L' && var[1] == 'C' && var[2] == '_' */ + + else if (var[3] == 'A') /* LC_ALL */ + { + FREE (lc_all); + lc_all = value ? savestring (value) : savestring (default_locale); +#if defined (HAVE_SETLOCALE) + return (setlocale (LC_ALL, value) != 0); +#else + return (1); +#endif + } + +#if defined (HAVE_SETLOCALE) + else if (var[3] == 'C' && var[4] == 'T') /* LC_CTYPE */ + { + if (lc_all == 0 || *lc_all == '\0') + return (setlocale (LC_CTYPE, value) != 0); + } + else if (var[3] == 'C' && var[4] == 'O') /* LC_COLLATE */ + { +# if defined (LC_COLLATE) + if (lc_all == 0 || *lc_all == '\0') + return (setlocale (LC_COLLATE, value) != 0); +# endif /* LC_COLLATE */ + } + else if (var[3] == 'M' && var[4] == 'E') /* LC_MESSAGES */ + { +# if defined (LC_MESSAGES) + if (lc_all == 0 || *lc_all == '\0') + return (setlocale (LC_MESSAGES, value) != 0); +# endif /* LC_MESSAGES */ + } +#endif /* HAVE_SETLOCALE */ + + return (0); +} + +/* Called when LANG is assigned a value. Sets LC_ALL if that has not + already been set. */ +int +set_lang (var, value) + char *var, *value; +{ + return ((lc_all == 0) ? set_locale_var ("LC_ALL", value) : 0); +} + +/* Get the value of one of the locale variables (LC_MESSAGES, LC_CTYPE) */ +char * +get_locale_var (var) + char *var; +{ + char *locale; + + locale = lc_all; + + if (locale == 0) + locale = get_string_value (var); + if (locale == 0) + locale = default_locale; + + return (locale); +} + +/* Translate the contents of STRING, a $"..." quoted string, according + to the current locale. In the `C' or `POSIX' locale, or if gettext() + is not available, the passed string is returned unchanged. The + length of the translated string is returned in LENP, if non-null. */ +char * +localetrans (string, len, lenp) + char *string; + int len, *lenp; +{ + char *locale, *t; +#if defined (HAVE_GETTEXT) + char *translated; + int tlen; +#endif + + /* Don't try to translate null strings. */ + if (string == 0 || *string == 0) + { + if (lenp) + *lenp = 0; + return ((char *)NULL); + } + + t = xmalloc (len + 1); + + locale = get_locale_var ("LC_MESSAGES"); + + /* If we don't have setlocale() or the current locale is `C' or `POSIX', + just return the string. If we don't have gettext(), there's no use + doing anything else. */ +#if defined (HAVE_GETTEXT) + if (locale == 0 || locale[0] == '\0' || + (locale[0] == 'C' && locale[1] == '\0') || STREQ (locale, "POSIX")) +#endif + { + strcpy (t, string); + if (lenp) + *lenp = len; + return (t); + } + +#if defined (HAVE_GETTEXT) + /* Now try to translate it. */ + translated = gettext (string); + if (translated == string) /* gettext returns its argument if untranslatable */ + { + strcpy (t, string); + if (lenp) + *lenp = len; + } + else + { + free (t); + tlen = strlen (translated); + t = xmalloc (tlen + 1); + strcpy (t, translated); + if (lenp) + *lenp = tlen; + } + return (t); +#endif /* HAVE_GETTEXT */ +} diff --git a/machines.h b/machines.h deleted file mode 100644 index 7fe1ff9..0000000 --- a/machines.h +++ /dev/null @@ -1,2392 +0,0 @@ -/* machines.h -- - Included file in the makefile that gets run through Cpp. This file - tells which machines have what features based on the unique machine - identifier present in Cpp. */ - -/* Copyright (C) 1993 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, 675 Mass Ave, Cambridge, MA 02139, USA. */ - -/* **************************************************************** */ -/* */ -/* Global Assumptions (true for most systems). */ -/* */ -/* **************************************************************** */ - -/* We make some global assumptions here. This can be #undef'ed in - various machine specific entries. */ - -/* If this file is being processed with Gcc, then the user has Gcc. */ -#if defined (__GNUC__) && !defined (NeXT) && !defined (__FreeBSD__) -# if !defined (HAVE_GCC) -# define HAVE_GCC -# endif /* HAVE_GCC */ -#endif /* __GNUC__ && !NeXT && !__FreeBSD__ */ - -/* Assume that all machines have the getwd () system call. We unset it - for USG systems. */ -#define HAVE_GETWD - -/* Assume that all systems have a working getcwd () call. We unset it for - ISC systems. */ -#define HAVE_GETCWD - -/* Most (but not all) systems have a good, working version of dup2 (). - For systems that don't have the call (HP/UX), and for systems - that don't set the open-on-exec flag for the dup'ed file descriptors, - (Sequents running Dynix, Ultrix), #undef HAVE_DUP2 in the machine - description. */ -#define HAVE_DUP2 - -/* Every machine that has Gcc has alloca as a builtin in Gcc. If you are - compiling Bash without Gcc, then you must have alloca in a library, - in your C compiler, or be able to assemble or compile the alloca source - that we ship with Bash. */ -#define HAVE_ALLOCA - -/* We like most machines to use the GNU Malloc routines supplied in the - source code because they provide high quality error checking. On - some machines, our malloc () cannot be used (because of library - conflicts, for example), and for those, you should specifically - #undef USE_GNU_MALLOC in the machine description. */ -#define USE_GNU_MALLOC - -/* This causes the Gnu malloc library (from glibc) to be used. */ -/* #define USE_GNU_MALLOC_LIBRARY */ - -/* Assume that every operating system supplies strchr () and strrchr () - in a standard library until proven otherwise. */ -#define HAVE_STRCHR - -/* Hardware-dependent CFLAGS. */ -#define MACHINE_CFLAGS - -/* **************************************************************** */ -/* */ -/* Sun Microsystems Machines */ -/* */ -/* **************************************************************** */ - -/* NetBSD running on a sparc. */ -#if defined (sparc) && defined (__NetBSD__) -# define M_MACHINE "sun4" -# define M_OS "NetBSD" -# define SYSDEP_CFLAGS -DOPENDIR_NOT_ROBUST -DINT_GROUPS_ARRAY \ - -DRLIMTYPE=quad_t -# define SYSDEP_LDFLAGS -static -# define HAVE_SYS_SIGLIST -# define HAVE_SETLINEBUF -# define HAVE_GETGROUPS -# define HAVE_VFPRINTF -# define HAVE_STRERROR -# define VOID_SIGHANDLER -# define HAVE_DIRENT -# define HAVE_STRCASECMP -# undef USE_GNU_MALLOC -#endif /* sparc && __NetBSD__ */ - -/* BSDI BSD/OS running on a sparc. */ -#if defined (sparc) && defined (__bsdi__) -# define M_MACHINE "sun4" -# define M_OS "BSD_OS" -# define SYSDEP_CFLAGS -DOPENDIR_NOT_ROBUST -DRLIMTYPE=quad_t -# define HAVE_SYS_SIGLIST -# define HAVE_SETLINEBUF -# define HAVE_GETGROUPS -# define HAVE_VFPRINTF -# define HAVE_STRERROR -# define VOID_SIGHANDLER -# define HAVE_DIRENT -# define HAVE_STRCASECMP -#endif /* sparc && __bsdi__ */ - -#if defined (sun) && !defined (M_MACHINE) -/* We aren't currently using GNU Malloc on Suns because of a bug in Sun's - YP which bites us when Sun free ()'s an already free ()'ed address. - When Sun fixes their YP, we can start using our winning malloc again. */ -#undef USE_GNU_MALLOC - -/* Most Sun systems have signal handler functions that are void. */ -# define VOID_SIGHANDLER - -/* Most Sun systems have the following. */ -# define HAVE_SYS_SIGLIST -# define HAVE_SETLINEBUF -# define HAVE_VFPRINTF -# define HAVE_GETGROUPS - -/* Check for SunOS4 or greater. */ -# if defined (SunOS5) -# define M_OS "SunOS5" -# define SYSDEP_CFLAGS -DUSGr4 -DUSG -DSolaris -DOPENDIR_NOT_ROBUST \ - -DNO_SBRK_DECL -DINT_GROUPS_ARRAY -# define EXTRA_LIB_SEARCH_PATH /usr/ccs/lib -# if !defined (HAVE_GCC) -# define REQUIRED_LIBRARIES -ldl -# define SYSDEP_LDFLAGS -Bdynamic -# endif /* !HAVE_GCC */ -# define HAVE_STRERROR -# undef HAVE_GETWD -# undef HAVE_SETLINEBUF -# endif /* SunOS5 */ - -# if defined (SunOS4) -# define M_OS "SunOS4" -# define SYSDEP_CFLAGS -DBSD_GETPGRP -DOPENDIR_NOT_ROBUST -DTERMIOS_LDISC \ - -DINT_GROUPS_ARRAY -# define HAVE_DIRENT -# endif /* SunOS4 */ - -# if !defined (SunOS4) && !defined (SunOS5) -# define M_OS "SunOS3" -# if !defined (sparc) && !defined (__sparc__) -# undef VOID_SIGHANDLER -# endif /* !sparc */ -# endif /* !SunOS4 && !SunOS5 */ - -# if defined (mc68010) -# define sun2 -# define M_MACHINE "sun2" -# endif -# if defined (mc68020) -# define sun3 -# define M_MACHINE "sun3" -# endif -# if defined (sparc) || defined (__sparc__) -# define sun4 -# define M_MACHINE "sparc" -# endif -# if defined (i386) -# define done386 -# if !defined (SunOS5) -# define Sun386i -# define M_MACHINE "Sun386i" -# else -# define M_MACHINE "i386" -# endif -# endif /* i386 */ - -#endif /* sun && !M_MACHINE */ - -/* **************************************************************** */ -/* */ -/* DEC Machines (vax, decstations) */ -/* */ -/* **************************************************************** */ - -/* ************************ */ -/* */ -/* Alpha with OSF/1 */ -/* */ -/* ************************ */ -#if defined (__alpha) || defined (alpha) -# define M_MACHINE "alpha" -# define M_OS "OSF1" -# define HAVE_SYS_SIGLIST -# define HAVE_SETLINEBUF -# define HAVE_VFPRINTF -# define HAVE_STRERROR -# define HAVE_GETGROUPS -# define VOID_SIGHANDLER -# define USE_TERMCAP_EMULATION -# if !defined (__GNUC__) -# define SYSDEP_CFLAGS -DNLS -D_BSD -# endif /* !__GNUC__ */ -# undef HAVE_ALLOCA -# undef USE_GNU_MALLOC -#endif /* __alpha || alpha */ - -/* ************************ */ -/* */ -/* NetBSD/pmax (DEC mips) */ -/* */ -/* ************************ */ -#if defined(mips) && defined(__NetBSD__) -# define M_MACHINE "mips" -# define M_OS "NetBSD" -# define SYSDEP_CFLAGS -DOPENDIR_NOT_ROBUST -DINT_GROUPS_ARRAY \ - -DRLIMTYPE=quad_t -# define HAVE_SYS_SIGLIST -# define HAVE_SETLINEBUF -# define HAVE_GETGROUPS -# define HAVE_VFPRINTF -# define HAVE_STRERROR -# define VOID_SIGHANDLER -# define HAVE_DIRENT -# define HAVE_STRCASECMP -#endif /* mips && __NetBSD__ */ - -/* ************************ */ -/* */ -/* Ultrix */ -/* */ -/* ************************ */ -#if defined (ultrix) -# if defined (MIPSEL) -# undef HAVE_ALLOCA_H -# define M_MACHINE "MIPSEL" -# else /* !MIPSEL */ -# define M_MACHINE "vax" -# endif /* !MIPSEL */ -# define SYSDEP_CFLAGS -DBSD_GETPGRP -DTERMIOS_MISSING -DTERMIOS_LDISC \ - -DINT_GROUPS_ARRAY -# define M_OS "Ultrix" -# define HAVE_DIRENT -# define VOID_SIGHANDLER -# define HAVE_SYS_SIGLIST -# define HAVE_SETLINEBUF -# define HAVE_VFPRINTF -# define HAVE_GETGROUPS -# undef HAVE_DUP2 -#endif /* ultrix */ - -/* ************************ */ -/* */ -/* VAX 4.3 BSD */ -/* */ -/* ************************ */ -#if defined (vax) && !defined (ultrix) -# define M_MACHINE "vax" -# define M_OS "Bsd" -# define HAVE_SETLINEBUF -# define HAVE_SYS_SIGLIST -# define HAVE_GETGROUPS -# define USE_VFPRINTF_EMULATION -#endif /* vax && !ultrix */ - -/* ************************ */ -/* */ -/* Tahoe 4.3 BSD */ -/* */ -/* ************************ */ -#if defined (tahoe) -# define M_MACHINE "tahoe" -# define M_OS "Bsd" -# define HAVE_SETLINEBUF -# define HAVE_SYS_SIGLIST -# define HAVE_GETGROUPS -# define HAVE_VFPRINTF -#endif /* tahoe */ - -/* **************************************************************** */ -/* */ -/* Machines with MIPSco processors */ -/* */ -/* **************************************************************** */ - -/* **************************************** */ -/* */ -/* SGI Iris/IRIX */ -/* */ -/* **************************************** */ -#if defined (sgi) -# if defined (Irix3) -# define M_OS "Irix3" -# if !defined (HAVE_GCC) -# undef MACHINE_CFLAGS -# define MACHINE_CFLAGS -real_frameptr -Wf,-XNl3072 -# endif -# undef HAVE_ALLOCA -# endif /* Irix3 */ -# if defined (Irix4) -# define M_OS "Irix4" -# if !defined (HAVE_GCC) -# undef MACHINE_CFLAGS -# define MACHINE_CFLAGS -Wf,-XNl3072 -# endif -# endif /* Irix4 */ -# if defined (Irix5) -# define M_OS "Irix5" -# if !defined (HAVE_GCC) -# undef MACHINE_CFLAGS -# define MACHINE_CFLAGS -Wf,-XNl3072 -# endif -# endif /* Irix5 */ -# if defined (Irix6) -# define M_OS "Irix6" -# if !defined (HAVE_GCC) -# undef MACHINE_CFLAGS -# define MACHINE_CFLAGS -mips2 -# endif /* !HAVE_GCC */ -# endif /* Irix6 */ -# define M_MACHINE "sgi" -# define HAVE_GETGROUPS -# define VOID_SIGHANDLER -# define HAVE_SYS_SIGLIST -# define HAVE_SETLINEBUF -# define HAVE_VFPRINTF -# define REQUIRED_LIBRARIES -lsun - /* SGI cc uses ansi c features *without* defining __STDC__ */ -# if defined (__EXTENSIONS__) && !defined (__STDC__) -# define ANSIC -D__STDC__ -# else -# define ANSIC -# endif /* !__EXTENSIONS__ || __STDC__ */ -# if defined (Irix5) || defined (Irix6) -# define SGI_CFLAGS -DUSG -DPGRP_PIPE -DHAVE_BCOPY -DHAVE_GETPW_DECLS \ - -DHAVE_SOCKETS -DNO_SBRK_DECL -# else -# define SGI_CFLAGS -DUSG -DPGRP_PIPE -DHAVE_BCOPY -DHAVE_GETPW_DECLS \ - -DHAVE_SOCKETS -# endif /* !Irix5 */ -# define SYSDEP_CFLAGS SGI_CFLAGS MACHINE_CFLAGS ANSIC -# define SYSDEP_LDFLAGS MACHINE_CFLAGS -#endif /* sgi */ - -/* ************************ */ -/* */ -/* NEC EWS 4800 */ -/* */ -/* ************************ */ -#if defined (nec_ews) -# if defined (SYSTYPE_SYSV) || defined (USGr4) -# define M_MACHINE "ews4800" -# define M_OS "USG" -# define HAVE_VFPRINTF -# define VOID_SIGHANDLER -# define HAVE_STRERROR -# define HAVE_DUP2 -# undef HAVE_GETWD -# undef HAVE_RESOURCE /* ? */ - /* Alloca requires either Gcc or cc with -lucb. */ -# if !defined (HAVE_GCC) -# define EXTRA_LIB_SEARCH_PATH /usr/ucblib -# define REQUIRED_LIBRARIES -lc -lucb -# endif /* !HAVE_GCC */ -# if defined (MIPSEB) -# if !defined (HAVE_GCC) -# undef MACHINE_CFLAGS -# define MACHINE_CFLAGS -Wf,-XNl3072 -# endif -# define SYSDEP_CFLAGS MACHINE_CFLAGS -DUSGr4 -DUSGr3 -D_POSIX_JOB_CONTROL -# else /* !MIPSEB */ -# define SYSDEP_CFLAGS -DUSGr4 -# endif /* MIPSEB */ -# else /* !SYSTYPE_SYSV && !USGr4 */ -# define M_OS "Bsd" -# endif /* !SYSTYPE_SYSV && !USGr4 */ -# define HAVE_SYS_SIGLIST -# define HAVE_SETLINEBUF -# define HAVE_GETGROUPS -#endif /* nec_ews */ - -/* ************************ */ -/* */ -/* Generic MIPS SVR4, 4.2 */ -/* */ -/* ************************ */ -#if defined (MIPSEB) && defined (USGr4) -# define M_MACHINE "MIPSEB" -# define M_OS "USG" -# if defined (sony) && !defined (HAVE_GCC) -# undef MACHINE_CFLAGS -# define MACHINE_CFLAGS -Wf,-XNl3072 -# endif -/* XXX - os/svr4.h -- for the future -- XXX */ -# undef HAVE_GETWD -# define HAVE_DIRENT -# define HAVE_STRERROR -# define HAVE_VFPRINTF -# define VOID_SIGHANDLER -# define HAVE_SYS_SIGLIST -# define HAVE_SETLINEBUF -# define HAVE_GETGROUPS -/* alloca */ -# if !defined (HAVE_GCC) -# define EXTRA_LIB_SEARCH_PATH /usr/ucblib -# define REQUIRED_LIBRARIES -lc -lucb -# endif /* !HAVE_GCC */ -# if defined (USGr4_2) -# define SYSDEP_CFLAGS MACHINE_CFLAGS -DUSGr4 -DUSGr4_2 -# else -# define SYSDEP_CFLAGS MACHINE_CFLAGS -DUSGr4 -# endif /* !USGr4_2 */ -#endif - -/* ************************ */ -/* */ -/* Sony */ -/* */ -/* ************************ */ -#if defined (sony) && !defined (M_MACHINE) -# if defined (MIPSEB) -# define M_MACHINE "MIPSEB" -# else /* !MIPSEB */ -# define M_MACHINE "sony" -# endif /* !MIPSEB */ - -# if defined (SYSTYPE_SYSV) || defined (USGr4) -# define M_OS "USG" -# undef HAVE_GETWD -# define HAVE_DIRENT -# define HAVE_STRERROR -# define HAVE_VFPRINTF -# define VOID_SIGHANDLER - /* Alloca requires either Gcc or cc with -lucb. */ -# if !defined (HAVE_GCC) -# define EXTRA_LIB_SEARCH_PATH /usr/ucblib -# define REQUIRED_LIBRARIES -lc -lucb -# endif /* !HAVE_GCC */ -# if defined (MIPSEB) -# if !defined (HAVE_GCC) -# undef MACHINE_CFLAGS -# define MACHINE_CFLAGS -Wf,-XNl3072 -# endif -# define SYSDEP_CFLAGS MACHINE_CFLAGS -DUSGr4 -# else /* !MIPSEB */ -# define SYSDEP_CFLAGS -DUSGr4 -# endif /* !MIPSEB */ -# else /* !SYSTYPE_SYSV && !USGr4 */ -# define M_OS "Bsd" -# define SYSDEP_CFLAGS -DHAVE_UID_T -# endif /* !SYSTYPE_SYSV && !USGr4 */ -# define HAVE_SYS_SIGLIST -# define HAVE_SETLINEBUF -# define HAVE_GETGROUPS -#endif /* sony */ - -/* ******************************* */ -/* */ -/* Ardent Titan OS v2.2 and later */ -/* */ -/* ******************************* */ -#if defined (ardent) -# define M_MACHINE "Ardent Titan" -# define M_OS "Bsd" -# if defined (titan) -# undef HAVE_GETGROUPS -# else -# define HAVE_GETGROUPS -# endif /* !titan */ -# define HAVE_SYS_SIGLIST -# define HAVE_SETLINEBUF -# define SYSDEP_CFLAGS -43 -w -# define SYSDEP_LDFLAGS -43 -# undef HAVE_ALLOCA -# undef USE_GNU_MALLOC -# undef HAVE_VFPRINTF -# undef HAVE_DIRENT_H -#endif /* ardent */ - -/* ************************ */ -/* */ -/* Stardent */ -/* */ -/* ************************ */ -#if defined (stardent) && !defined (M_MACHINE) -# define M_MACHINE "Stardent" -# define M_OS "USG" -# define HAVE_SYS_SIGLIST -# define USE_TERMCAP_EMULATION -# define VOID_SIGHANDLER -# undef HAVE_GETWD -# undef HAVE_ALLOCA -#endif /* stardent */ - -/* ******************************** */ -/* */ -/* MIPS RISC/os */ -/* */ -/* ******************************** */ - -/* Notes on compiling with "make": - - * Place /bsd43/bin in your PATH before /bin. - * Use `$(CC) -E' instead of `/lib/cpp' in Makefile. -*/ -#if defined (mips) && ((!defined (M_MACHINE) && !defined (__nonstopux)) || defined (RiscOS)) - -# if defined (MIPSEB) -# define M_MACHINE "MIPSEB" -# else /* !MIPSEB */ -# if defined (MIPSEL) -# define M_MACHINE "MIPSEL" -# else /* !MIPSEL */ -# define M_MACHINE "mips" -# endif /* !MIPSEL */ -# endif /* !MIPSEB */ - -# define M_OS "Bsd" - - /* Special things for machines from MIPS Co. */ -# define MIPS_CFLAGS -DOPENDIR_NOT_ROBUST -DPGRP_PIPE - -# if !defined (HAVE_GCC) -# undef MACHINE_CFLAGS -# define MACHINE_CFLAGS -Wf,-XNl3072 -systype bsd43 -# define SYSDEP_LDFLAGS -systype bsd43 -# endif /* !HAVE_GCC */ -# define SYSDEP_CFLAGS MACHINE_CFLAGS MIPS_CFLAGS -# define HAVE_SYS_SIGLIST -# define HAVE_SETLINEBUF -# define HAVE_VFPRINTF -# define HAVE_GETGROUPS -# undef HAVE_UNISTD_H -# if !defined (HAVE_RESOURCE) -# define HAVE_RESOURCE -# endif /* !HAVE_RESOURCE */ - /* /usr/include/sys/wait.h appears not to work correctly, so why use it? */ -# undef HAVE_WAIT_H -#endif /* mips */ - -/* ************************ */ -/* */ -/* Pyramid */ -/* */ -/* ************************ */ -#if defined (pyr) -# define M_MACHINE "Pyramid" -# define M_OS "Bsd" -# if !defined (HAVE_GCC) -# undef HAVE_ALLOCA -# endif /* HAVE_GCC */ -# define HAVE_SYS_SIGLIST -# define HAVE_SETLINEBUF -# define HAVE_GETGROUPS -#endif /* pyr */ - -/* ************************ */ -/* */ -/* IBMRT */ -/* */ -/* ************************ */ -#if defined (ibm032) -# define M_MACHINE "IBMRT" -# define M_OS "Bsd" -# define HAVE_SYS_SIGLIST -# define HAVE_SETLINEBUF -# define USE_VFPRINTF_EMULATION - /* Alloca requires either gcc or hc or pcc with -ma in SYSDEP_CFLAGS. */ -# if !defined (HAVE_GCC) -# define SYSDEP_CFLAGS -ma -U__STDC__ -# endif /* !HAVE_GCC */ -# define HAVE_GETGROUPS -/* #define USE_GNU_TERMCAP */ -#endif /* ibm032 */ - -/* **************************************************************** */ -/* */ -/* All Intel 386 Processor Machines are Defined Here! */ -/* */ -/* **************************************************************** */ - -#if defined (i386) - -/* Sequent Symmetry running Dynix/ptx 2.x */ -# if !defined (done386) && defined (_SEQUENT_) -# define done386 -# define M_MACHINE "Symmetry" -# define M_OS "Dynix" -# define DYNIX_CFLAGS -DHAVE_GETDTABLESIZE -DHAVE_SETDTABLESIZE \ - -DHAVE_GETPW_DECLS -DHAVE_SOCKETS -# define SYSDEP_CFLAGS -DUSG -DUSGr3 DYNIX_CFLAGS -# define HAVE_DIRENT -# define HAVE_VFPRINTF -# define VOID_SIGHANDLER -/* Might need to add -lsocket -linet -lnsl to the list of libraries. */ -# define REQUIRED_LIBRARIES -lPW -lseq -# undef HAVE_GETWD -# undef HAVE_RESOURCE -# undef HAVE_ALLOCA -# endif /* _SEQUENT_ */ - -/* Sequent Symmetry running Dynix (4.2 BSD) */ -# if !defined (done386) && defined (sequent) -# define done386 -# define M_MACHINE "Symmetry" -# define M_OS "Bsd" -# define SYSDEP_CFLAGS -DCPCC -DHAVE_SETDTABLESIZE -# define HAVE_SETLINEBUF -# define HAVE_SYS_SIGLIST -# define HAVE_GETGROUPS -# define LD_HAS_NO_DASH_L -# undef HAVE_DUP2 -# endif /* Sequent 386 */ - -/* NeXT 3.x on i386 */ -# if !defined (done386) && defined (NeXT) -# define done386 -# define M_MACHINE "i386" -# define M_OS "NeXTstep" -# define HAVE_VFPRINTF -# define HAVE_SYS_SIGLIST -# define HAVE_GETGROUPS -# define HAVE_STRERROR -# define VOID_SIGHANDLER -# if !defined (HAVE_RESOURCE) -# define HAVE_RESOURCE -# endif -# define HAVE_STRCASECMP -# define GCC_STANDARD -# undef HAVE_GETWD -# undef HAVE_GETCWD -# undef USE_GNU_MALLOC -# undef HAVE_DIRENT_H -# define SYSDEP_CFLAGS -DNeXT -DMKFIFO_MISSING -DRLOGIN_PGRP_BUG -# endif - -/* Generic 386 clone running Mach (4.3 BSD-compatible). */ -# if !defined (done386) && defined (MACH) -# define done386 -# define M_MACHINE "i386" -# define M_OS "Bsd" -# define HAVE_SETLINEBUF -# define HAVE_SYS_SIGLIST -# define HAVE_GETGROUPS -# endif /* i386 && MACH */ - -/* AIX PS/2 1.[23] for the [34]86. */ -# if !defined (done386) && defined (aixpc) -# define done386 -# define M_MACHINE "aixpc" -# define M_OS "AIX" -# define HAVE_VFPRINTF -# define VOID_SIGHANDLER -# if defined (AIX_13) /* AIX PS/2 1.3 */ -# define SYSDEP_CFLAGS -DTERMIOS_LDISC -# define REQUIRED_LIBRARIES -lc_s -# else -# define SYSDEP_CFLAGS -D_BSD -DTERMIOS_LDISC -# define REQUIRED_LIBRARIES -lbsd -lc_s -# endif /* !AIX_13 */ -# define HAVE_GETGROUPS -# if !defined (HAVE_GCC) -# undef HAVE_ALLOCA -# undef HAVE_ALLOCA_H -# endif /* !HAVE_GCC */ -# define USE_TERMCAP_EMULATION -# endif /* AIXPC i386 */ - -/* System V Release 4 on the 386 */ -# if !defined (done386) && defined (USGr4) -# define done386 -# define M_MACHINE "i386" -# define M_OS "USG" -# define HAVE_DIRENT -# define HAVE_SYS_SIGLIST -# define HAVE_VFPRINTF -# define VOID_SIGHANDLER - /* Alloca requires either Gcc or cc with -lucb. */ -# if !defined (HAVE_GCC) -# define EXTRA_LIB_SEARCH_PATH /usr/ucblib -# define REQUIRED_LIBRARIES -lc -lucb -# endif /* !HAVE_GCC */ -# define HAVE_GETGROUPS -# if defined (USGr4_2) -# define SYSDEP_CFLAGS -DUSGr4 -DUSGr4_2 -DNO_SBRK_DECL -# else -# define SYSDEP_CFLAGS -DUSGr4 -# endif /* ! USGr4_2 */ -# undef HAVE_GETWD -# endif /* System V Release 4 on i386 */ - -/* 386 box running Interactive Unix 2.2 or greater. */ -# if !defined (done386) && defined (isc386) -# define done386 -# define M_MACHINE "isc386" -# define M_OS "USG" -# define HAVE_DIRENT -# define HAVE_VFPRINTF -# define VOID_SIGHANDLER -# define HAVE_GETGROUPS -# define USE_TERMCAP_EMULATION -# if defined (HAVE_GCC) -# define SYSDEP_LDFLAGS -posix -# define ISC_POSIX -# else -# define REQUIRED_LIBRARIES -lPW -# define SYSDEP_LDFLAGS -Xp -# define ISC_POSIX -Xp -# endif -# define ISC_SYSDEPS -DUSGr3 -DPGRP_PIPE -DHAVE_GETPW_DECLS -D_POSIX_SOURCE -DOPENDIR_NOT_ROBUST -DMEMMOVE_MISSING -DWAITPID_BROKEN -# if defined (__STDC__) -# if defined (HAVE_GCC) -# define ISC_EXTRA -DO_NDELAY=O_NONBLOCK -# else -# define ISC_EXTRA -Dmode_t="unsigned short" -DO_NDELAY=O_NONBLOCK -# endif /* HAVE_GCC */ -# else -# define ISC_EXTRA -# endif /* __STDC__ */ -# define SYSDEP_CFLAGS ISC_SYSDEPS ISC_POSIX ISC_EXTRA -# undef HAVE_GETWD -# if !defined (ISC_4) -# undef HAVE_GETCWD -# else -# undef HAVE_RESOURCE -# endif /* ISC_4 */ -# endif /* isc386 */ - -/* Xenix386 machine (with help from Ronald Khoo ). */ -# if !defined (done386) && defined (Xenix386) -# define done386 -# define M_MACHINE "i386" -# define M_OS "Xenix" -# define XENIX_CFLAGS -DUSG -DUSGr3 -DMEMMOVE_MISSING - -# if defined (XENIX_22) -# define XENIX_EXTRA -DREVERSED_SETVBUF_ARGS -# define REQUIRED_LIBRARIES -lx -# else /* !XENIX_22 */ -# define HAVE_DIRENT -# if defined (XENIX_23) -# define XENIX_EXTRA -DLD_HAS_NO_DASH_L -# define REQUIRED_LIBRARIES -ldir -# else /* !XENIX_23 */ -# define XENIX_EXTRA -xenix -# define SYSDEP_LDFLAGS -xenix -# define REQUIRED_LIBRARIES -ldir -l2.3 -# endif /* !XENIX_23 */ -# endif /* !XENIX_22 */ - -# define SYSDEP_CFLAGS XENIX_CFLAGS XENIX_EXTRA -# define HAVE_VFPRINTF -# define VOID_SIGHANDLER -# define ALLOCA_ASM x386-alloca.s -# define ALLOCA_OBJ x386-alloca.o -# undef HAVE_ALLOCA -# undef HAVE_GETWD -# undef HAVE_RESOURCE -# endif /* Xenix386 */ - -/* SCO UNIX 3.2 chip@count.tct.com (Chip Salzenberg) */ -# if !defined (done386) && defined (M_UNIX) -# define done386 -# define M_MACHINE "i386" -# define M_OS "SCO" -# define SCO_CFLAGS -DUSG -DUSGr3 -DPGRP_PIPE -# if defined (SCOv4) || defined (SCOv5) -# define SYSDEP_CFLAGS SCO_CFLAGS -DWAITPID_BROKEN -# else /* !SCOv4 && !SCOv5 */ -# define SYSDEP_CFLAGS SCO_CFLAGS -DOPENDIR_NOT_ROBUST -DMUST_UNBLOCK_CHILD -# endif /* !SCOv4 && !SCOv5 */ -# define HAVE_VFPRINTF -# define VOID_SIGHANDLER -# define HAVE_GETGROUPS -# undef HAVE_GETWD -# undef HAVE_RESOURCE -/* advice from wbader@cess.lehigh.edu and Eduard.Vopicka@vse.cz */ -# if !defined (HAVE_GCC) -# define REQUIRED_LIBRARIES -lc_s -lc -lPW -# else -# define REQUIRED_LIBRARIES -lc_s -lc -# endif /* !HAVE_GCC */ -# endif /* SCO Unix on 386 boxes. */ - -# if !defined (done386) && defined (__OSF1__) -# define done386 -# define M_MACHINE "i386" -# define M_OS "OSF1" -# define HAVE_SYS_SIGLIST -# define HAVE_SETLINEBUF -# define HAVE_VFPRINTF -# define HAVE_STRERROR -# define HAVE_GETGROUPS -# define VOID_SIGHANDLER -# define HAVE_BCOPY -# define USE_TERMCAP_EMULATION -# define SYSDEP_CFLAGS -D_BSD -# define REQUIRED_LIBRARIES -lbsd -# endif /* OSF/1 */ - -/* BSDI BSD/OS running on a 386 or 486. */ -# if !defined (done386) && defined (__bsdi__) -# define done386 -# define M_MACHINE "i386" -# if defined (BSDI2) -# define M_OS "BSD_OS" -# define SYSDEP_CFLAGS -DOPENDIR_NOT_ROBUST -DRLIMTYPE=quad_t -# else -# define M_OS "BSD386" -# define SYSDEP_CFLAGS -DOPENDIR_NOT_ROBUST -DINT_GROUPS_ARRAY -# endif -# define HAVE_SYS_SIGLIST -# define HAVE_SETLINEBUF -# define HAVE_GETGROUPS -# define HAVE_VFPRINTF -# define HAVE_STRERROR -# define VOID_SIGHANDLER -# define HAVE_DIRENT -# define HAVE_STRCASECMP -# endif /* !done386 && bsdi */ - -/* NetBSD running on a 386 or 486. */ -# if !defined (done386) && defined (__NetBSD__) -# define done386 -# define M_MACHINE "i386" -# define M_OS "NetBSD" -# define SYSDEP_CFLAGS -DOPENDIR_NOT_ROBUST -DINT_GROUPS_ARRAY \ - -DRLIMTYPE=quad_t -# define HAVE_SYS_SIGLIST -# define HAVE_SETLINEBUF -# define HAVE_GETGROUPS -# define HAVE_VFPRINTF -# define HAVE_STRERROR -# define VOID_SIGHANDLER -# define HAVE_DIRENT -# define HAVE_STRCASECMP -# endif /* !done386 && __NetBSD__ */ - -/* FreeBSD running on a 386 or 486. */ -# if !defined (done386) && defined (__FreeBSD__) -# define done386 -# define M_MACHINE "i386" -# define M_OS "FreeBSD" -# if __FreeBSD__ > 1 -# define SYSDEP_CFLAGS -D__BSD_4_4__ -DRLIMTYPE=quad_t -# else -# define SYSDEP_CFLAGS -DOPENDIR_NOT_ROBUST -DINT_GROUPS_ARRAY -# endif -# define HAVE_SYS_SIGLIST -# define HAVE_SETLINEBUF -# define HAVE_GETGROUPS -# define HAVE_VFPRINTF -# define HAVE_STRERROR -# define VOID_SIGHANDLER -# define HAVE_DIRENT -# define HAVE_STRCASECMP -# define GCC_STANDARD -# endif /* !done386 && __FreeBSD__ */ - -/* Jolitz 386BSD running on a 386 or 486. */ -# if !defined (done386) && defined (__386BSD__) -# define done386 -# define M_MACHINE "i386" -# define M_OS "_386BSD" -# define SYSDEP_CFLAGS -DOPENDIR_NOT_ROBUST -DINT_GROUPS_ARRAY -# define HAVE_SYS_SIGLIST -# define HAVE_SETLINEBUF -# define HAVE_GETGROUPS -# define HAVE_VFPRINTF -# define HAVE_STRERROR -# define VOID_SIGHANDLER -# define HAVE_DIRENT -# define HAVE_STRCASECMP -# endif /* !done386 && __386BSD__ */ - -# if !defined (done386) && (defined (__linux__) || defined (linux)) -# define done386 -# define M_MACHINE "i386" -# define M_OS "Linux" -# define SYSDEP_CFLAGS -DHAVE_GETDTABLESIZE -DHAVE_BCOPY \ - -DHAVE_GETPW_DECLS -DHAVE_GETHOSTNAME -# define REQUIRED_LIBRARIES -# define HAVE_GETGROUPS -# define HAVE_STRERROR -# define VOID_SIGHANDLER -# define HAVE_SYS_SIGLIST -# define HAVE_VFPRINTF -# define HAVE_VARARGS_H -# define SEARCH_LIB_NEEDS_SPACE -# if defined (__GNUC__) -# define HAVE_FIXED_INCLUDES -# endif /* __GNUC__ */ -# undef USE_GNU_MALLOC -# undef HAVE_SETLINEBUF -# undef HAVE_GETWD -# endif /* !done386 && __linux__ */ - -/* QNX 4.2 with GCC pt@flard.ocunix.on.ca (Paul Trunley) */ -# if !defined (done386) && defined (qnx) -# define done386 -# define M_MACHINE "i386" -# define M_OS "QNX" -# define SYSDEP_CFLAGS -D_POSIX_SOURCE -O2 -DUSG -# define HAVE_VFPRINTF -# define VOID_SIGHANDLER -# define HAVE_GCC -# define HAVE_FIXED_INCLUDES -# define HAVE_STRERROR -# define HAVE_GETGROUPS -# undef USE_GNU_MALLOC -# endif /* QNX 4.2 with GCC */ - -/* Lynx 2.1.0 (Mike Brennen ) */ -# if !defined (done386) && (defined (__Lynx__) || defined (Lynx)) -# define done386 -# define M_MACHINE "i386" -# define M_OS "Lynx" -# define SYSDEP_CFLAGS -DHAVE_GETDTABLESIZE -DHAVE_BCOPY -# define REQUIRED_LIBRARIES -lc_p -# define HAVE_GETGROUPS -# define VOID_SIGHANDLER -# define HAVE_SYS_SIGLIST -# define HAVE_VFPRINTF -# define HAVE_VARARGS_H -# if defined (__GNUC__) -# define HAVE_FIXED_INCLUDES -# endif /* __GNUC__ */ -/* Actually, Lynx does have unistd.h, but it defines _POSIX_VERSION, - and doesn't supply a fully compatible job control package. We just - pretend that it doesn't have it. */ -# undef HAVE_UNISTD_H -/* Lynx's wait structure reverses w_Stopval and w_Stopsig - don't use it */ -# undef HAVE_WAIT_H -# undef HAVE_DIRENT_H -# endif /* !done386 && __Lynx__ */ - -/* Assume a generic 386 running Sys V Release 3. */ -# if !defined (done386) -# define done386 -# define M_MACHINE "i386" -# define M_OS "USG" -# define SYSDEP_CFLAGS -DUSGr3 -# define HAVE_VFPRINTF -# define VOID_SIGHANDLER - /* Alloca requires either Gcc or cc with libPW.a */ -# if !defined (HAVE_GCC) -# define REQUIRED_LIBRARIES -lPW -# endif /* !HAVE_GCC */ -# undef HAVE_GETWD -# endif /* Generic i386 Box running Sys V release 3. */ -#endif /* All i386 Machines with an `i386' define in cpp. */ - -/* **************************************************************** */ -/* */ -/* Alliant FX/800 */ -/* */ -/* **************************************************************** */ -/* Original descs flushed. FX/2800 machine desc 1.13 bfox@ai.mit.edu. - Do NOT use -O with the stock compilers. If you must optimize, use - -uniproc with fxc, and avoid using scc. */ -#if defined (alliant) -# define M_MACHINE "alliant" -# define M_OS "Concentrix" -# define HAVE_SYS_SIGLIST -# define HAVE_SETLINEBUF -# define HAVE_GETGROUPS -# define HAVE_VFPRINTF -# define HAVE_RESOURCE -# define VOID_SIGHANDLER -# define HAVE_STRERROR -# define USE_GNU_MALLOC -# define LD_HAS_NO_DASH_L -# define SYSDEP_CFLAGS -DTERMIOS_MISSING -DMKFIFO_MISSING \ - -DBSD_GETPGRP -DRLOGIN_PGRP_BUG -w - /* Actually, Alliant does have unistd.h, but it defines _POSIX_VERSION, - and doesn't supply a fully compatible job control package. We just - pretend that it doesn't have it. */ -# undef HAVE_UNISTD_H -# undef HAVE_ALLOCA -#endif /* alliant */ - -/* ********************* */ -/* */ -/* Linux/m68k */ -/* */ -/* ********************* */ -#if defined (mc68000) && (defined (__linux__) || defined (linux)) -# define M_MACHINE "m68k" -# define M_OS "Linux" -# define SYSDEP_CFLAGS -DHAVE_BCOPY -DHAVE_GETPW_DECLS -DHAVE_GETHOSTNAME -# define REQUIRED_LIBRARIES -# define HAVE_GETGROUPS -# define HAVE_STRERROR -# define VOID_SIGHANDLER -# define HAVE_SYS_SIGLIST -# define HAVE_VFPRINTF -# define HAVE_VARARGS_H -# if defined (__GNUC__) -# define HAVE_FIXED_INCLUDES -# endif /* __GNUC__ */ -# undef USE_GNU_MALLOC -# undef HAVE_SETLINEBUF -# define HAVE_STRCASECMP -#endif /* mc68000 && __linux__ */ - -/* **************************************************************** */ -/* */ -/* Motorola Delta series running System V R3V6/7 */ -/* */ -/* **************************************************************** */ -/* Contributed by Robert L. McMillin (rlm@ms_aspen.hac.com). */ - -#if defined (m68k) && defined (sysV68) -# define M_MACHINE "Delta" -# define M_OS "USG" -# define SYSDEP_CFLAGS -DUSGr3 -DMEMMOVE_MISSING -# define VOID_SIGHANDLER -# define HAVE_VFPRINTF -# define REQUIRED_LIBRARIES -lm881 -# undef HAVE_GETWD -# undef HAVE_RESOURCE -# undef HAVE_DUP2 -# undef HAVE_ALLOCA -#endif /* Delta series */ - -/* **************************************************************** */ -/* */ -/* Gould 9000 - UTX/32 R2.1A */ -/* */ -/* **************************************************************** */ -#if defined (gould) /* Maybe should be GOULD_PN ? */ -# define M_MACHINE "gould" -# define M_OS "Bsd" -# define HAVE_SYS_SIGLIST -# define HAVE_SETLINEBUF -# define HAVE_GETGROUPS -#endif /* gould */ - -/* ************************ */ -/* */ -/* NeXT */ -/* */ -/* ************************ */ -#if defined (NeXT) && !defined (M_MACHINE) -# define M_MACHINE "NeXT" -# define M_OS "NeXTstep" -# define HAVE_VFPRINTF -# define HAVE_SYS_SIGLIST -# define HAVE_GETGROUPS -# define HAVE_STRERROR -# define VOID_SIGHANDLER -# if !defined (HAVE_RESOURCE) -# define HAVE_RESOURCE -# endif -# define HAVE_STRCASECMP -# define GCC_STANDARD -# undef HAVE_GETWD -# undef HAVE_GETCWD -# undef HAVE_DIRENT_H -# define SYSDEP_CFLAGS -DMKFIFO_MISSING -DRLOGIN_PGRP_BUG -# undef USE_GNU_MALLOC -#endif /* NeXT */ - -/* ********************** */ -/* */ -/* m68k NetBSD */ -/* */ -/* ********************** */ -#if defined (m68k) && defined (__NetBSD__) -# include -# define M_MACHINE MACHINE -# define M_OS "NetBSD" -/* os/netbsd.h */ -# define SYSDEP_CFLAGS -DOPENDIR_NOT_ROBUST -DINT_GROUPS_ARRAY \ - -DRLIMTYPE=quad_t -# define HAVE_SYS_SIGLIST -# define HAVE_SETLINEBUF -# define HAVE_GETGROUPS -# define HAVE_VFPRINTF -# define HAVE_STRERROR -# define VOID_SIGHANDLER -# define HAVE_DIRENT -# define HAVE_STRCASECMP -#endif /* m68k && __NetBSD__ */ - -/* ************************ */ -/* */ -/* hp9000 4.4 BSD */ -/* */ -/* ************************ */ -#if defined (hp9000) && defined (__BSD_4_4__) -# define M_MACHINE "hp9000" -# define M_OS "BSD_4_4" -# define HAVE_SYS_SIGLIST -# define HAVE_SETLINEBUF -# define HAVE_GETGROUPS -# define HAVE_STRERROR -# define HAVE_VFPRINTF -# define VOID_SIGHANDLER -# define HAVE_STRCASECMP -# define SYSDEP_CFLAGS -DHAVE_GETDTABLESIZE -DHAVE_BCOPY -DHAVE_RESOURCE -# undef HAVE_ALLOCA -#endif /* hp9000 && __BSD_4_4__ */ - -/* ************************ */ -/* */ -/* hp9000 4.3 BSD */ -/* */ -/* ************************ */ -#if defined (hp9000) && !defined (hpux) && !defined (M_MACHINE) -# define M_MACHINE "hp9000" -# define M_OS "Bsd" -# undef HAVE_ALLOCA -# define HAVE_SYS_SIGLIST -# define HAVE_SETLINEBUF -# define HAVE_GETGROUPS -# define USE_VFPRINTF_EMULATION -#endif /* hp9000 && !hpux */ - -/* ************************ */ -/* */ -/* hpux */ -/* */ -/* ************************ */ -#if defined (hpux) - -/* HPUX comes in several different flavors, from pre-release 6.2 (basically - straight USG), to Posix compliant 9.0. */ - - /* HP machines come in several processor types. - They are distinguished here. */ -# if defined (hp9000s200) && !defined (hp9000s300) -# define M_MACHINE "hp9000s200" -# endif /* hp9000s200 */ -# if defined (hp9000s300) && !defined (M_MACHINE) -# define M_MACHINE "hp9000s300" -# endif /* hp9000s300 */ -# if defined (hp9000s500) && !defined (M_MACHINE) -# define M_MACHINE "hp9000s500" -# endif /* hp9000s500 */ -# if defined (hp9000s700) && !defined (M_MACHINE) -# define M_MACHINE "hp9000s700" -# endif /* hp9000s700 */ -# if defined (hp9000s800) && !defined (M_MACHINE) -# define M_MACHINE "hp9000s800" -# endif /* hp9000s800 */ -# if defined (hppa) && !defined (M_MACHINE) -# define M_MACHINE "hppa" -# endif /* hppa */ - -/* Define the OS as the particular type that we are using. */ -/* This is for HP-UX systems earlier than HP-UX 6.2 -- no job control. */ -# if defined (HPUX_USG) -# define M_OS "USG" -# define HPUX_CFLAGS -Dhpux -# define REQUIRED_LIBRARIES -lPW -lBSD -# undef HAVE_WAIT_H -# define HPUX_EXTRA -# else /* !HPUX_USG */ - -/* All of the other operating systems need HPUX to be defined. */ -# define HPUX_EXTRA -DHPUX -Dhpux -DHAVE_GETHOSTNAME -DUSG - - /* HPUX 6.2 .. 6.5 require -lBSD for getwd (), and -lPW for alloca (). */ -# if defined (HPUX_6) -# define M_OS "hpux_6" -# define REQUIRED_LIBRARIES -lPW -lBSD -# undef HAVE_ALLOCA -# undef HAVE_WAIT_H -# endif /* HPUX_6 */ - - /* On HP-UX 7.x, we do not link with -lBSD, so we don't have getwd (). */ -# if defined (HPUX_7) -# define M_OS "hpux_7" -# define REQUIRED_LIBRARIES -lPW -# define HPUX_CFLAGS -DHAVE_SOCKETS -# undef HAVE_GETWD -# undef USE_GNU_MALLOC -# endif /* HPUX_7 */ - - /* HP-UX 8.x systems do not have a working alloca () on all platforms. - This can cause us problems, especially when globbing. HP has the - same YP bug as Sun, so we #undef USE_GNU_MALLOC. */ -# if defined (HPUX_8) -# define M_OS "hpux_8" -# if !defined (__GNUC__) -# undef HAVE_ALLOCA -# define HPUX_ANSI +O3 -Aa -D_HPUX_SOURCE -# else -# define HPUX_ANSI -# endif -# undef HAVE_GETWD -# undef USE_GNU_MALLOC -# define HPUX_CFLAGS -DNO_SBRK_DECL -DHAVE_SOCKETS HPUX_ANSI -# endif /* HPUX_8 */ - - /* HP-UX 9.0 reportedly fixes the alloca problems present in the 8.0 - release. If so, -lPW is required to include it. */ -# if defined (HPUX_9) -# define M_OS "hpux_9" -# if !defined (__GNUC__) -# undef HAVE_ALLOCA -# define HPUX_ANSI +O3 -Ae -# else -# define HPUX_ANSI -# endif -# undef HAVE_GETWD -# undef USE_GNU_MALLOC -# undef HAVE_RESOURCE -# define HPUX_CFLAGS -DNO_SBRK_DECL -DHAVE_SOCKETS -DHAVE_GETHOSTNAME HPUX_ANSI -# endif /* HPUX_9 */ - -# if defined (HPUX_10) -# define M_OS "hpux_10" -# if !defined (__GNUC__) -# undef HAVE_ALLOCA -# define HPUX_ANSI +O3 -Ae -# else -# define HPUX_ANSI -# endif -# undef HAVE_GETWD -# undef USE_GNU_MALLOC -# undef HAVE_RESOURCE -# define HPUX_CFLAGS -DNO_SBRK_DECL -DHAVE_SOCKETS -DHAVE_GETHOSTNAME -DBSD_GETPGRP HPUX_ANSI -# endif /* HPUX_9 */ - -# endif /* !HPUX_USG */ - - /* All of the HPUX systems that we have tested have the following. */ -# define HAVE_DIRENT -# define HAVE_VFPRINTF -# define VOID_SIGHANDLER -# define HAVE_GETGROUPS -# define HAVE_STRERROR -# define USE_TERMCAP_EMULATION -# define SEARCH_LIB_NEEDS_SPACE - -# if defined (HPUX_CFLAGS) -# define SYSDEP_CFLAGS HPUX_CFLAGS HPUX_EXTRA -# else /* !HPUX_CFLAGS */ -# define SYSDEP_CFLAGS HPUX_EXTRA -# endif /* !HPUX_CFLAGS */ - -#endif /* hpux */ - -/* ************************ */ -/* */ -/* MIPS OSF/1 */ -/* */ -/* ************************ */ -# if defined (MIPSEL) && defined (__OSF1__) -# define M_MACHINE "mips" -# define M_OS "OSF1" -# define HAVE_SYS_SIGLIST -# define HAVE_SETLINEBUF -# define HAVE_VFPRINTF -# define HAVE_STRERROR -# define HAVE_GETGROUPS -# define VOID_SIGHANDLER -# define HAVE_BCOPY -# define USE_TERMCAP_EMULATION -# define SYSDEP_CFLAGS -D_BSD -# define REQUIRED_LIBRARIES -lbsd -# endif /* MIPSEL && __OSF1__ */ - -/* ************************ */ -/* */ -/* HP OSF/1 */ -/* */ -/* ************************ */ -#if defined (__hp_osf) -# define M_MACHINE "HPOSF1" -# define M_OS "OSF1" -# define SYSDEP_CFLAGS -q no_sl_enable -# define SYSDEP_LDFLAGS -q lang_level:classic -# define REQUIRED_LIBRARIES -lPW -# define HAVE_SETLINEBUF -# define HAVE_VFPRINTF -# define VOID_SIGHANDLER -# define HAVE_GETGROUPS -# define HAVE_STRERROR -# undef HAVE_ALLOCA -#endif /* __hp_osf */ - -/* ************************ */ -/* */ -/* KSR1 OSF/1 */ -/* */ -/* ************************ */ -#if defined (__ksr1__) -# define M_MACHINE "KSR1" -# define M_OS "OSF1" -# define HAVE_SETLINEBUF -# define HAVE_VFPRINTF -# define VOID_SIGHANDLER -# define HAVE_GETGROUPS -# define HAVE_STRERROR -# define SYSDEP_CFLAGS -DHAVE_GETDTABLESIZE -DHAVE_BCOPY -DHAVE_UID_T -# undef HAVE_ALLOCA -# undef USE_GNU_MALLOC -#endif /* ksr1 */ - -/* ************************ */ -/* */ -/* Intel Paragon - OSF/1 */ -/* */ -/* ************************ */ -#if defined (__i860) && defined (__PARAGON__) -# define M_MACHINE "Paragon" -# define M_OS "OSF1" -# define HAVE_GETGROUPS -# define HAVE_SETLINEBUF -# define HAVE_VFPRINTF -# define VOID_SIGHANDLER -# define HAVE_STRERROR -# define HAVE_SYS_SIGLIST -#endif /* __i860 && __PARAGON__ */ - -/* ************************ */ -/* */ -/* IBM AIX/ESA (OSF/1) */ -/* */ -/* ************************ */ -#if defined(AIXESA) || (defined(__ibmesa) && defined(_AIX)) -# define M_MACHINE "IBMESA" -# define M_OS "OSF1" -# define HAVE_GETGROUPS -# define HAVE_SETLINEBUF -# define HAVE_VPRINTF -# define VOID_SIGHANDLER -# define HAVE_STRERROR -# define HAVE_SYS_SIGLIST -# define HAVE_ALLOCA_H /* hack for AIX/ESA, which has malloc.h */ -# undef USE_GNU_MALLOC -#endif /* AIXESA || (__ibmesa && _AIX) */ - -/* ************************ */ -/* */ -/* Intel i860 -- SVR4 */ -/* */ -/* ************************ */ -#if defined (__i860) && defined (USGr4) && !defined (M_MACHINE) -# define M_MACHINE "i860" -# define M_OS "USG" -# define HAVE_DIRENT -# define HAVE_SYS_SIGLIST -# define HAVE_VFPRINTF -# define VOID_SIGHANDLER -# define HAVE_GETGROUPS -# if !defined (HAVE_GCC) && !defined (HAVE_ALLOCA_H) -# undef HAVE_ALLOCA -# endif /* !HAVE_GCC && !HAVE_ALLOCA_H */ -# if defined (USGr4_2) -# define SYSDEP_CFLAGS -DUSGr4 -DUSGr4_2 -# else -# define SYSDEP_CFLAGS -DUSGr4 -# endif /* ! USGr4_2 */ -# undef HAVE_GETWD -#endif /* __i860 && USGr4 */ - -/* ************************ */ -/* */ -/* Xenix286 */ -/* */ -/* ************************ */ -#if defined (Xenix286) -# define M_MACHINE "i286" -# define M_OS "Xenix" - -# define XENIX_CFLAGS -DUSG -DUSGr3 -DMEMMOVE_MISSING - -# if defined (XENIX_22) -# define XENIX_EXTRA -DREVERSED_SETVBUF_ARGS -# define REQUIRED_LIBRARIES -lx -# else /* !XENIX_22 */ -# define HAVE_DIRENT -# if defined (XENIX_23) -# define XENIX_EXTRA -DLD_HAS_NO_DASH_L -# define REQUIRED_LIBRARIES -ldir -# else /* !XENIX_23 */ -# define XENIX_EXTRA -xenix -# define SYSDEP_LDFLAGS -xenix -# define REQUIRED_LIBRARIES -ldir -l2.3 -# endif /* !XENIX_23 */ -# endif /* !XENIX_22 */ - -# define SYSDEP_CFLAGS XENIX_CFLAGS XENIX_EXTRA -# undef HAVE_ALLOCA -# undef HAVE_GETWD -# undef HAVE_RESOURCE -#endif /* Xenix286 */ - -/* ************************ */ -/* */ -/* convex */ -/* */ -/* ************************ */ -#if defined (convex) -# define M_MACHINE "convex" -# define M_OS "Bsd" -# undef HAVE_ALLOCA -# define HAVE_SETLINEBUF -# define HAVE_SYS_SIGLIST -# define HAVE_GETGROUPS -#endif /* convex */ - -/* ************************ */ -/* */ -/* AIX/RT */ -/* */ -/* ************************ */ -#if defined (aix) && !defined (aixpc) -# define M_MACHINE "AIXRT" -# define M_OS "USG" -# define HAVE_DIRENT -# define HAVE_VFPRINTF -# define HAVE_SYS_SIGLIST -# define VOID_SIGHANDLER -# define HAVE_GETGROUPS -# define USE_TERMCAP_EMULATION -# if !defined (HAVE_GCC) -# undef MACHINE_CFLAGS -# define MACHINE_CFLAGS -a -# endif /* !HAVE_GCC */ -# define SYSDEP_CFLAGS MACHINE_CFLAGS -DNLS -DUSGr3 -DHAVE_BCOPY -# undef USE_GNU_MALLOC -# undef HAVE_ALLOCA -# undef HAVE_RESOURCE -#endif /* aix && !aixpc */ - -/* **************************************** */ -/* */ -/* IBM RISC 6000 */ -/* */ -/* **************************************** */ -#if defined (RISC6000) || defined (_IBMR2) -# define M_MACHINE "RISC6000" -# define M_OS "AIX" -# define HAVE_DIRENT -# define HAVE_SYS_SIGLIST -# define HAVE_SETLINEBUF -# define HAVE_VFPRINTF -# define VOID_SIGHANDLER -# define USE_TERMCAP_EMULATION -# define HAVE_GETGROUPS -# define SYSDEP_CFLAGS -DNLS -DUSGr3 -DHAVE_BCOPY -# undef HAVE_ALLOCA -# undef HAVE_GETWD -# undef USE_GNU_MALLOC -#endif /* RISC6000 */ - -/* **************************************** */ -/* */ -/* u370 IBM AIX/370 */ -/* */ -/* **************************************** */ -#if defined (u370) -# if defined (_AIX370) -# define M_MACHINE "AIX370" -# define M_OS "Bsd" -# define REQUIRED_LIBRARIES -lbsd -# define HAVE_SETLINEBUF -# define HAVE_VFPRINTF -# define SYSDEP_CFLAGS -D_BSD -# define HAVE_GETGROUPS -# define USE_TERMCAP_EMULATION -# undef USE_GNU_MALLOC -# endif /* _AIX370 */ -# if defined (USGr4) /* System V Release 4 on 370 series architecture. */ -# define M_MACHINE "uxp" -# define M_OS "USG" -# define HAVE_DIRENT -# define HAVE_SYS_SIGLIST -# define HAVE_VFPRINTF -# define USE_GNU_MALLOC -# define VOID_SIGHANDLER -# if !defined (HAVE_GCC) -# undef HAVE_ALLOCA -# define EXTRA_LIB_SEARCH_PATH /usr/ucblib -# define REQUIRED_LIBRARIES -lc -lucb -# endif /* !HAVE_GCC */ -# define HAVE_GETGROUPS -# define HAVE_RESOURCE -# define SYSDEP_CFLAGS -DUSGr4 -DNO_SBRK_DECL -# endif /* USGr4 */ -#endif /* u370 */ - -/* ************************ */ -/* */ -/* ATT 3B */ -/* */ -/* ************************ */ -#if defined (att3b) || defined (u3b2) -# if defined (att3b) -# define M_MACHINE "att3b" -# define HAVE_SYS_SIGLIST -# else /* !att3b */ -# define M_MACHINE "u3b2" -# endif /* !att3b */ -# define M_OS "USG" -# undef HAVE_GETWD -# define HAVE_VFPRINTF -# define VOID_SIGHANDLER - /* For an AT&T Unix before V.3 take out the -DUSGr3 and the HAVE_DIRENT. */ -# define SYSDEP_CFLAGS -DUSGr3 -# define HAVE_DIRENT - /* Alloca requires either Gcc or cc with libPW.a. */ -# if !defined (HAVE_GCC) -# define REQUIRED_LIBRARIES -lPW -# endif /* !HAVE_GCC */ -#endif /* att3b */ - -/* ************************ */ -/* */ -/* ATT 386 */ -/* */ -/* ************************ */ -#if defined (att386) -# define M_MACHINE "att386" -# define M_OS "USG" -# undef HAVE_GETWD - /* Alloca requires either Gcc or cc with libPW.a. */ -# if !defined (HAVE_GCC) -# define REQUIRED_LIBRARIES -lPW -# endif /* HAVE_GCC */ -# define HAVE_SYS_SIGLIST -# define HAVE_VFPRINTF -# define VOID_SIGHANDLER - /* For an AT&T Unix before V.3 take out the -DUSGr3 and the HAVE_DIRENT. */ -# define SYSDEP_CFLAGS -DUSGr3 -# define HAVE_DIRENT -#endif /* att386 */ - -/* ************************ */ -/* */ -/* ATT UNIX PC */ -/* */ -/* ************************ */ -#if defined (unixpc) -# define M_MACHINE "unixpc" -# define M_OS "USG" -# define HAVE_VFPRINTF -# define HAVE_DIRENT -# if defined (HAVE_GCC) -# define REQUIRED_LIBRARIES -ldirent -shlib -# else /* !HAVE_GCC */ -# define REQUIRED_LIBRARIES -ldirent -# endif /* !HAVE_GCC */ -# undef HAVE_GETWD -# undef HAVE_DUP2 -# undef VOID_SIGHANDLER -# undef HAVE_WAIT_H -#endif /* unixpc */ - -/* ************************ */ -/* */ -/* Encore */ -/* */ -/* ************************ */ -#if defined (MULTIMAX) -# if defined (n16) -# define M_MACHINE "Multimax32k" -# else -# define M_MACHINE "Multimax" -# endif /* n16 */ -# if defined (UMAXV) -# define M_OS "USG" -# define REQUIRED_LIBRARIES -lPW -# define SYSDEP_CFLAGS -DUSGr3 -# define HAVE_DIRENT -# define HAVE_VFPRINTF -# define USE_TERMCAP_EMULATION -# define VOID_SIGHANDLER -# else -# if defined (CMU) -# define M_OS "Mach" -# else -# define M_OS "Bsd" -# endif /* CMU */ -# define HAVE_SYS_SIGLIST -# define HAVE_STRERROR -# define HAVE_SETLINEBUF -# endif /* UMAXV */ -# define HAVE_GETGROUPS -#endif /* MULTIMAX */ - -/* ******************************************** */ -/* */ -/* Encore Series 91 (88K BCS w Job Control) */ -/* */ -/* ******************************************** */ -#if defined (__m88k) && defined (__UMAXV__) -# define M_MACHINE "Gemini" -# define M_OS "USG" -# define REQUIRED_LIBRARIES -lPW -# define USE_TERMCAP_EMULATION -# define HAVE_DIRENT -# define HAVE_GETGROUPS -# define HAVE_VFPRINTF -# define VOID_SIGHANDLER -# define SYSDEP_CFLAGS -q ext=pcc -D_POSIX_JOB_CONTROL -D_POSIX_VERSION \ - -Dmalloc=_malloc -Dfree=_free -Drealloc=_realloc -#endif /* m88k && __UMAXV__ */ - -/* ******************************************** */ -/* */ -/* System V Release 4 on the ICL DRS6000 */ -/* */ -/* ******************************************** */ -#if defined (drs6000) -# define M_MACHINE "drs6000" -# define M_OS "USG" -# define SYSDEP_CFLAGS -Xa -DUSGr4 -# define SEARCH_LIB_NEEDS_SPACE -# define HAVE_DIRENT -# define HAVE_SYS_SIGLIST -# define HAVE_VFPRINTF -# define HAVE_GETGROUPS -# define HAVE_STRERROR -# define VOID_SIGHANDLER -# define USE_GNU_TERMCAP -# if !defined (__GNUC__) -# undef HAVE_ALLOCA -# endif -# undef HAVE_ALLOCA_H -# undef USE_GNU_MALLOC -#endif /* drs6000 */ - -/* ******************************************** */ -/* */ -/* System V Release 4 on the Sparc (generic) */ -/* */ -/* ******************************************** */ -#if defined (sparc) && defined (__svr4__) && !defined (M_MACHINE) -# define M_MACHINE "sparc" -# define M_OS "SVR4" -# define SYSDEP_CFLAGS -DUSG -DUSGr4 -DHAVE_UID_T -# define HAVE_DIRENT -# define HAVE_VFPRINTF -# define HAVE_GETGROUPS -# define HAVE_STRERROR -# define VOID_SIGHANDLER -# define USE_GNU_TERMCAP -# if !defined (__GNUC__) -# undef HAVE_ALLOCA -# endif -# undef HAVE_BCOPY -# undef HAVE_GETWD -# undef USE_GNU_MALLOC -#endif /* sparc && __svr4__ */ - -/* ******************************************** */ -/* */ -/* Commodore Amiga */ -/* */ -/* ******************************************** */ -#if defined (amiga) && defined (__NetBSD__) -# define M_MACHINE "amiga" -# define M_OS "NetBSD" -# define SYSDEP_CFLAGS -DOPENDIR_NOT_ROBUST -DINT_GROUPS_ARRAY \ - -DRLIMTYPE=quad_t -# define HAVE_SYS_SIGLIST -# define HAVE_SETLINEBUF -# define HAVE_GETGROUPS -# define HAVE_VFPRINTF -# define HAVE_STRERROR -# define VOID_SIGHANDLER -# define HAVE_DIRENT -# define HAVE_STRCASECMP -#endif /* amiga && __NetBSD__ */ - -#if defined (amiga) && !defined (M_MACHINE) -# define M_MACHINE "amiga" -# define M_OS "USG" -# define SYSDEP_CFLAGS -DUSGr4 -# if !defined (HAVE_GCC) -# define EXTRA_LIB_SEARCH_PATH /usr/ucblib -# define REQUIRED_LIBRARIES -lc -lucb -# endif /* !HAVE_GCC */ -# define HAVE_DIRENT -# define HAVE_SYS_SIGLIST -# define HAVE_VFPRINTF -# define VOID_SIGHANDLER -# define HAVE_GETGROUPS -# define HAVE_STRERROR -# undef HAVE_GETWD -# undef USE_GNU_MALLOC -#endif /* System V Release 4 on amiga */ - -/* ************************ */ -/* */ -/* clipper */ -/* */ -/* ************************ */ -/* This is for the Orion 1/05 (A BSD 4.2 box based on a Clipper processor) */ -#if defined (clipper) && !defined (M_MACHINE) -# define M_MACHINE "clipper" -# define M_OS "Bsd" -# define HAVE_SETLINEBUF -# define HAVE_GETGROUPS -#endif /* clipper */ - -/* ******************************** */ -/* */ -/* Integrated Solutions 68020? */ -/* */ -/* ******************************** */ -#if defined (is68k) -# define M_MACHINE "is68k" -# define M_OS "Bsd" -# define HAVE_SYS_SIGLIST -# define HAVE_SETLINEBUF -# define HAVE_GETGROUPS -# define USE_VFPRINTF_EMULATION -# undef HAVE_ALLOCA -#endif /* is68k */ - -/* ******************************** */ -/* */ -/* Omron Luna/Mach 2.5 */ -/* */ -/* ******************************** */ -#if defined (luna88k) -# define M_MACHINE "Luna88k" -# define M_OS "Bsd" -# define HAVE_SYS_SIGLIST -# define USE_GNU_MALLOC -# define HAVE_SETLINEBUF -# define HAVE_VFPRINTF -# define HAVE_GETGROUPS -# define HAVE_VFPRINTF -#endif /* luna88k */ - -/* ************************ */ -/* */ -/* BBN Butterfly GP1000 */ -/* Mach 1000 v2.5 */ -/* */ -/* ************************ */ -#if defined (butterfly) && defined (BFLY1) -#define M_MACHINE "BBN Butterfly" -#define M_OS "Mach 1000" -#define HAVE_SETLINEBUF -#define HAVE_SYS_SIGLIST -#define HAVE_GETGROUPS -#define HAVE_VFPRINTF -# ifdef BUILDING_MAKEFILE -MAKE = make -# endif /* BUILDING_MAKEFILE */ -#endif /* butterfly */ - -/* **************************************** */ -/* */ -/* Apollo/SR10.2/BSD4.3 */ -/* */ -/* **************************************** */ -/* This is for the Apollo DN3500 running SR10.2 BSD4.3 */ -#if defined (apollo) -# define M_MACHINE "apollo" -# define M_OS "Bsd" -# define SYSDEP_CFLAGS -D_POSIX_VERSION -D_INCLUDE_BSD_SOURCE \ - -D_INCLUDE_POSIX_SOURCE -DTERMIOS_MISSING \ - -DBSD_GETPGRP -Dpid_t=int -# define HAVE_SYS_SIGLIST -# define HAVE_SETLINEBUF -# define HAVE_GETGROUPS -#endif /* apollo */ - -/* ************************ */ -/* */ -/* DG AViiON */ -/* */ -/* ************************ */ -/* This is for the DG AViiON box (runs DG/UX with both AT&T & BSD features.) */ -/* DG/UX comes standard with Gcc. */ -#if defined (__DGUX__) || defined (DGUX) -# define M_OS "DGUX" -# if !defined (_M88KBCS_TARGET) -# define M_MACHINE "AViiON" -# define REQUIRED_LIBRARIES -ldgc -# else /* _M88KBCS_TARGET */ -# define M_MACHINE "m88kBCS_AV" -# undef MACHINE_CFLAGS -# define MACHINE_CFLAGS -D_M88K_SOURCE -# undef HAVE_RESOURCE -# endif /* _M88KBCS_TARGET */ -# define SYSDEP_CFLAGS MACHINE_CFLAGS -D_DGUX_SOURCE -DPGRP_PIPE -DUSG -# define HAVE_GCC -# define HAVE_FIXED_INCLUDES -# define HAVE_STRERROR -# define HAVE_GETGROUPS -# define VOID_SIGHANDLER -# undef HAVE_GETWD -# undef USE_GNU_MALLOC - -/* If you want to build bash for M88K BCS compliance on a DG/UX 5.4 - or above system, do the following: - - If you have built in this directory before run "make clean" to - endure the Bash directory is clean. - - Run "eval `sde-target m88kbcs`" to set the software development - environment to build BCS objects. - - Run "make". - - Do "eval `sde-target default`" to reset the SDE. */ -#endif /* __DGUX__ */ - -/* ************************ */ -/* */ -/* Harris Night Hawk */ -/* */ -/* ************************ */ -/* This is for the Harris Night Hawk family. */ -#if defined (_CX_UX) -# if defined (_M88K) -# define M_MACHINE "nh4000" -# else /* !_M88K */ -# if defined (hcx) -# define M_MACHINE "nh2000" -# else /* !hcx */ -# if defined (gcx) -# define M_MACHINE "nh3000" -# endif /* gcx */ -# endif /* !hcx */ -# endif /* !_M88K */ -# define M_OS "USG" -# define SYSDEP_CFLAGS -g -Xa -v -Dgetwd=bash_getwd -D_POSIX_SOURCE \ - -D_POSIX_JOB_CONTROL -# define USE_TERMCAP_EMULATION -# define HAVE_VFPRINTF -# define HAVE_GETGROUPS -# define VOID_SIGHANDLER -# undef USE_GNU_MALLOC -# undef HAVE_GETWD -#endif /* _CX_UX */ - -/* **************************************** */ -/* */ -/* Tektronix */ -/* */ -/* **************************************** */ -/* These are unproven as yet. */ -#if defined (Tek4132) -# define M_MACHINE "Tek4132" -# define M_OS "Bsd" -# define HAVE_SYS_SIGLIST -# define HAVE_SETLINEBUF -# define HAVE_GETGROUPS -#endif /* Tek4132 */ - -#if defined (Tek4300) -# define M_MACHINE "Tek4300" -# define M_OS "Bsd" -# define HAVE_SYS_SIGLIST -# define HAVE_SETLINEBUF -# define HAVE_GETGROUPS -#endif /* Tek4300 */ - -/* ************************ */ -/* */ -/* Tektronix XD88 */ -/* */ -/* ************************ */ -#if defined (m88k) && defined (XD88) -# define M_MACHINE "XD88" -# define M_OS "USG" -# define HAVE_DIRENT -# define HAVE_VFPRINTF -# define HAVE_GETCWD -# define VOID_SIGHANDLER -# define HAVE_GETGROUPS -# undef HAVE_GETWD -# undef HAVE_ALLOCA -#endif /* m88k && XD88 */ - -/* ************************ */ -/* */ -/* Motorola M88100 */ -/* */ -/* ************************ */ -#if defined (m88k) && (defined (M88100) || defined (USGr4)) -# define M_MACHINE "M88100" -# define M_OS "USG" -# if defined (USGr4) -# define SYSDEP_CFLAGS -DUSGr4 -D_POSIX_JOB_CONTROL -# else -# define SYSDEP_CFLAGS -D_POSIX_JOB_CONTROL -DWAITPID_BROKEN -# endif -# define HAVE_DIRENT -# define HAVE_VFPRINTF -# define VOID_SIGHANDLER -# define HAVE_GETGROUPS -# undef HAVE_GETWD -# if !defined (USGr4) -# undef HAVE_GETCWD -# endif -# undef HAVE_ALLOCA -#endif /* m88k && M88100 */ - -/* ************************ */ -/* */ -/* Sequent Balances */ -/* (Dynix 3.x) */ -/* ************************ */ -#if defined (sequent) && !defined (M_MACHINE) -# define M_MACHINE "Sequent" -# define M_OS "Bsd" -# define HAVE_SYS_SIGLIST -# define HAVE_SETLINEBUF -# define HAVE_GETGROUPS -# define LD_HAS_NO_DASH_L -# undef HAVE_DUP2 -#endif /* sequent */ - -/* ****************************************** */ -/* */ -/* NCR Tower 32, System V Release 3 */ -/* */ -/* ****************************************** */ -#if defined (tower32) -# define M_MACHINE "tower32" -# define M_OS "USG" -# if !defined (HAVE_GCC) -# define REQUIRED_LIBRARIES -lPW - /* Disable stack/frame-pointer optimization, incompatible with alloca */ -# undef MACHINE_CFLAGS -# define MACHINE_CFLAGS -W2,-aat -# endif /* !HAVE_GCC */ -# define SYSDEP_CFLAGS -DUSGr3 MACHINE_CFLAGS -# define HAVE_VFPRINTF -# define USE_TERMCAP_EMULATION -# define VOID_SIGHANDLER -# undef HAVE_GETWD -#endif /* tower32 */ - -/* ************************ */ -/* */ -/* Concurrent */ -/* */ -/* ************************ */ -#if defined (concurrent) -# define M_MACHINE "Concurrent" -# if defined (USE_BSD_UNIVERSE) - /* Use the BSD universe (`universe ucb') */ -# define M_OS "Bsd" -# define HAVE_SYS_SIGLIST -# define HAVE_SETLINEBUF -# define HAVE_GETGROUPS -# else /* !USE_BSD_UNIVERSE */ - /* Concurrent 7000 with RTU 6.1A using the ATT universe (`universe att') */ -# define M_OS "USG" -# define SYSDEP_CFLAGS -DHAVE_BCOPY -DHAVE_UID_T -DHAVE_GETDTABLESIZE -Dmc7000 -# define REQUIRED_LIBRARIES -ljobs -# define HAVE_VPRINTF -# define HAVE_GETGROUPS -# define HAVE_DUP2 -# define HAVE_DIRENT -# define HAVE_SYS_SIGLIST -# endif /* !USE_BSD_UNIVERSE */ -#endif /* concurrent */ - -/* **************************************************************** */ -/* */ -/* Honeywell Bull X20 (lele@idea.sublink.org) */ -/* */ -/* **************************************************************** */ -#if defined (hbullx20) -# define M_MACHINE "Honeywell" -# define M_OS "USG" -# define SYSDEP_CFLAGS -DUSG - /* Bull x20 needs -lposix for struct dirent. */ -# define REQUIRED_LIBRARIES -lPW -lposix -# define HAVE_DIRENT -# define HAVE_VFPRINTF -# define VOID_SIGHANDLER -# define USE_TERMCAP_EMULATION -# undef HAVE_GETWD -#endif /* hbullx20 */ - -/* ************************ */ -/* */ -/* CRAY */ -/* */ -/* ************************ */ -#if defined (cray) -# include -# if defined (Cray1) || defined (Cray2) -# define M_MACHINE "Cray" -# define CRAY_STACK -# endif -# if defined (CrayXMP) && !defined (M_MACHINE) -# define M_MACHINE "CrayXMP" -# define CRAY_STACK -DCRAY_STACKSEG_END=getb67 -# endif -# if defined (CrayYMP) && !defined (M_MACHINE) -# define M_MACHINE "CrayYMP" -# if RELEASE_LEVEL >= 7000 -# define CRAY_STACK -DCRAY_STACKSEG_END=_getb67 -# else -# define CRAY_STACK -DCRAY_STACKSEG_END=getb67 -# endif /* RELEASE_LEVEL < 7000 */ -# endif -# if !defined (M_MACHINE) -# define M_MACHINE "Cray" -# define CRAY_STACK -# endif -# define M_OS "Unicos" -# define SYSDEP_CFLAGS -DUSG -DPGRP_PIPE -DOPENDIR_NOT_ROBUST \ - -DHAVE_BCOPY CRAY_STACK -# define HAVE_VFPRINTF -# define HAVE_MULTIPLE_GROUPS -# define VOID_SIGHANDLER -# define USE_TERMCAP_EMULATION -# undef HAVE_ALLOCA -# undef HAVE_RESOURCE -# undef USE_GNU_MALLOC -#endif /* cray */ - -/* ************************ */ -/* */ -/* MagicStation */ -/* */ -/* ************************ */ -#if defined (MagicStation) -# define M_MACHINE "MagicStation" -# define M_OS "USG" -# define SYSDEP_CFLAGS -DUSGr4 -# define HAVE_DIRENT -# define HAVE_GETGROUPS -# define HAVE_STRERROR -# define VOID_SIGHANDLER -# undef HAVE_ALLOCA -# undef HAVE_GETWD -#endif /* MagicStation */ - -/* ************************ */ -/* */ -/* Plexus */ -/* */ -/* ************************ */ -#if defined (plexus) -# define M_MACHINE "plexus" -# define M_OS "USG" -# define REQUIRED_LIBRARIES -lndir -# define USE_TERMCAP_EMULATION -# undef HAVE_DUP2 -# undef HAVE_GETWD -# define HAVE_VFPRINTF -# undef HAVE_ALLOCA /* -lPW doesn't work w/bash-cc? */ -#endif /* plexus */ - -/* ************************ */ -/* */ -/* Siemens MX500 */ -/* (SINIX 5.2x) */ -/* ************************ */ -#ifdef sinix -#define M_MACHINE "Siemens MX500" -#define M_OS "SINIX V5.2x" -#define USG -#define HAVE_GETCWD -#define VOID_SIGHANDLER -#define HAVE_STRERROR -#define HAVE_GETGROUPS -#define HAVE_VFPRINTF -#define HAVE_POSIX_SIGNALS -#define HAVE_RESOURCE -#define USE_GNU_MALLOC -#define SYSDEP_CFLAGS -DUSGr3 -DUSG -#define REQUIRED_LIBRARIES syscalls.o -#undef HAVE_ALLOCA -#undef HAVE_GETWD -#endif /* sinix */ - -/* ************************ */ -/* */ -/* Symmetric 375 (4.2 BSD) */ -/* */ -/* ************************ */ -#if defined (scs) && !defined (M_MACHINE) -# define M_MACHINE "Symmetric_375" -# define M_OS "Bsd" -# define HAVE_SYS_SIGLIST -# define HAVE_GETGROUPS -# define HAVE_SETLINEBUF -# define USE_VFPRINTF_EMULATION -# define USE_GNU_MALLOC -# undef HAVE_STRCHR -#endif /* scs */ - -/* ************************ */ -/* */ -/* Tandem */ -/* */ -/* ************************ */ -/* I don't know what this is supposed to be (Greg Lehey, LEMIS, 29 May 1995). - * Tandem had two very different machines which ran SVR3: the LXN, based on - * a Motorola 68000, and the S2, based on a MIPS R3000. Both are obsolete - * (well, S2s should now be running NonStop UX version B, which is a flavour - * of SVR4). I'm leaving this here and will test for NonStop UX B with the - * preprocessor variable __nonstopux, which is set by the native compiler and - * should also be set by any other compiler, such as gcc (caveat portor: you'$ - * need to fix gcc config to to get this). */ -#if defined (tandem) && !defined (M_MACHINE) -# define M_MACHINE "tandem" -# define M_OS "USG" -# define SYSDEP_CFLAGS -DUSGr3 -# define HAVE_VFPRINTF -# define VOID_SIGHANDLER - /* Alloca requires either Gcc or cc with libPW.a */ -# if !defined (HAVE_GCC) -# define REQUIRED_LIBRARIES -lPW -# endif /* !HAVE_GCC */ -# undef HAVE_GETWD -#endif /* Tandem running SVR3 */ - -/* This is for NonStop UX Bxx, which is SVR4, but there's a very good - * chance it will trigger on NonStop UX Axx (SVR3). If this happens, - * fix it or upgrade your OS. */ -#if defined (mips) && defined (__nonstopux) /* Integrity, NonStop UX */ -# define M_MACHINE "Integrity" -# define M_OS "NonStop_UX" -# undef HAVE_GETWD -# define HAVE_DIRENT -# define HAVE_STRERROR -# define HAVE_VFPRINTF -# define VOID_SIGHANDLER -# define HAVE_SYS_SIGLIST -# define HAVE_SETLINEBUF -# define HAVE_GETGROUPS -# undef HAVE_ALLOCA -#endif - -/* ****************** */ -/* */ -/* Fujitsu UXP/M */ -/* */ -/* ****************** */ - -#if defined (__uxpm__) -# define M_MACHINE "VP" -# define M_OS "USG" -# define VOID_SIGHANDLER -# define HAVE_POSIX_SIGNALS -# define HAVE_VFPRINTF -# define HAVE_DIRENT -# define HAVE_SETVBUF -# define HAVE_STRCHR -# define HAVE_STRERROR -# define HAVE_GETGROUPS -# define HAVE_DUP2 -# undef HAVE_ALLOCA -# undef HAVE_GETWD -# define HAVE_GETCWD -# define HAVE_SYS_SIGLIST -# define NO_SBRK_DECL -# define SYSDEP_CFLAGS -DHAVE_UID_T -Dsys_siglist=_sys_siglist -DUSGr4 -# define EXTRA_LIB_SEARCH_PATH /usr/ucblib -# define REQUIRED_LIBRARIES -lc -lucb -#endif - -/* ****************** */ -/* */ -/* Amdahl UTS */ -/* */ -/* ****************** */ - -#if defined (UTS) && !defined (M_MACHINE) -# define M_MACHINE "uts" -# define M_OS "systemV" -# define SYSDEP_CFLAGS -DUSG -DMEMMOVE_MISSING -# define REQUIRED_LIBRARIES -# undef HAVE_SYS_SIGLIST -# undef HAVE_GETWD -# undef HAVE_ALLOCA -# define HAVE_VFPRINTF -# define HAVE_DIRENT -# undef HAVE_RESOURCE -#endif /* UTS */ - -/* ************************ */ -/* */ -/* Stratus i860 running FTX (jonathan@sybase.com (Jonathan Stockley)) */ -/* */ -/* ************************ */ -/* Use 'make CPP_DEFINES=-D_FTX' to build as /usr/ccs/lib/cpp doesn't set - anything other than i860 which may be set on other i860 machines. - The C compiler, cc, sets _FTX & i860 but, unfortunately it barfs at stuff - in cpp-Makefile that has a # in it (it has it's own builtin cpp). -*/ -#if defined(_FTX) && defined (i860) && !defined (M_MACHINE) -#define M_MACHINE "Stratus_i860" -#define M_OS "FTX" -#define VOID_SIGHANDLER -#define HAVE_POSIX_SIGNALS -#define HAVE_VFPRINTF -#define HAVE_SETVBUF -#define REVERSED_SETVBUF_ARGS -#define HAVE_STRCHR -#define HAVE_STRERROR -#define HAVE_GETGROUPS -#define HAVE_DUP2 -#undef HAVE_ALLOCA -#undef HAVE_GETWD -#define HAVE_GETCWD -#define HAVE_SYS_SIGLIST -#define SYSDEP_CFLAGS -DHAVE_UID_T -Dsys_siglist=_sys_siglist -DUSGr4 -#define EXTRA_LIB_SEARCH_PATH /usr/ucblib -#define REQUIRED_LIBRARIES -lc -lucb -#endif /* _FTX */ - -/* ************************ */ -/* */ -/* PCS Cadmus System */ -/* */ -/* ************************ */ -#if defined (cadmus) && !defined (M_MACHINE) -# define M_MACHINE "cadmus" -# define M_OS "BrainDeath" -# define SYSDEP_CFLAGS -DUSG -# define HAVE_DIRENT -# define HAVE_VFPRINTF -# define VOID_SIGHANDLER -# define USE_TERMCAP_EMULATION -# undef HAVE_GETWD -# undef HAVE_ALLOCA -# undef HAVE_WAIT_H -#endif /* cadmus */ - -/* **************************************************************** */ -/* */ -/* Generic Entry */ -/* */ -/* **************************************************************** */ - -/* Use this entry for your machine if it isn't represented here. It - is loosely based on a Vax running 4.3 BSD. */ - -#if !defined (M_MACHINE) -# define UNKNOWN_MACHINE -#endif - -#if defined (UNKNOWN_MACHINE) -# define M_MACHINE "UNKNOWN_MACHINE" -# define M_OS "UNKNOWN_OS" - -/* Required libraries for building on this system. */ -# define REQUIRED_LIBRARIES - -/* Define HAVE_SYS_SIGLIST if your system has sys_siglist[]. */ -# define HAVE_SYS_SIGLIST - -/* Undef HAVE_GETWD if your C library does not provide a working version - of getwd(). */ -/* # undef HAVE_GETWD */ - -/* Undef HAVE_GETCWD if your C library does not provide a working version - of getcwd(). */ -/* # undef HAVE_GETCWD */ - -/* Undef HAVE_ALLOCA if you are not using Gcc, and neither your library - nor compiler has a version of alloca (). In that case, we will use - our version of alloca () in alloca.c */ -/* # undef HAVE_ALLOCA */ - -/* Undef USE_GNU_MALLOC if there appear to be library conflicts, or if you - especially desire to use your OS's version of malloc () and friends. We - reccommend against this because GNU Malloc has debugging code built in. */ -/* # undef USE_GNU_MALLOC */ - -/* Define USE_GNU_TERMCAP if you want to use the GNU termcap library - instead of your system termcap library. */ -/* # define USE_GNU_TERMCAP */ - -/* Define HAVE_SETLINEBUF if your machine has the setlinebuf () - stream library call. Otherwise, setvbuf () will be used. If - neither of them work, you can edit in your own buffer control - based upon your machines capabilities. */ -# define HAVE_SETLINEBUF - -/* Define HAVE_VFPRINTF if your machines has the vfprintf () library - call. Otherwise, printf will be used. */ -# define HAVE_VFPRINTF - -/* Define USE_VFPRINTF_EMULATION if you want to use the BSD-compatible - vfprintf() emulation in vprint.c. */ -/* # define USE_VFPRINTF_EMULATION */ - -/* Define HAVE_GETGROUPS if your OS allows you to be in multiple - groups simultaneously by supporting the `getgroups' system call. */ -# define HAVE_GETGROUPS - -/* Define SYSDEP_CFLAGS to be the flags to cc that make your compiler - work. For example, `-ma' on the RT makes alloca () work. */ -/* This is a summary of the semi-machine-independent definitions that - can go into SYSDEP_CFLAGS: - - AFS - The Andrew File System is being used - AFS_CREATE_BUG - AFS has a bug with file creation if O_CREAT is - specified - BSD_GETPGRP - getpgrp(2) takes a pid argument, a la 4.3 BSD - HAVE_BCOPY - bcopy(3) exists and works as in BSD - HAVE_GETDTABLESIZE - getdtablesize(2) exists and works correctly - HAVE_GETHOSTNAME - gethostname(2) or gethostname(3) is present and - works as in BSD - HAVE_GETPW_DECLS - USG machines with the getpw* functions defined in - that cannot handle redefinitions in the - bash source - HAVE_RESOURCE - and [gs]rlimit exist and work - HAVE_SETDTABLESIZE - setdtablesize(2) exists and works correctly - HAVE_SOCKETS - this system has BSD sockets added to a System V base - HAVE_UID_T - Definitions for uid_t and gid_t are in - INT_GROUPS_ARRAY - the second argument to getgroups(3) is an array - of integers - MEMMOVE_MISSING - the system does not have memmove(3) - MKFIFO_MISSING - named pipes do not work or mkfifo(3) is missing - NO_SBRK_DECL - don't declare sbrk as extern char *sbrk() in - lib/malloc/malloc.c - OPENDIR_NOT_ROBUST - opendir(3) allows you to open non-directory files - PGRP_PIPE - Requires parent-child synchronization via pipes to - make job control work right - REVERSED_SETVBUF_ARGS - brain-damaged implementation of setvbuf that - has args 2 and 3 reversed from the SVID and - ANSI standard - RLOGIN_PGRP_BUG - processes started by rlogind have a process group - of 0 - TERMIOS_LDISC - system has a c_line line discipline member in struct - termios - TERMIOS_MISSING - the termios(3) functions are not present or don't - work, even though _POSIX_VERSION is defined - USG - The machine is running some sort of System V Unix - USGr3 - The machine is running SVR3.x - USGr4 - The machine is running SVR4 - USGr4_2 - The machine is running SVR4.2 -*/ -# define SYSDEP_CFLAGS - -/* Define HAVE_STRERROR if your system supplies a definition for strerror () - in the C library, or a macro in a header file. */ -/* # define HAVE_STRERROR */ - -/* Define HAVE_STRCASECMP if your system supplies definitions for the - casel-insensitive string comparison functions strcasecmp and strncasemp - in the C library or one of the system header files. */ -/* # define HAVE_STRCASECMP */ - -/* Define HAVE_DIRENT if you have the dirent library and a definition of - struct dirent. If not, the BSD directory reading library and struct - direct are assumed. */ -/* # define HAVE_DIRENT */ - -/* If your system does not supply /usr/lib/libtermcap.a, but includes - the termcap routines as a part of the curses library, then define - this. This is the case on some System V machines. */ -/* # define USE_TERMCAP_EMULATION */ - -/* Define VOID_SIGHANDLER if your system's signal () returns a pointer to - a function returning void. */ -/* # define VOID_SIGHANDLER */ - -/* Define EXTRA_LIB_SEARCH_PATH if your required libraries (or standard) - ones for that matter) are not normally in the ld search path. For - example, some machines require /usr/ucblib in the ld search path so - that they can use -lucb. */ -/* # define EXTRA_LIB_SEARCH_PATH /usr/ucblib */ - -/* Define SEARCH_LIB_NEEDS_SPACE if your native ld requires a space after - the -L argument, which gives the name of an alternate directory to search - for libraries specified with -llib. For example, the HPUX ld requires - this: - -L lib/readline -lreadline - instead of: - -Llib/readline -lreadline - */ -/* # define SEARCH_LIB_NEEDS_SPACE */ - -/* Define LD_HAS_NO_DASH_L if your ld can't grok the -L flag in any way, or - if it cannot grok the -l flag, or both. */ -/* # define LD_HAS_NO_DASH_L */ - -/* Define GCC_STANDARD if the standard `cc' is gcc and you don't want - to use the compiler named `gcc' for some reason. */ -/* # define GCC_STANDARD */ - -# if defined (LD_HAS_NO_DASH_L) -# undef SEARCH_LIB_NEEDS_SPACE -# endif /* LD_HAS_NO_DASH_L */ - -#endif /* UNKNOWN_MACHINE */ diff --git a/mailcheck.c b/mailcheck.c index 78f657d..1589012 100644 --- a/mailcheck.c +++ b/mailcheck.c @@ -18,14 +18,21 @@ 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, 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include "config.h" + #include #include "bashtypes.h" #include "posixstat.h" #include +#if defined (HAVE_UNISTD_H) +# include +#endif #include "bashansi.h" + #include "shell.h" #include "maxpath.h" #include "execute_cmd.h" +#include "mailcheck.h" #include #ifndef NOW @@ -34,27 +41,34 @@ Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ typedef struct { char *name; + char *msg; time_t access_time; time_t mod_time; long file_size; } FILEINFO; /* The list of remembered mail files. */ -FILEINFO **mailfiles = (FILEINFO **)NULL; +static FILEINFO **mailfiles = (FILEINFO **)NULL; /* Number of mail files that we have. */ -int mailfiles_count = 0; +static int mailfiles_count; /* The last known time that mail was checked. */ -int last_time_mail_checked = 0; +static int last_time_mail_checked; + +/* Non-zero means warn if a mail file has been read since last checked. */ +int mail_warning; /* Returns non-zero if it is time to check mail. */ int time_to_check_mail () { - char *temp = get_string_value ("MAILCHECK"); - time_t now = NOW; - long seconds = -1L; + char *temp; + time_t now; + long seconds; + + temp = get_string_value ("MAILCHECK"); + seconds = -1L; /* Skip leading whitespace in MAILCHECK. */ if (temp) @@ -70,9 +84,10 @@ time_to_check_mail () if (seconds < 0) return (0); + now = NOW; /* Time to check if MAILCHECK is explicitly set to zero, or if enough time has passed since the last check. */ - return (!seconds || ((now - last_time_mail_checked) >= seconds)); + return (seconds == 0 || ((now - last_time_mail_checked) >= seconds)); } /* Okay, we have checked the mail. Perhaps I should make this function @@ -92,17 +107,43 @@ find_mail_file (file) register int i; for (i = 0; i < mailfiles_count; i++) - if (STREQ ((mailfiles[i])->name, file)) + if (STREQ (mailfiles[i]->name, file)) return i; return -1; } +#define RESET_MAIL_FILE(i) \ + do \ + { \ + mailfiles[i]->access_time = mailfiles[i]->mod_time = 0; \ + mailfiles[i]->file_size = 0L; \ + } \ + while (0) + +static void +update_mail_file (i) + int i; +{ + char *file; + struct stat finfo; + + file = mailfiles[i]->name; + if (stat (file, &finfo) == 0) + { + mailfiles[i]->access_time = finfo.st_atime; + mailfiles[i]->mod_time = finfo.st_mtime; + mailfiles[i]->file_size = finfo.st_size; + } + else + RESET_MAIL_FILE (i); +} + /* Add this file to the list of remembered files and return its index in the list of mail files. */ static int -add_mail_file (file) - char *file; +add_mail_file (file, msg) + char *file, *msg; { struct stat finfo; char *filename; @@ -110,7 +151,7 @@ add_mail_file (file) filename = full_pathname (file); i = find_mail_file (file); - if (i > -1) + if (i >= 0) { if (stat (filename, &finfo) == 0) { @@ -128,17 +169,8 @@ add_mail_file (file) mailfiles[i] = (FILEINFO *)xmalloc (sizeof (FILEINFO)); mailfiles[i]->name = filename; - if (stat (filename, &finfo) == 0) - { - mailfiles[i]->access_time = finfo.st_atime; - mailfiles[i]->mod_time = finfo.st_mtime; - mailfiles[i]->file_size = finfo.st_size; - } - else - { - mailfiles[i]->access_time = mailfiles[i]->mod_time = (time_t)-1; - mailfiles[i]->file_size = -1L; - } + mailfiles[i]->msg = msg ? savestring (msg) : (char *)NULL; + update_mail_file (i); return i; } @@ -150,8 +182,7 @@ reset_mail_files () for (i = 0; i < mailfiles_count; i++) { - mailfiles[i]->access_time = mailfiles[i]->mod_time = 0; - mailfiles[i]->file_size = 0L; + RESET_MAIL_FILE (i); } } @@ -164,6 +195,7 @@ free_mail_files () for (i = 0; i < mailfiles_count; i++) { free (mailfiles[i]->name); + FREE (mailfiles[i]->msg); free (mailfiles[i]); } @@ -177,86 +209,55 @@ free_mail_files () /* Return non-zero if FILE's mod date has changed and it has not been accessed since modified. */ static int -file_mod_date_changed (file) - char *file; +file_mod_date_changed (i) + int i; { - time_t time = (time_t)0; + time_t mtime; struct stat finfo; - int i; + char *file; - i = find_mail_file (file); - if (i != -1) - time = mailfiles[i]->mod_time; + file = mailfiles[i]->name; + mtime = mailfiles[i]->mod_time; if ((stat (file, &finfo) == 0) && (finfo.st_size > 0)) - return (time != finfo.st_mtime); + return (mtime != finfo.st_mtime); return (0); } /* Return non-zero if FILE's access date has changed. */ static int -file_access_date_changed (file) - char *file; +file_access_date_changed (i) + int i; { - time_t time = (time_t)0; + time_t atime; struct stat finfo; - int i; + char *file; - i = find_mail_file (file); - if (i != -1) - time = mailfiles[i]->access_time; + file = mailfiles[i]->name; + atime = mailfiles[i]->access_time; if ((stat (file, &finfo) == 0) && (finfo.st_size > 0)) - return (time != finfo.st_atime); + return (atime != finfo.st_atime); return (0); } /* Return non-zero if FILE's size has increased. */ static int -file_has_grown (file) - char *file; +file_has_grown (i) + int i; { - long size = 0L; + long size; struct stat finfo; - int i; + char *file; - i = find_mail_file (file); - if (i != -1) - size = mailfiles[i]->file_size; + file = mailfiles[i]->name; + size = mailfiles[i]->file_size; return ((stat (file, &finfo) == 0) && (finfo.st_size > size)); } -char * -make_default_mailpath () -{ - char *mp; - - mp = xmalloc (1 + sizeof (DEFAULT_MAIL_PATH) + strlen (current_user.user_name)); - strcpy (mp, DEFAULT_MAIL_PATH); - strcpy (mp + sizeof (DEFAULT_MAIL_PATH) - 1, current_user.user_name); - return (mp); -} - -/* Return the colon separated list of pathnames to check for mail. */ -static char * -get_mailpaths () -{ - char *mailpaths; - - mailpaths = get_string_value ("MAILPATH"); - - if (!mailpaths) - mailpaths = get_string_value ("MAIL"); - - if (mailpaths) - return (savestring (mailpaths)); - - return (make_default_mailpath ()); -} - /* Take an element from $MAILPATH and return the portion from the first unquoted `?' or `%' to the end of the string. This is the message to be printed when the file contents change. */ @@ -284,7 +285,18 @@ parse_mailpath_spec (str) } return ((char *)NULL); } - + +char * +make_default_mailpath () +{ + char *mp; + + mp = xmalloc (1 + sizeof (DEFAULT_MAIL_DIRECTORY) + strlen (current_user.user_name)); + strcpy (mp, DEFAULT_MAIL_DIRECTORY); + strcpy (mp + sizeof (DEFAULT_MAIL_DIRECTORY) - 1, current_user.user_name); + return (mp); +} + /* Remember the dates of the files specified by MAILPATH, or if there is no MAILPATH, by the file specified in MAIL. If neither exists, use a default value, which we randomly concoct from using Unix. */ @@ -295,16 +307,31 @@ remember_mail_dates () char *mailfile, *mp; int i = 0; - mailpaths = get_mailpaths (); + mailpaths = get_string_value ("MAILPATH"); + + /* If no $MAILPATH, but $MAIL, use that as a single filename to check. */ + if (mailpaths == 0 && (mailpaths = get_string_value ("MAIL"))) + { + add_mail_file (mailpaths, (char *)NULL); + return; + } + + if (mailpaths == 0) + { + mailpaths = make_default_mailpath (); + add_mail_file (mailpaths, (char *)NULL); + free (mailpaths); + return; + } + while (mailfile = extract_colon_unit (mailpaths, &i)) { mp = parse_mailpath_spec (mailfile); if (mp && *mp) - *mp = '\0'; - add_mail_file (mailfile); + *mp++ = '\0'; + add_mail_file (mailfile, mp); free (mailfile); } - free (mailpaths); } /* check_mail () is useful for more than just checking mail. Since it has @@ -316,65 +343,45 @@ remember_mail_dates () /* Check for mail in some files. If the modification date of any of the files in MAILPATH has changed since we last did a remember_mail_dates () then mention that the user has mail. - Special hack: If the shell variable MAIL_WARNING is on and the + Special hack: If the variable MAIL_WARNING is non-zero and the mail file has been accessed since the last time we remembered, then the message "The mail in has been read" is printed. */ void check_mail () { - char *current_mail_file, *you_have_mail_message; - char *mailpaths, *mp; - int file_index = 0; - char *dollar_underscore; + char *current_mail_file, *message; + int i, use_user_notification; + char *dollar_underscore, *temp; + WORD_LIST *tlist; dollar_underscore = get_string_value ("_"); - if (dollar_underscore) dollar_underscore = savestring (dollar_underscore); - mailpaths = get_mailpaths (); - while ((current_mail_file = extract_colon_unit (mailpaths, &file_index))) + for (i = 0; i < mailfiles_count; i++) { - char *t; - int use_user_notification; - - if (!*current_mail_file) - { - free (current_mail_file); - continue; - } + current_mail_file = mailfiles[i]->name; - t = full_pathname (current_mail_file); - free (current_mail_file); - current_mail_file = t; + if (*current_mail_file == '\0') + continue; - use_user_notification = 0; - you_have_mail_message = "You have mail in $_"; - - mp = parse_mailpath_spec (current_mail_file); - if (mp && *mp) + if (file_mod_date_changed (i)) { - *mp = '\0'; - you_have_mail_message = ++mp; - use_user_notification++; - } + int file_is_bigger; + + use_user_notification = mailfiles[i]->msg != (char *)NULL; + message = mailfiles[i]->msg ? mailfiles[i]->msg : "You have mail in $_"; - if (file_mod_date_changed (current_mail_file)) - { - WORD_LIST *tlist; - int i, file_is_bigger; bind_variable ("_", current_mail_file); + #define atime mailfiles[i]->access_time #define mtime mailfiles[i]->mod_time - /* Have to compute this before the call to add_mail_file, which + /* Have to compute this before the call to update_mail_file, which resets all the information. */ - file_is_bigger = file_has_grown (current_mail_file); - - i = add_mail_file (current_mail_file); + file_is_bigger = file_has_grown (i); - if (i == -1) - continue; /* if this returns -1 , it is a bug */ + update_mail_file (i); /* If the user has just run a program which manipulates the mail file, then don't bother explaining that the mail @@ -383,39 +390,32 @@ check_mail () the mail in the file is manipulated, check the size also. If the file has not grown, continue. */ if ((atime >= mtime) && !file_is_bigger) - { - free (current_mail_file); - continue; - } + continue; /* If the mod time is later than the access time and the file has grown, note the fact that this is *new* mail. */ - if (!use_user_notification && (atime < mtime) && file_is_bigger) - you_have_mail_message = "You have new mail in $_"; + if (use_user_notification == 0 && (atime < mtime) && file_is_bigger) + message = "You have new mail in $_"; #undef atime #undef mtime - if ((tlist = expand_string (you_have_mail_message, 1))) + if ((tlist = expand_string (message, Q_DOUBLE_QUOTES))) { - char *tem = string_list (tlist); - printf ("%s\n", tem); - free (tem); + temp = string_list (tlist); + puts (temp); + free (temp); dispose_words (tlist); } else - printf ("\n"); + putchar ('\n'); } - if (find_variable ("MAIL_WARNING") && - file_access_date_changed (current_mail_file)) + if (mail_warning && file_access_date_changed (i)) { - add_mail_file (current_mail_file); - printf ("The mail in %s has been read!\n", current_mail_file); + update_mail_file (i); + printf ("The mail in %s has been read\n", current_mail_file); } - - free (current_mail_file); } - free (mailpaths); if (dollar_underscore) { diff --git a/mailcheck.h b/mailcheck.h new file mode 100644 index 0000000..9c4032f --- /dev/null +++ b/mailcheck.h @@ -0,0 +1,33 @@ +/* mailcheck.h -- variables and function declarations for mail checking. */ + +/* Copyright (C) 1987,1991 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 1, 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, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#if !defined (_MAILCHECK_H_) +#define _MAILCHECK_H_ + +/* Functions from mailcheck.c */ +extern int time_to_check_mail __P((void)); +extern void reset_mail_timer __P((void)); +extern void reset_mail_files __P((void)); +extern void free_mail_files __P((void)); +extern char *make_default_mailpath __P((void)); +extern void remember_mail_dates __P((void)); +extern void check_mail __P((void)); + +#endif /* _MAILCHECK_H */ diff --git a/make_cmd.c b/make_cmd.c index 85eb3d5..d17b4d8 100644 --- a/make_cmd.c +++ b/make_cmd.c @@ -1,5 +1,5 @@ -/* make_cmd.c -- - Functions for making instances of the various parser constructs. */ +/* make_cmd.c -- Functions for making instances of the various + parser constructs. */ /* Copyright (C) 1989 Free Software Foundation, Inc. @@ -19,17 +19,23 @@ 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, 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include "config.h" + #include #include "bashtypes.h" #include #include "filecntl.h" #include "bashansi.h" -#include "config.h" +#if defined (HAVE_UNISTD_H) +# include +#endif + #include "command.h" #include "general.h" #include "error.h" #include "flags.h" #include "make_cmd.h" +#include "variables.h" #include "subst.h" #include "input.h" #include "externs.h" @@ -42,47 +48,59 @@ extern int line_number, current_command_line_count; extern int disallow_filename_globbing; WORD_DESC * -make_word (string) +make_bare_word (string) char *string; { WORD_DESC *temp; temp = (WORD_DESC *)xmalloc (sizeof (WORD_DESC)); - temp->word = savestring (string); - temp->quoted = temp->dollar_present = temp->assignment = 0; - - while (*string) + if (*string) + temp->word = savestring (string); + else { - if (*string == '$') temp->dollar_present = 1; - -#ifdef OLDCODE - if (member (*string, "'`\\\"")) - { - temp->quoted = 1; - if (*string == '\\') - string++; - } -#else - switch (*string) - { - case '\\': - string++; - /*FALLTHROUGH*/ - case '\'': - case '`': - case '"': - temp->quoted = 1; - break; - } -#endif - - if (*string) - (string++); + temp->word = xmalloc (1); + temp->word[0] = '\0'; } + + temp->flags = 0; return (temp); } WORD_DESC * +make_word_flags (w, string) + WORD_DESC *w; + char *string; +{ + register char *s; + + for (s = string; *s; s++) + switch (*s) + { + case '$': + w->flags |= W_HASDOLLAR; + break; + case '\\': + break; /* continue the loop */ + case '\'': + case '`': + case '"': + w->flags |= W_QUOTED; + break; + } + return (w); +} + +WORD_DESC * +make_word (string) + char *string; +{ + WORD_DESC *temp; + + temp = make_bare_word (string); + return (make_word_flags (temp, string)); +} + +WORD_DESC * make_word_from_token (token) int token; { @@ -112,24 +130,14 @@ add_string_to_list (string, list) char *string; WORD_LIST *list; { - WORD_LIST *temp = (WORD_LIST *)xmalloc (sizeof (WORD_LIST)); + WORD_LIST *temp; + + temp = (WORD_LIST *)xmalloc (sizeof (WORD_LIST)); temp->word = make_word (string); temp->next = list; return (temp); } -#if 0 -WORD_DESC * -coerce_to_word (number) - int number; -{ - char string[24]; - - sprintf (string, "%d", number); - return (make_word (string)); -} -#endif - COMMAND * make_command (type, pointer) enum command_type type; @@ -140,8 +148,7 @@ make_command (type, pointer) temp = (COMMAND *)xmalloc (sizeof (COMMAND)); temp->type = type; temp->value.Simple = pointer; - temp->value.Simple->flags = 0; - temp->flags = 0; + temp->value.Simple->flags = temp->flags = 0; temp->redirects = (REDIRECT *)NULL; return (temp); } @@ -160,44 +167,50 @@ command_connect (com1, com2, connector) return (make_command (cm_connection, (SIMPLE_COM *)temp)); } -COMMAND * -make_for_command (name, map_list, action) +static COMMAND * +make_for_or_select (type, name, map_list, action) + enum command_type type; WORD_DESC *name; WORD_LIST *map_list; COMMAND *action; { - FOR_COM *temp = (FOR_COM *)xmalloc (sizeof (FOR_COM)); + FOR_COM *temp; + temp = (FOR_COM *)xmalloc (sizeof (FOR_COM)); temp->flags = 0; temp->name = name; temp->map_list = map_list; temp->action = action; - return (make_command (cm_for, (SIMPLE_COM *)temp)); + return (make_command (type, (SIMPLE_COM *)temp)); } -#if defined (SELECT_COMMAND) COMMAND * -make_select_command (name, map_list, action) +make_for_command (name, map_list, action) WORD_DESC *name; WORD_LIST *map_list; COMMAND *action; { - SELECT_COM *temp = (SELECT_COM *)xmalloc (sizeof (SELECT_COM)); - - temp->flags = 0; - temp->name = name; - temp->map_list = map_list; - temp->action = action; - return (make_command (cm_select, (SIMPLE_COM *)temp)); + return (make_for_or_select (cm_for, name, map_list, action)); } + +COMMAND * +make_select_command (name, map_list, action) + WORD_DESC *name; + WORD_LIST *map_list; + COMMAND *action; +{ +#if defined (SELECT_COMMAND) + return (make_for_or_select (cm_select, name, map_list, action)); #endif +} COMMAND * make_group_command (command) COMMAND *command; { - GROUP_COM *temp = (GROUP_COM *)xmalloc (sizeof (GROUP_COM)); + GROUP_COM *temp; + temp = (GROUP_COM *)xmalloc (sizeof (GROUP_COM)); temp->command = command; return (make_command (cm_group, (SIMPLE_COM *)temp)); } @@ -245,9 +258,9 @@ make_if_command (test, true_case, false_case) } static COMMAND * -make_until_or_while (test, action, which) - COMMAND *test, *action; +make_until_or_while (which, test, action) enum command_type which; + COMMAND *test, *action; { WHILE_COM *temp; @@ -262,31 +275,34 @@ COMMAND * make_while_command (test, action) COMMAND *test, *action; { - return (make_until_or_while (test, action, cm_while)); + return (make_until_or_while (cm_while, test, action)); } COMMAND * make_until_command (test, action) COMMAND *test, *action; { - return (make_until_or_while (test, action, cm_until)); + return (make_until_or_while (cm_until, test, action)); } COMMAND * make_bare_simple_command () { COMMAND *command; - SIMPLE_COM *temp = (SIMPLE_COM *)xmalloc (sizeof (SIMPLE_COM)); + SIMPLE_COM *temp; + + command = (COMMAND *)xmalloc (sizeof (COMMAND)); + command->value.Simple = temp = (SIMPLE_COM *)xmalloc (sizeof (SIMPLE_COM)); temp->flags = 0; temp->line = line_number; temp->words = (WORD_LIST *)NULL; temp->redirects = (REDIRECT *)NULL; - command = (COMMAND *)xmalloc (sizeof (COMMAND)); + command->type = cm_simple; command->redirects = (REDIRECT *)NULL; command->flags = 0; - command->value.Simple = temp; + return (command); } @@ -302,7 +318,7 @@ make_simple_command (element, command) malloc doesn't return zeroed space. */ if (!command) command = make_bare_simple_command (); - + if (element.word) { WORD_LIST *tw = (WORD_LIST *)xmalloc (sizeof (WORD_LIST)); @@ -324,127 +340,112 @@ make_simple_command (element, command) return (command); } -#define POSIX_HERE_DOCUMENTS +/* Because we are Bourne compatible, we read the input for this + << or <<- redirection now, from wherever input is coming from. + We store the input read into a WORD_DESC. Replace the text of + the redirectee.word with the new input text. If <<- is on, + then remove leading TABS from each line. */ void make_here_document (temp) REDIRECT *temp; { - int kill_leading = 0; + int kill_leading, redir_len; + char *redir_word, *document, *full_line; + int document_index, document_size, delim_unquoted; + + if (temp->instruction != r_deblank_reading_until && + temp->instruction != r_reading_until) + { + internal_error ("make_here_document: bad instruction type %d", temp->instruction); + return; + } + + kill_leading = temp->instruction == r_deblank_reading_until; + + document = (char *)NULL; + document_index = document_size = 0; + + /* Quote removal is the only expansion performed on the delimiter + for here documents, making it an extremely special case. */ + redir_word = string_quote_removal (temp->redirectee.filename->word, 0); + + /* redirection_expand will return NULL if the expansion results in + multiple words or no words. Check for that here, and just abort + this here document if it does. */ + if (redir_word) + redir_len = strlen (redir_word); + else + { + temp->here_doc_eof = xmalloc (1); + temp->here_doc_eof[0] = '\0'; + goto document_done; + } - switch (temp->instruction) + free (temp->redirectee.filename->word); + temp->here_doc_eof = redir_word; + + /* Read lines from wherever lines are coming from. + For each line read, if kill_leading, then kill the + leading tab characters. + If the line matches redir_word exactly, then we have + manufactured the document. Otherwise, add the line to the + list of lines in the document. */ + + /* If the here-document delimiter was quoted, the lines should + be read verbatim from the input. If it was not quoted, we + need to perform backslash-quoted newline removal. */ + delim_unquoted = (temp->redirectee.filename->flags & W_QUOTED) == 0; + while (full_line = read_secondary_line (delim_unquoted)) { - /* Because we are Bourne compatible, we read the input for this - << or <<- redirection now, from wherever input is coming from. - We store the input read into a WORD_DESC. Replace the text of - the redirectee.word with the new input text. If <<- is on, - then remove leading TABS from each line. */ - - case r_deblank_reading_until: /* <<-foo */ - kill_leading++; - /* FALLTHROUGH */ - case r_reading_until: /* <= document_size) { - char *redir_word; - int redir_len; - char *full_line; - char *document = (char *)NULL; - int document_index = 0, document_size = 0; - -#if !defined (POSIX_HERE_DOCUMENTS) - /* Because of Bourne shell semantics, we turn off globbing, but - only for this style of redirection. I feel a little ill. */ - { - int old_value = disallow_filename_globbing; - disallow_filename_globbing = 1; - - redir_word = redirection_expand (temp->redirectee.filename); - - disallow_filename_globbing = old_value; - } -#else /* POSIX_HERE_DOCUMENTS */ - /* Quote removal is the only expansion performed on the delimiter - for here documents, making it an extremely special case. I - still feel ill. */ - redir_word = string_quote_removal (temp->redirectee.filename->word, 0); -#endif /* POSIX_HERE_DOCUMENTS */ - - /* redirection_expand will return NULL if the expansion results in - multiple words or no words. Check for that here, and just abort - this here document if it does. */ - if (redir_word) - redir_len = strlen (redir_word); - else - { - temp->here_doc_eof = savestring (""); - goto document_done; - } - - free (temp->redirectee.filename->word); - temp->here_doc_eof = redir_word; - - /* Read lines from wherever lines are coming from. - For each line read, if kill_leading, then kill the - leading tab characters. - If the line matches redir_word exactly, then we have - manufactured the document. Otherwise, add the line to the - list of lines in the document. */ - - /* If the here-document delimiter was quoted, the lines should - be read verbatim from the input. If it was not quoted, we - need to perform backslash-quoted newline removal. */ - while (full_line = read_secondary_line - (temp->redirectee.filename->quoted == 0)) - { - register char *line = full_line; - int len; - - line_number++; - - if (kill_leading && *line) - { - /* Hack: To be compatible with some Bourne shells, we - check the word before stripping the whitespace. This - is a hack, though. */ - if (STREQN (line, redir_word, redir_len) && - line[redir_len] == '\n') - goto document_done; - - while (*line == '\t') - line++; - } - - if (!*line) - continue; - - if (STREQN (line, redir_word, redir_len) && - line[redir_len] == '\n') - goto document_done; - - len = strlen (line); - if (len + document_index >= document_size) - { - document_size = document_size ? 2 * (document_size + len) - : 1000; /* XXX */ - document = xrealloc (document, document_size); - } - - /* len is guaranteed to be > 0 because of the check for line - being an empty string before the call to strlen. */ - FASTCOPY (line, document + document_index, len); - document_index += len; - } - - document_done: - if (document) - document[document_index] = '\0'; - else - document = savestring (""); - temp->redirectee.filename->word = document; + document_size = document_size ? 2 * (document_size + len) : 1000; + document = xrealloc (document, document_size); } + + /* len is guaranteed to be > 0 because of the check for line + being an empty string before the call to strlen. */ + FASTCOPY (line, document + document_index, len); + document_index += len; + } + +document_done: + if (document) + document[document_index] = '\0'; + else + { + document = xmalloc (1); + document[0] = '\0'; } + temp->redirectee.filename->word = document; } - -/* Generate a REDIRECT from SOURCE, DEST, and INSTRUCTION. + +/* Generate a REDIRECT from SOURCE, DEST, and INSTRUCTION. INSTRUCTION is the instruction type, SOURCE is a file descriptor, and DEST is a file descriptor or a WORD_DESC *. */ REDIRECT * @@ -483,13 +484,13 @@ make_redirection (source, instruction, dest_and_filename) case r_reading_until: /* << foo */ break; + case r_close_this: /* <&- */ case r_duplicating_input: /* 1<&2 */ case r_duplicating_output: /* 1>&2 */ - case r_close_this: /* <&- */ case r_duplicating_input_word: /* 1<&$foo */ case r_duplicating_output_word: /* 1>&$foo */ break; - + case r_err_and_out: /* command &>filename */ temp->flags = O_TRUNC | O_WRONLY | O_CREAT; break; @@ -499,8 +500,7 @@ make_redirection (source, instruction, dest_and_filename) break; default: - programming_error ("Redirection instruction from yyparse () '%d' is\n\ -out of range in make_redirection ().", instruction); + programming_error ("make_redirection: redirection instruction `%d' out of range", instruction); abort (); break; } @@ -508,16 +508,19 @@ out of range in make_redirection ().", instruction); } COMMAND * -make_function_def (name, command) +make_function_def (name, command, lineno, lstart) WORD_DESC *name; COMMAND *command; + int lineno, lstart; { FUNCTION_DEF *temp; temp = (FUNCTION_DEF *)xmalloc (sizeof (FUNCTION_DEF)); temp->command = command; temp->name = name; - command->line = line_number - current_command_line_count + 1; + temp->line = lineno; + temp->ignore = 0; + command->line = lstart; return (make_command (cm_function_def, (SIMPLE_COM *)temp)); } @@ -529,42 +532,18 @@ clean_simple_command (command) COMMAND *command; { if (command->type != cm_simple) - { - programming_error - ("clean_simple_command () got a command with type %d.", command->type); - } + programming_error ("clean_simple_command: bad command type `%d'", command->type); else { command->value.Simple->words = REVERSE_LIST (command->value.Simple->words, WORD_LIST *); - command->value.Simple->redirects = + command->value.Simple->redirects = REVERSE_LIST (command->value.Simple->redirects, REDIRECT *); } return (command); } -/* Cons up a new array of words. The words are taken from LIST, - which is a WORD_LIST *. Absolutely everything is malloc'ed, - so you should free everything in this array when you are done. - The array is NULL terminated. */ -char ** -make_word_array (list) - WORD_LIST *list; -{ - int count = list_length (list); - char **array = (char **)xmalloc ((1 + count) * sizeof (char *)); - - for (count = 0; list; count++) - { - array[count] = xmalloc (1 + strlen (list->word->word)); - strcpy (array[count], list->word->word); - list = list->next; - } - array[count] = (char *)NULL; - return (array); -} - /* The Yacc grammar productions have a problem, in that they take a list followed by an ampersand (`&') and do a simple command connection, making the entire list effectively asynchronous, instead of just diff --git a/make_cmd.h b/make_cmd.h index 2118770..0a21177 100644 --- a/make_cmd.h +++ b/make_cmd.h @@ -26,6 +26,7 @@ extern WORD_LIST *make_word_list __P((WORD_DESC *, WORD_LIST *)); extern WORD_LIST *add_string_to_list __P((char *, WORD_LIST *)); +extern WORD_DESC *make_bare_word __P((char *)); extern WORD_DESC *make_word __P((char *)); extern WORD_DESC *make_word_from_token __P((int)); @@ -42,13 +43,10 @@ extern COMMAND *make_bare_simple_command __P((void)); extern COMMAND *make_simple_command __P((ELEMENT, COMMAND *)); extern void make_here_document __P((REDIRECT *)); extern REDIRECT *make_redirection __P((int, enum r_instruction, REDIRECTEE)); -extern COMMAND *make_function_def __P((WORD_DESC *, COMMAND *)); +extern COMMAND *make_function_def __P((WORD_DESC *, COMMAND *, int, int)); extern COMMAND *clean_simple_command __P((COMMAND *)); -extern char **make_word_array __P((WORD_LIST *)); -#if defined (SELECT_COMMAND) extern COMMAND *make_select_command __P((WORD_DESC *, WORD_LIST *, COMMAND *)); -#endif extern COMMAND *connect_async_list __P((COMMAND *, COMMAND *, int)); diff --git a/maxpath.h b/maxpath.h index 6677309..be0db2f 100644 --- a/maxpath.h +++ b/maxpath.h @@ -1,4 +1,4 @@ -/* maxpath.h - Find out what this system thinks MAXPATHLEN is. */ +/* maxpath.h - Find out what this system thinks PATH_MAX and NAME_MAX are. */ /* Copyright (C) 1993 Free Software Foundation, Inc. @@ -18,26 +18,58 @@ with Bash; see the file COPYING. If not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ -#if !defined (_MAXPATH_H) -#define _MAXPATH_H +#if !defined (_MAXPATH_H_) +#define _MAXPATH_H_ -#if !defined (MAXPATHLEN) && defined (HAVE_LIMITS_H) -# if !defined (BUILDING_MAKEFILE) -# include -# endif /* BUILDING_MAKEFILE */ -#endif /* !MAXPATHLEN && HAVE_LIMITS_H */ +/* These values are supposed to be in or one of the files + it includes. */ +#if defined (HAVE_LIMITS_H) +# include +#endif /* !HAVE_LIMITS_H */ -#if !defined (MAXPATHLEN) && defined (HAVE_SYS_PARAM) -# include -#endif /* !MAXPATHLEN && HAVE_SYS_PARAM */ +/* If PATH_MAX is not defined, look for MAXPATHLEN */ +#if !defined (PATH_MAX) +# if defined (HAVE_SYS_PARAM_H) +# include +# define maxpath_param_h +# endif +# if defined (MAXPATHLEN) && !defined (PATH_MAX) +# define PATH_MAX MAXPATHLEN +# endif /* MAXPATHLEN && !PATH_MAX */ +#endif /* !PATH_MAX */ -#if !defined (MAXPATHLEN) && defined (PATH_MAX) -# define MAXPATHLEN PATH_MAX -#endif /* !MAXPATHLEN && PATH_MAX */ +/* If NAME_MAX is not defined, look for MAXNAMLEN */ +#if !defined (NAME_MAX) +# if defined (HAVE_SYS_PARAM_H) && !defined (maxpath_param_h) +# include +# endif +# if defined (MAXNAMLEN) && !defined (NAME_MAX) +# define NAME_MAX MAXNAMLEN +# endif /* MAXNAMLEN && !NAME_MAX */ +#endif /* !NAME_MAX */ -/* Yecch! Who cares about this gross concept in the first place? */ -#if !defined (MAXPATHLEN) -# define MAXPATHLEN 1024 -#endif /* MAXPATHLEN */ +/* Default POSIX values */ +#if !defined (PATH_MAX) && defined (_POSIX_PATH_MAX) +# define PATH_MAX _POSIX_PATH_MAX +#endif -#endif /* _MAXPATH_H */ +#if !defined (NAME_MAX) && defined (_POSIX_NAME_MAX) +# define NAME_MAX _POSIX_NAME_MAX +#endif + + +/* Default values */ +#if !defined (PATH_MAX) +# define PATH_MAX 1024 +#endif + +#if !defined (NAME_MAX) +# define NAME_MAX 14 +#endif + +#if PATH_MAX < 1024 +# undef PATH_MAX +# define PATH_MAX 1024 +#endif + +#endif /* _MAXPATH_H_ */ diff --git a/memalloc.h b/memalloc.h index 92c0648..ba210bb 100644 --- a/memalloc.h +++ b/memalloc.h @@ -19,8 +19,8 @@ with Bash; see the file COPYING. If not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ -#if !defined (__MEMALLOC_H__) -# define __MEMALLOC_H__ +#if !defined (_MEMALLOC_H_) +# define _MEMALLOC_H_ #if defined (sparc) && defined (sun) && !defined (HAVE_ALLOCA_H) # define HAVE_ALLOCA_H @@ -34,8 +34,6 @@ # define HAVE_ALLOCA #endif /* HAVE_ALLOCA_H && !HAVE_ALLOCA */ -#if !defined (BUILDING_MAKEFILE) - #if defined (__GNUC__) # undef alloca # define alloca __builtin_alloca @@ -46,15 +44,15 @@ # else /* !IBMESA */ # include # endif /* !IBMESA */ -# else -# if defined (hpux_9) && defined (__STDC__) +# else /* !HAVE_ALLOCA_H */ +# if defined (hpux_9) && defined (__STDC__) && !defined (alloca) extern void *alloca (); # else +# if !defined (alloca) extern char *alloca (); -# endif +# endif /* !alloca */ +# endif /* !hpux_9 || !__STDC__ && !alloca */ # endif /* !HAVE_ALLOCA_H */ #endif /* !__GNUC__ */ -#endif /* !BUILDING_MAKEFILE */ - -#endif /* __MEMALLOC_H__ */ +#endif /* _MEMALLOC_H_ */ diff --git a/nojobs.c b/nojobs.c index e5e8d2c..c203ce8 100644 --- a/nojobs.c +++ b/nojobs.c @@ -1,6 +1,7 @@ /* The thing that makes children, remembers them, and contains wait loops. */ -/* This file works under BSD, System V, minix, and Posix systems. */ +/* This file works under BSD, System V, minix, and Posix systems. It does + not implement job control. */ /* Copyright (C) 1987, 1989, 1992 Free Software Foundation, Inc. @@ -20,54 +21,65 @@ with Bash; see the file COPYING. If not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include +#include "config.h" + #include "bashtypes.h" +#include "filecntl.h" + +#if defined (HAVE_UNISTD_H) +# include +#endif + +#include #include -#include #include -#include "config.h" +#include "bashjmp.h" + #include "command.h" #include "general.h" -#include "filecntl.h" #include "jobs.h" #include "externs.h" +#include "sig.h" #include "error.h" +#include "bashtty.h" #if defined (BUFFERED_INPUT) # include "input.h" #endif -#if !defined (USG) && !defined (_POSIX_VERSION) -# include +#if defined (TERMIOS_TTY_DRIVER) +# include #else -# if defined (_POSIX_VERSION) -# include -# else +# if defined (TERMIO_TTY_DRIVER) # include -# if !defined (AIXRT) -# include -# endif /* !AIXRT */ -# endif /* !POSIX_VERSION */ -#endif /* USG && _POSIX_VERSION */ - -#if !defined (SIGABRT) -# define SIGABRT SIGIOT -#endif /* !SIGABRT */ +# else +# include +# endif /* !TERMIO_TTY_DRIVER */ +#endif /* TERMIOS_TTY_DRIVER */ + +/* For struct winsize on SCO */ +/* sys/ptem.h has winsize but needs mblk_t from sys/stream.h */ +#if defined (HAVE_SYS_PTEM_H) && defined (TIOCGWINSZ) && defined (SIGWINCH) +# if defined (HAVE_SYS_STREAM_H) +# include +# endif +# include +#endif -#if defined (USG) || defined (_POSIX_VERSION) +#if defined (_POSIX_VERSION) || !defined (HAVE_KILLPG) # define killpg(pg, sig) kill(-(pg),(sig)) #endif /* USG || _POSIX_VERSION */ -#if defined (USG) +#if !defined (HAVE_SIGINTERRUPT) # define siginterrupt(sig, code) #endif /* USG */ -#if defined (_POSIX_VERSION) +#if defined (HAVE_WAITPID) # define WAITPID(pid, statusp, options) waitpid (pid, statusp, options) #else # define WAITPID(pid, statusp, options) wait (statusp) -#endif /* !_POSIX_VERSION */ +#endif /* !HAVE_WAITPID */ #if !defined (errno) extern int errno; @@ -76,7 +88,7 @@ extern int errno; extern int interactive, interactive_shell, login_shell; extern int subshell_environment; extern int last_command_exit_value; -#if defined (_POSIX_VERSION) +#if defined (HAVE_POSIX_SIGNALS) extern sigset_t top_level_mask; #endif @@ -86,7 +98,11 @@ pid_t last_asynchronous_pid = NO_PID; /* Call this when you start making children. */ int already_making_children = 0; -#if defined (_POSIX_VERSION) +/* If this is non-zero, $LINES and $COLUMNS are reset after every process + exits from get_tty_state(). */ +int check_window_size; + +#if defined (HAVE_WAITPID) static void reap_zombie_children (); #endif @@ -96,7 +112,7 @@ struct proc_status { }; static struct proc_status *pid_list = (struct proc_status *)NULL; -static int pid_list_size = 0; +static int pid_list_size; #define PROC_BAD -1 #define PROC_STILL_ALIVE -2 @@ -114,7 +130,7 @@ alloc_pid_list () /* None of the newly allocated slots have process id's yet. */ for (i = old; i < pid_list_size; i++) - pid_list[i].pid = NO_PID; + pid_list[i].pid = NO_PID; } /* Return the offset within the PID_LIST array of an empty slot. This can @@ -197,7 +213,7 @@ cleanup_dead_jobs () { register int i; -#if defined (_POSIX_VERSION) +#if defined (HAVE_WAITPID) reap_zombie_children (); #endif @@ -212,46 +228,78 @@ initialize_jobs () get_tty_state (); } -#if !defined (READLINE) && defined (TIOCGWINSZ) && defined (SIGWINCH) -static SigHandler *old_winch; +#if defined (TIOCGWINSZ) && defined (SIGWINCH) +static SigHandler *old_winch = (SigHandler *)SIG_DFL; + +static void +get_new_window_size (from_sig) + int from_sig; +{ + struct winsize win; + int tty; + + tty = open ("/dev/tty", O_RDONLY); + if (tty >= 0 && (ioctl (tty, TIOCGWINSZ, &win) == 0) && + win.ws_row > 0 && win.ws_col > 0) + { +#if defined (aixpc) + shell_tty_info.c_winsize = win; /* structure copying */ +#endif + set_lines_and_columns (win.ws_row, win.ws_col); +#if defined (READLINE) + _rl_set_screen_size (win.ws_row, win.ws_col); +#endif + } + close (tty); +} static sighandler sigwinch_sighandler (sig) int sig; { - struct winsize win; - -#if defined (USG) && !defined (_POSIX_VERSION) +#if defined (MUST_REINSTALL_SIGHANDLERS) set_signal_handler (SIGWINCH, sigwinch_sighandler); -#endif /* USG && !_POSIX_VERSION */ - if ((ioctl (0, TIOCGWINSZ, &win) == 0) && - win.ws_row > 0 && win.ws_col > 0) - set_lines_and_columns (win.ws_row, win.ws_col); +#endif /* MUST_REINSTALL_SIGHANDLERS */ + get_new_window_size (1); +} +#else +static void +get_new_window_size (from_sig) + int from_sig; +{ +} +#endif /* TIOCGWINSZ && SIGWINCH */ + +void +set_sigwinch_handler () +{ +#if defined (TIOCGWINSZ) && defined (SIGWINCH) + old_winch = set_signal_handler (SIGWINCH, sigwinch_sighandler); +#endif +} + +void +unset_sigwinch_handler () +{ +#if defined (TIOCGWINSZ) && defined (SIGWINCH) + set_signal_handler (SIGWINCH, old_winch); +#endif } -#endif /* !READLINE && TIOCGWINSZ && SIGWINCH */ /* Setup this shell to handle C-C, etc. */ void initialize_job_signals () { set_signal_handler (SIGINT, sigint_sighandler); -#if !defined (READLINE) && defined (TIOCGWINSZ) && defined (SIGWINCH) - set_signal_handler (SIGWINCH, sigwinch_sighandler); -#endif /* !READLINE && TIOCGWINSZ && SIGWINCH */ + set_sigwinch_handler (); /* If this is a login shell we don't wish to be disturbed by stop signals. */ if (login_shell) - { -#if defined (SIGTSTP) - set_signal_handler (SIGTSTP, SIG_IGN); - set_signal_handler (SIGTTOU, SIG_IGN); - set_signal_handler (SIGTTIN, SIG_IGN); -#endif - } + ignore_tty_job_signals (); } -#if defined (_POSIX_VERSION) +#if defined (HAVE_WAITPID) /* Collect the status of all zombie children so that their system resources can be deallocated. */ static void @@ -263,9 +311,9 @@ reap_zombie_children () while ((pid = waitpid (-1, (int *)&status, WNOHANG)) > 0) set_pid_status (pid, status); -#endif /* WNOHANG */ +#endif } -#endif /* _POSIX_VERSION */ +#endif /* WAITPID && WNOHANG */ /* 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 @@ -277,12 +325,12 @@ make_child (command, async_p) int async_p; { pid_t pid; -#if defined (_POSIX_VERSION) +#if defined (HAVE_WAITPID) int retry = 1; -#endif /* _POSIX_VERSION */ +#endif /* HAVE_WAITPID */ /* Discard saved memory. */ - if (command) + if (command) free (command); start_pipeline (); @@ -298,13 +346,13 @@ make_child (command, async_p) #endif /* BUFFERED_INPUT */ /* Create the child, handle severe errors. */ -#if defined (_POSIX_VERSION) +#if defined (HAVE_WAITPID) retry_fork: -#endif /* _POSIX_VERSION */ +#endif /* HAVE_WAITPID */ if ((pid = fork ()) < 0) { -#if defined (_POSIX_VERSION) +#if defined (HAVE_WAITPID) /* Posix systems with a non-blocking waitpid () system call available get another chance after zombies are reaped. */ if (errno == EAGAIN && retry) @@ -313,13 +361,13 @@ make_child (command, async_p) retry = 0; goto retry_fork; } -#endif /* _POSIX_VERSION */ +#endif /* HAVE_WAITPID */ - internal_error ("fork: %s", strerror (errno)); + sys_error ("fork"); throw_to_top_level (); } - + if (pid == 0) { #if defined (BUFFERED_INPUT) @@ -330,27 +378,16 @@ make_child (command, async_p) } #endif /* BUFFERED_INPUT */ -#if defined (_POSIX_VERSION) +#if defined (HAVE_POSIX_SIGNALS) /* Restore top-level signal mask. */ sigprocmask (SIG_SETMASK, &top_level_mask, (sigset_t *)NULL); #endif /* Ignore INT and QUIT in asynchronous children. */ if (async_p) - { -#if 0 - /* This now done by setup_async_signals (). */ - set_signal_handler (SIGINT, SIG_IGN); - set_signal_handler (SIGQUIT, SIG_IGN); -#endif - last_asynchronous_pid = getpid (); - } + last_asynchronous_pid = getpid (); -#if defined (SIGTSTP) - set_signal_handler (SIGTSTP, SIG_DFL); - set_signal_handler (SIGTTIN, SIG_DFL); - set_signal_handler (SIGTTOU, SIG_DFL); -#endif + default_tty_job_signals (); } else { @@ -366,6 +403,26 @@ make_child (command, async_p) return (pid); } +void +ignore_tty_job_signals () +{ +#if defined (SIGTSTP) + set_signal_handler (SIGTSTP, SIG_IGN); + set_signal_handler (SIGTTIN, SIG_IGN); + set_signal_handler (SIGTTOU, SIG_IGN); +#endif +} + +void +default_tty_job_signals () +{ +#if defined (SIGTSTP) + set_signal_handler (SIGTSTP, SIG_DFL); + set_signal_handler (SIGTTIN, SIG_DFL); + set_signal_handler (SIGTTOU, SIG_DFL); +#endif +} + /* Wait for a single pid (PID) and return its exit status. */ wait_for_single_pid (pid) pid_t pid; @@ -377,7 +434,10 @@ wait_for_single_pid (pid) pstatus = find_status_by_pid (pid); if (pstatus == PROC_BAD) - return (127); + { + internal_error ("wait: pid %d is not a child of this shell", pid); + return (127); + } if (pstatus != PROC_STILL_ALIVE) return (pstatus); @@ -390,7 +450,7 @@ wait_for_single_pid (pid) if (errno != EINTR && errno != ECHILD) { siginterrupt (SIGINT, 0); - file_error ("wait"); + sys_error ("wait"); } break; } @@ -416,7 +476,7 @@ wait_for_background_pids () WAIT status; /* If we aren't using job control, we let the kernel take care of the - bookkeeping for us. wait () will return -1 and set errno to ECHILD + bookkeeping for us. wait () will return -1 and set errno to ECHILD when there are no more unwaited-for child processes on both 4.2 BSD-based and System V-based systems. */ @@ -429,7 +489,7 @@ wait_for_background_pids () if (errno != EINTR && errno != ECHILD) { siginterrupt (SIGINT, 0); - file_error("wait"); + sys_error("wait"); } siginterrupt (SIGINT, 0); @@ -448,9 +508,7 @@ wait_sigint_handler (sig) maybe_call_trap_handler (sig); #endif -#if !defined (VOID_SIGHANDLER) - return (0); -#endif /* !VOID_SIGHANDLER */ + SIGRETURN (0); } /* Wait for pid (one of our children) to terminate. This is called only @@ -489,19 +547,19 @@ wait_for (pid) break; } else if (got_pid < 0 && errno != EINTR) - programming_error ("got errno %d while waiting for %d", errno, pid); + programming_error ("wait_for(%d): %s", pid, strerror(errno)); else if (got_pid > 0) set_pid_status (got_pid, status); } set_pid_status (got_pid, status); -#if defined (_POSIX_VERSION) +#if defined (HAVE_WAITPID) if (got_pid >= 0) reap_zombie_children (); -#endif /* _POSIX_VERSION */ +#endif /* HAVE_WAITPID */ - if (!interactive_shell) + if (interactive_shell == 0) { set_signal_handler (SIGINT, old_sigint_handler); /* If the job exited because of SIGINT, make sure the shell acts as if @@ -512,14 +570,14 @@ wait_for (pid) (*old_sigint_handler) (SIGINT); } } - + /* Default return value. */ /* ``a full 8 bits of status is returned'' */ if (WIFSIGNALED (status)) return_val = 128 + WTERMSIG (status); else return_val = WEXITSTATUS (status); - + if (!WIFSTOPPED (status) && WIFSIGNALED (status) && (WTERMSIG (status) != SIGINT)) { @@ -529,7 +587,7 @@ wait_for (pid) fprintf (stderr, "\n"); } - if (interactive_shell && !subshell_environment) + if (interactive_shell && subshell_environment == 0) { if (WIFSIGNALED (status) || WIFSTOPPED (status)) set_tty_state (); @@ -559,28 +617,30 @@ kill_pid (pid, signal, group) return (result); } -#if defined (_POSIX_VERSION) +#if defined (TERMIOS_TTY_DRIVER) static struct termios shell_tty_info; -#else -# if defined (USG) +#else /* !TERMIOS_TTY_DRIVER */ +# if defined (TERMIO_TTY_DRIVER) static struct termio shell_tty_info; # else static struct sgttyb shell_tty_info; -# endif /* USG */ -#endif /* _POSIX_VERSION */ +# endif /* !TERMIO_TTY_DRIVER */ +#endif /* !TERMIOS_TTY_DRIVER */ -static int got_tty_state = 0; +static int got_tty_state; /* Fill the contents of shell_tty_info with the current tty info. */ get_tty_state () { - int tty = open ("/dev/tty", O_RDONLY); + int tty; + + tty = open ("/dev/tty", O_RDONLY); if (tty != -1) { -#if defined (_POSIX_VERSION) +#if defined (TERMIOS_TTY_DRIVER) tcgetattr (tty, &shell_tty_info); #else -# if defined (USG) +# if defined (TERMIO_TTY_DRIVER) ioctl (tty, TCGETA, &shell_tty_info); # else ioctl (tty, TIOCGETP, &shell_tty_info); @@ -588,24 +648,28 @@ get_tty_state () #endif close (tty); got_tty_state = 1; + if (check_window_size) + get_new_window_size (0); } } /* Make the current tty use the state in shell_tty_info. */ set_tty_state () { - int tty = open ("/dev/tty", O_RDONLY); + int tty; + + tty = open ("/dev/tty", O_RDONLY); if (tty != -1) { - if (!got_tty_state) + if (got_tty_state == 0) { close (tty); return; } -#if defined (_POSIX_VERSION) +#if defined (TERMIOS_TTY_DRIVER) tcsetattr (tty, TCSADRAIN, &shell_tty_info); #else -# if defined (USG) +# if defined (TERMIO_TTY_DRIVER) ioctl (tty, TCSETAW, &shell_tty_info); /* Wait for output, no flush */ # else ioctl (tty, TIOCSETN, &shell_tty_info); @@ -642,3 +706,8 @@ describe_pid (pid) { fprintf (stderr, "%d\n", (int) pid); } + +void +unfreeze_jobs_list () +{ +} diff --git a/oslib.c b/oslib.c new file mode 100644 index 0000000..ef643ff --- /dev/null +++ b/oslib.c @@ -0,0 +1,429 @@ +/* oslib.c - functions present only in some unix versions. */ + +/* Copyright (C) 1995 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, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "config.h" + +#include "bashtypes.h" +#include + +#if defined (HAVE_UNISTD_H) +# include +#endif + +#include "posixstat.h" +#include "filecntl.h" +#include "bashansi.h" + +#include +#include +#include + +#include "shell.h" +#include "maxpath.h" + +#if !defined (errno) +extern int errno; +#endif /* !errno */ + +/* A standard error message to use when getcwd() returns NULL. */ +char *bash_getcwd_errstr = "getcwd: cannot access parent directories"; + +#if !defined (HAVE_SYSCONF) || !defined (_SC_CLK_TCK) +# if !defined (CLK_TCK) +# if defined (HZ) +# define CLK_TCK HZ +# else +# define CLK_TCK 60 +# endif +# endif /* !CLK_TCK */ +#endif /* !HAVE_SYSCONF && !_SC_CLK_TCK */ + +long +get_clk_tck () +{ + static long retval = 0; + + if (retval != 0) + return (retval); + +#if defined (HAVE_SYSCONF) && defined (_SC_CLK_TCK) + retval = sysconf (_SC_CLK_TCK); +#else /* !SYSCONF || !_SC_CLK_TCK */ + retval = CLK_TCK; +#endif /* !SYSCONF || !_SC_CLK_TCK */ + + return (retval); +} + +/* Make the functions strchr and strrchr if they do not exist. */ +#if !defined (HAVE_STRCHR) +char * +strchr (string, c) + char *string; + int c; +{ + register char *s; + + for (s = string; s && *s; s++) + if (*s == c) + return (s); + + return ((char *) NULL); +} + +char * +strrchr (string, c) + char *string; + int c; +{ + register char *s, *t; + + for (s = string, t = (char *)NULL; s && *s; s++) + if (*s == c) + t = s; + return (t); +} +#endif /* !HAVE_STRCHR */ + +#if !defined (HAVE_STRCASECMP) + +#if !defined (to_lower) +# define to_lower(c) (islower(c) ? (c) : toupper(c)) +#endif /* to_lower */ + +/* Compare at most COUNT characters from string1 to string2. Case + doesn't matter. */ +int +strncasecmp (string1, string2, count) + char *string1, *string2; + int count; +{ + register char *s1, *s2; + register int r; + + if (count > 0) + { + s1 = string1; + s2 = string2; + do + { + if ((r = to_lower (*s1) - to_lower (*s2)) != 0) + return r; + if (*s1++ == '\0') + break; + s2++; + } + while (--count != 0); + } + return (0); +} + +/* strcmp (), but caseless. */ +int +strcasecmp (string1, string2) + char *string1, *string2; +{ + register char *s1, *s2; + register int r; + + s1 = string1; + s2 = string2; + + while ((r = to_lower (*s1) - to_lower (*s2)) == 0) + { + if (*s1++ == '\0') + return 0; + s2++; + } + return (r); +} +#endif /* !HAVE_STRCASECMP */ + +/* Return a string corresponding to the error number E. From + the ANSI C spec. */ +#if defined (strerror) +# undef strerror +#endif + +#if !defined (HAVE_STRERROR) +char * +strerror (e) + int e; +{ + static char emsg[40]; +#if defined (HAVE_SYS_ERRLIST) + extern int sys_nerr; + extern char *sys_errlist[]; + + if (e > 0 && e < sys_nerr) + return (sys_errlist[e]); + else +#endif /* HAVE_SYS_ERRLIST */ + { + sprintf (emsg, "Unknown error %d", e); + return (&emsg[0]); + } +} +#endif /* HAVE_STRERROR */ + +#if !defined (HAVE_DUP2) || defined (DUP2_BROKEN) +/* Replacement for dup2 (), for those systems which either don't have it, + or supply one with broken behaviour. */ +int +dup2 (fd1, fd2) + int fd1, fd2; +{ + int saved_errno, r; + + /* If FD1 is not a valid file descriptor, then return immediately with + an error. */ + if (fcntl (fd1, F_GETFL, 0) == -1) + return (-1); + + if (fd2 < 0 || fd2 >= getdtablesize ()) + { + errno = EBADF; + return (-1); + } + + if (fd1 == fd2) + return (0); + + saved_errno = errno; + + (void) close (fd2); + r = fcntl (fd1, F_DUPFD, fd2); + + if (r >= 0) + errno = saved_errno; + else + if (errno == EINVAL) + errno = EBADF; + + /* Force the new file descriptor to remain open across exec () calls. */ + SET_OPEN_ON_EXEC (fd2); + return (r); +} +#endif /* !HAVE_DUP2 */ + +/* + * Return the total number of available file descriptors. + * + * On some systems, like 4.2BSD and its descendents, there is a system call + * that returns the size of the descriptor table: getdtablesize(). There are + * lots of ways to emulate this on non-BSD systems. + * + * On System V.3, this can be obtained via a call to ulimit: + * return (ulimit(4, 0L)); + * + * On other System V systems, NOFILE is defined in /usr/include/sys/param.h + * (this is what we assume below), so we can simply use it: + * return (NOFILE); + * + * On POSIX systems, there are specific functions for retrieving various + * configuration parameters: + * return (sysconf(_SC_OPEN_MAX)); + * + */ + +#if !defined (HAVE_GETDTABLESIZE) +int +getdtablesize () +{ +# if defined (_POSIX_VERSION) && defined (HAVE_SYSCONF) && defined (_SC_OPEN_MAX) + return (sysconf(_SC_OPEN_MAX)); /* Posix systems use sysconf */ +# else /* ! (_POSIX_VERSION && HAVE_SYSCONF && _SC_OPEN_MAX) */ +# if defined (ULIMIT_MAXFDS) + return (ulimit (4, 0L)); /* System V.3 systems use ulimit(4, 0L) */ +# else /* !ULIMIT_MAXFDS */ +# if defined (NOFILE) /* Other systems use NOFILE */ + return (NOFILE); +# else /* !NOFILE */ + return (20); /* XXX - traditional value is 20 */ +# endif /* !NOFILE */ +# endif /* !ULIMIT_MAXFDS */ +# endif /* ! (_POSIX_VERSION && _SC_OPEN_MAX) */ +} +#endif /* !HAVE_GETDTABLESIZE */ + +#if !defined (HAVE_BCOPY) +void +bcopy (s,d,n) + char *d, *s; + int n; +{ + FASTCOPY (s, d, n); +} +#endif /* !HAVE_BCOPY */ + +#if !defined (HAVE_BZERO) +void +bzero (s, n) + char *s; + int n; +{ + register int i; + + for (i = 0; i < n; i++) + s[i] = '\0'; +} +#endif + +#if !defined (HAVE_GETHOSTNAME) +# if defined (HAVE_UNAME) +# include +int +gethostname (name, namelen) + char *name; + int namelen; +{ + int i; + struct utsname ut; + + --namelen; + + uname (&ut); + i = strlen (ut.nodename) + 1; + strncpy (name, ut.nodename, i < namelen ? i : namelen); + name[namelen] = '\0'; + return (0); +} +# else /* !HAVE_UNAME */ +int +gethostname (name, namelen) + int name, namelen; +{ + strncpy (name, "unknown", namelen); + name[namelen] = '\0'; + return 0; +} +# endif /* !HAVE_UNAME */ +#endif /* !HAVE_GETHOSTNAME */ + +#if !defined (HAVE_KILLPG) +int +killpg (pgrp, sig) + pid_t pgrp; + int sig; +{ + return (kill (-pgrp, sig)); +} +#endif /* !HAVE_KILLPG */ + + +/* We supply our own version of getenv () because we want library + routines to get the changed values of exported variables. */ + +/* The NeXT C library has getenv () defined and used in the same file. + This screws our scheme. However, Bash will run on the NeXT using + the C library getenv (), since right now the only environment variable + that we care about is HOME, and that is already defined. */ +#if defined (CAN_REDEFINE_GETENV) +static char *last_tempenv_value = (char *)NULL; +extern char **environ; + +char * +getenv (name) +#if defined (__linux__) || defined (__bsdi__) || defined (convex) + const char *name; +#else + char const *name; +#endif /* !__linux__ && !__bsdi__ && !convex */ +{ + SHELL_VAR *var; + + var = find_tempenv_variable ((char *)name); + if (var) + { + FREE (last_tempenv_value); + + last_tempenv_value = savestring (value_cell (var)); + dispose_variable (var); + return (last_tempenv_value); + } + else if (shell_variables) + { + var = find_variable ((char *)name); + if (var && exported_p (var)) + return (value_cell (var)); + } + else + { + register int i, len; + + /* In some cases, s5r3 invokes getenv() before main(); BSD systems + using gprof also exhibit this behavior. This means that + shell_variables will be 0 when this is invoked. We look up the + variable in the real environment in that case. */ + + for (i = 0, len = strlen (name); environ[i]; i++) + { + if ((STREQN (environ[i], name, len)) && (environ[i][len] == '=')) + return (environ[i] + len + 1); + } + } + + return ((char *)NULL); +} + +/* Some versions of Unix use _getenv instead. */ +char * +_getenv (name) +#if defined (__linux__) || defined (__bsdi__) || defined (convex) + const char *name; +#else + char const *name; +#endif /* !__linux__ && !__bsdi__ && !convex */ +{ + return (getenv (name)); +} + +#endif /* CAN_REDEFINE_GETENV */ + +#if !defined (HAVE_MKFIFO) && defined (PROCESS_SUBSTITUTION) +int +mkfifo (path, mode) + char *path; + int mode; +{ +#if defined (S_IFIFO) + return (mknod (path, (mode | S_IFIFO), 0)); +#else /* !S_IFIFO */ + return (-1); +#endif /* !S_IFIFO */ +} +#endif + +#if !defined (HAVE_SETLINEBUF) +/* Cause STREAM to buffer lines as opposed to characters or blocks. */ +int +setlinebuf (stream) + FILE *stream; +{ +#if defined (_IOLBF) +# if defined (SETVBUF_REVERSED) + setvbuf (stream, _IOLBF, (char *)NULL, BUFSIZ); +# else /* !SETVBUF_REVERSED */ + setvbuf (stream, (char *)NULL, _IOLBF, BUFSIZ); +# endif /* !SETVBUF_REVERSED */ +#endif /* _IOLBF */ + return (0); +} +#endif /* !HAVE_SETLINEBUF */ diff --git a/parse.y b/parse.y index 9c4c75a..1a949b0 100644 --- a/parse.y +++ b/parse.y @@ -19,15 +19,34 @@ Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ %{ -#include +#include "config.h" + #include "bashtypes.h" -#include #include "bashansi.h" + +#if defined (HAVE_UNISTD_H) +# include +#endif + +#if defined (HAVE_LOCALE_H) +# include +#endif + +#include +#include + +#include "memalloc.h" + #include "shell.h" +#include "trap.h" #include "flags.h" -#include "input.h" +#include "parser.h" +#include "mailcheck.h" +#include "builtins/common.h" +#include "builtins/builtext.h" #if defined (READLINE) +# include "bashline.h" # include #endif /* READLINE */ @@ -50,19 +69,24 @@ #include "maxpath.h" #endif /* PROMPT_STRING_DECODE */ -#define YYDEBUG 1 +#define RE_READ_TOKEN -99 +#define NO_EXPANSION -100 + +#define YYDEBUG 0 + extern int eof_encountered; -extern int no_line_editing; +extern int no_line_editing, running_under_emacs; extern int current_command_number; extern int interactive, interactive_shell, login_shell; +extern int sourcelevel; extern int posixly_correct; extern int last_command_exit_value; extern int interrupt_immediately; extern char *shell_name, *current_host_name; +extern char *dist_version; +extern int patch_level; +extern int dump_translatable_strings; extern Function *last_shell_builtin, *this_shell_builtin; -#if defined (READLINE) -extern int bash_readline_initialized; -#endif #if defined (BUFFERED_INPUT) extern int bash_input_fd_changed; #endif @@ -73,12 +97,13 @@ extern int bash_input_fd_changed; /* */ /* **************************************************************** */ -/* This is kind of sickening. In order to let these variables be seen by - all the functions that need them, I am forced to place their declarations - far away from the place where they should logically be found. */ - +static char *ansiexpand (); +static char *localeexpand (); static int reserved_word_acceptable (); static int read_token (); +static int yylex (); +static int read_token_word (); +static void discard_parser_constructs (); static void report_syntax_error (); static void handle_eof_input_unit (); @@ -86,6 +111,10 @@ static void prompt_again (); static void reset_readline_prompt (); static void print_prompt (); +/* Default prompt strings */ +char *primary_prompt = PPROMPT; +char *secondary_prompt = SPROMPT; + /* PROMPT_STRING_POINTER points to one of these, never to an actual string. */ char *ps1_prompt, *ps2_prompt; @@ -94,27 +123,42 @@ char *ps1_prompt, *ps2_prompt; char **prompt_string_pointer = (char **)NULL; char *current_prompt_string; +/* Non-zero means we expand aliases in commands. */ +int expand_aliases = 0; + +/* If non-zero, the decoded prompt string undergoes parameter and + variable substitution, command substitution, arithmetic substitution, + string expansion, process substitution, and quote removal in + decode_prompt_string. */ +int promptvars = 1; + /* The decoded prompt string. Used if READLINE is not defined or if editing is turned off. Analogous to current_readline_prompt. */ static char *current_decoded_prompt; /* The number of lines read from input while creating the current command. */ -int current_command_line_count = 0; +int current_command_line_count; /* Variables to manage the task of reading here documents, because we need to defer the reading until after a complete command has been collected. */ static REDIRECT *redir_stack[10]; -int need_here_doc = 0; +int need_here_doc; /* Where shell input comes from. History expansion is performed on each line when the shell is interactive. */ static char *shell_input_line = (char *)NULL; -static int shell_input_line_index = 0; -static int shell_input_line_size = 0; /* Amount allocated for shell_input_line. */ -static int shell_input_line_len = 0; /* strlen (shell_input_line) */ +static int shell_input_line_index; +static int shell_input_line_size; /* Amount allocated for shell_input_line. */ +static int shell_input_line_len; /* strlen (shell_input_line) */ /* Either zero or EOF. */ -static int shell_input_line_terminator = 0; +static int shell_input_line_terminator; + +/* The line number in a script on which a function definition starts. */ +static int function_dstart; + +/* The line number in a script on which a function body starts. */ +static int function_bstart; static REDIRECTEE redir; %} @@ -133,7 +177,7 @@ static REDIRECTEE redir; in the case that they are preceded by a list_terminator. Members of the second group are recognized only under special circumstances. */ %token IF THEN ELSE ELIF FI CASE ESAC FOR SELECT WHILE UNTIL DO DONE FUNCTION -%token IN BANG +%token IN BANG TIME TIMEOPT /* More general tokens. yylex () knows how to make these. */ %token WORD ASSIGNMENT_WORD @@ -144,14 +188,16 @@ static REDIRECTEE redir; /* The types that the various syntactical units return. */ -%type inputunit command pipeline -%type list list0 list1 simple_list simple_list1 -%type simple_command shell_command_1 shell_command select_command -%type group_command function_def if_command elif_clause subshell -%type redirection redirections +%type inputunit command pipeline pipeline_command +%type list list0 list1 compound_list simple_list simple_list1 +%type simple_command shell_command +%type for_command select_command case_command group_command +%type function_def if_command elif_clause subshell +%type redirection redirection_list %type simple_command_element -%type words pattern -%type pattern_list case_clause_sequence case_clause_1 pattern_list_1 +%type word_list pattern +%type pattern_list case_clause_sequence case_clause +%type timespec %start inputunit @@ -176,8 +222,7 @@ inputunit: simple_list '\n' global_command = (COMMAND *)NULL; YYACCEPT; } - | - error '\n' + | error '\n' { /* Error during parsing. Return NULL command. */ global_command = (COMMAND *)NULL; @@ -194,7 +239,7 @@ inputunit: simple_list '\n' } | yacc_EOF { - /* Case of EOF seen by itself. Do ignoreeof or + /* Case of EOF seen by itself. Do ignoreeof or not. */ global_command = (COMMAND *)NULL; handle_eof_input_unit (); @@ -202,9 +247,9 @@ inputunit: simple_list '\n' } ; -words: - { $$ = (WORD_LIST *)NULL; } - | words WORD +word_list: WORD + { $$ = make_word_list ($1, (WORD_LIST *)NULL); } + | word_list WORD { $$ = make_word_list ($2, $1); } ; @@ -336,20 +381,9 @@ redirection: '>' WORD } | LESS_GREATER WORD { - REDIRECT *t1, *t2; - redir.filename = $2; - if (posixly_correct) - $$ = make_redirection (0, r_input_output, redir); - else - { - t1 = make_redirection (0, r_input_direction, redir); - redir.filename = copy_word ($2); - t2 = make_redirection (1, r_output_direction, redir); - t1->next = t2; - $$ = t1; - } - } + $$ = make_redirection (0, r_input_output, redir); + } | GREATER_BAR WORD { redir.filename = $2; @@ -370,17 +404,17 @@ simple_command_element: WORD { $$.redirect = $1; $$.word = 0; } ; -redirections: redirection +redirection_list: redirection { $$ = $1; } - | redirections redirection - { - register REDIRECT *t = $1; + | redirection_list redirection + { + register REDIRECT *t; - while (t->next) - t = t->next; - t->next = $2; + for (t = $1; t->next; t = t->next) + ; + t->next = $2; $$ = $1; } ; @@ -395,47 +429,42 @@ command: simple_command { $$ = clean_simple_command ($1); } | shell_command { $$ = $1; } - ; - -shell_command: shell_command_1 - { $$ = $1; } - | shell_command_1 redirections + | shell_command redirection_list { - if ($1->redirects) + COMMAND *tc; + + tc = $1; + /* According to Posix.2 3.9.5, redirections + specified after the body of a function should + be attached to the function and performed when + the function is executed, not as part of the + function definition command. */ + if (tc->type == cm_function_def) + { + tc = tc->value.Function_def->command; + if (tc->type == cm_group) + tc = tc->value.Group->command; + } + if (tc->redirects) { register REDIRECT *t; - for (t = $1->redirects; t->next; t = t->next) + for (t = tc->redirects; t->next; t = t->next) ; t->next = $2; } else - $1->redirects = $2; + tc->redirects = $2; $$ = $1; } ; -shell_command_1: FOR WORD newlines DO list DONE - { $$ = make_for_command ($2, add_string_to_list ("\"$@\"", (WORD_LIST *)NULL), $5); } - | FOR WORD newlines '{' list '}' - { $$ = make_for_command ($2, add_string_to_list ("$@", (WORD_LIST *)NULL), $5); } - | FOR WORD ';' newlines DO list DONE - { $$ = make_for_command ($2, add_string_to_list ("\"$@\"", (WORD_LIST *)NULL), $6); } - | FOR WORD ';' newlines '{' list '}' - { $$ = make_for_command ($2, add_string_to_list ("\"$@\"", (WORD_LIST *)NULL), $6); } - | FOR WORD newlines IN words list_terminator newlines DO list DONE - { $$ = make_for_command ($2, REVERSE_LIST ($5, WORD_LIST *), $9); } - | FOR WORD newlines IN words list_terminator newlines '{' list '}' - { $$ = make_for_command ($2, REVERSE_LIST ($5, WORD_LIST *), $9); } - - | CASE WORD newlines IN newlines ESAC - { $$ = make_case_command ($2, (PATTERN_LIST *)NULL); } - | CASE WORD newlines IN case_clause_sequence newlines ESAC - { $$ = make_case_command ($2, $5); } - | CASE WORD newlines IN case_clause_1 ESAC - { $$ = make_case_command ($2, $5); } - | WHILE list DO list DONE +shell_command: for_command + { $$ = $1; } + | case_command + { $$ = $1; } + | WHILE compound_list DO compound_list DONE { $$ = make_while_command ($2, $4); } - | UNTIL list DO list DONE + | UNTIL compound_list DO compound_list DONE { $$ = make_until_command ($2, $4); } | select_command { $$ = $1; } @@ -449,72 +478,74 @@ shell_command_1: FOR WORD newlines DO list DONE { $$ = $1; } ; -select_command: SELECT WORD newlines DO list DONE +for_command: FOR WORD newline_list DO list DONE + { $$ = make_for_command ($2, add_string_to_list ("\"$@\"", (WORD_LIST *)NULL), $5); } + | FOR WORD newline_list '{' list '}' + { $$ = make_for_command ($2, add_string_to_list ("$@", (WORD_LIST *)NULL), $5); } + | FOR WORD ';' newline_list DO list DONE + { $$ = make_for_command ($2, add_string_to_list ("\"$@\"", (WORD_LIST *)NULL), $6); } + | FOR WORD ';' newline_list '{' list '}' + { $$ = make_for_command ($2, add_string_to_list ("\"$@\"", (WORD_LIST *)NULL), $6); } + | FOR WORD newline_list IN word_list list_terminator newline_list DO list DONE + { $$ = make_for_command ($2, REVERSE_LIST ($5, WORD_LIST *), $9); } + | FOR WORD newline_list IN word_list list_terminator newline_list '{' list '}' + { $$ = make_for_command ($2, REVERSE_LIST ($5, WORD_LIST *), $9); } + ; + +select_command: SELECT WORD newline_list DO list DONE { -#if defined (SELECT_COMMAND) $$ = make_select_command ($2, add_string_to_list ("\"$@\"", (WORD_LIST *)NULL), $5); -#endif } - | SELECT WORD newlines '{' list '}' + | SELECT WORD newline_list '{' list '}' { -#if defined (SELECT_COMMAND) $$ = make_select_command ($2, add_string_to_list ("$@", (WORD_LIST *)NULL), $5); -#endif } - | SELECT WORD ';' newlines DO list DONE + | SELECT WORD ';' newline_list DO list DONE { -#if defined (SELECT_COMMAND) $$ = make_select_command ($2, add_string_to_list ("\"$@\"", (WORD_LIST *)NULL), $6); -#endif } - | SELECT WORD ';' newlines '{' list '}' + | SELECT WORD ';' newline_list '{' list '}' { -#if defined (SELECT_COMMAND) $$ = make_select_command ($2, add_string_to_list ("\"$@\"", (WORD_LIST *)NULL), $6); -#endif } - | SELECT WORD newlines IN words list_terminator newlines DO list DONE + | SELECT WORD newline_list IN word_list list_terminator newline_list DO list DONE { -#if defined (SELECT_COMMAND) $$ = make_select_command ($2, (WORD_LIST *)reverse_list ($5), $9); -#endif } - | SELECT WORD newlines IN words list_terminator newlines '{' list '}' + | SELECT WORD newline_list IN word_list list_terminator newline_list '{' list '}' { -#if defined (SELECT_COMMAND) $$ = make_select_command ($2, (WORD_LIST *)reverse_list ($5), $9); -#endif } ; -function_def: WORD '(' ')' newlines group_command - { $$ = make_function_def ($1, $5); } - - | WORD '(' ')' newlines group_command redirections - { $5->redirects = $6; $$ = make_function_def ($1, $5); } +case_command: CASE WORD newline_list IN newline_list ESAC + { $$ = make_case_command ($2, (PATTERN_LIST *)NULL); } + | CASE WORD newline_list IN case_clause_sequence newline_list ESAC + { $$ = make_case_command ($2, $5); } + | CASE WORD newline_list IN case_clause ESAC + { $$ = make_case_command ($2, $5); } + ; - | FUNCTION WORD '(' ')' newlines group_command - { $$ = make_function_def ($2, $6); } +function_def: WORD '(' ')' newline_list group_command + { $$ = make_function_def ($1, $5, function_dstart, function_bstart); } - | FUNCTION WORD '(' ')' newlines group_command redirections - { $6->redirects = $7; $$ = make_function_def ($2, $6); } - | FUNCTION WORD newlines group_command - { $$ = make_function_def ($2, $4); } + | FUNCTION WORD '(' ')' newline_list group_command + { $$ = make_function_def ($2, $6, function_dstart, function_bstart); } - | FUNCTION WORD newlines group_command redirections - { $4->redirects = $5; $$ = make_function_def ($2, $4); } + | FUNCTION WORD newline_list group_command + { $$ = make_function_def ($2, $4, function_dstart, function_bstart); } ; -subshell: '(' list ')' +subshell: '(' compound_list ')' { $2->flags |= CMD_WANT_SUBSHELL; $$ = $2; } ; - -if_command: IF list THEN list FI + +if_command: IF compound_list THEN compound_list FI { $$ = make_if_command ($2, $4, (COMMAND *)NULL); } - | IF list THEN list ELSE list FI + | IF compound_list THEN compound_list ELSE compound_list FI { $$ = make_if_command ($2, $4, $6); } - | IF list THEN list elif_clause FI + | IF compound_list THEN compound_list elif_clause FI { $$ = make_if_command ($2, $4, $5); } ; @@ -523,44 +554,34 @@ group_command: '{' list '}' { $$ = make_group_command ($2); } ; -elif_clause: ELIF list THEN list +elif_clause: ELIF compound_list THEN compound_list { $$ = make_if_command ($2, $4, (COMMAND *)NULL); } - | ELIF list THEN list ELSE list + | ELIF compound_list THEN compound_list ELSE compound_list { $$ = make_if_command ($2, $4, $6); } - | ELIF list THEN list elif_clause + | ELIF compound_list THEN compound_list elif_clause { $$ = make_if_command ($2, $4, $5); } ; -case_clause_1: pattern_list_1 - | case_clause_sequence pattern_list_1 +case_clause: pattern_list + | case_clause_sequence pattern_list { $2->next = $1; $$ = $2; } ; -pattern_list_1: newlines pattern ')' list +pattern_list: newline_list pattern ')' compound_list { $$ = make_pattern_list ($2, $4); } - | newlines pattern ')' newlines + | newline_list pattern ')' newline_list { $$ = make_pattern_list ($2, (COMMAND *)NULL); } - | newlines '(' pattern ')' list + | newline_list '(' pattern ')' compound_list { $$ = make_pattern_list ($3, $5); } - | newlines '(' pattern ')' newlines + | newline_list '(' pattern ')' newline_list { $$ = make_pattern_list ($3, (COMMAND *)NULL); } ; -case_clause_sequence: pattern_list - | case_clause_sequence pattern_list +case_clause_sequence: pattern_list SEMI_SEMI + | case_clause_sequence pattern_list SEMI_SEMI { $2->next = $1; $$ = $2; } ; -pattern_list: newlines pattern ')' list SEMI_SEMI - { $$ = make_pattern_list ($2, $4); } - | newlines pattern ')' newlines SEMI_SEMI - { $$ = make_pattern_list ($2, (COMMAND *)NULL); } - | newlines '(' pattern ')' list SEMI_SEMI - { $$ = make_pattern_list ($3, $5); } - | newlines '(' pattern ')' newlines SEMI_SEMI - { $$ = make_pattern_list ($3, (COMMAND *)NULL); } - ; - pattern: WORD { $$ = make_word_list ($1, (WORD_LIST *)NULL); } | pattern '|' WORD @@ -572,7 +593,7 @@ pattern: WORD It must end with a newline or semicolon. Lists are used within commands such as if, for, while. */ -list: newlines list0 +list: newline_list list0 { $$ = $2; if (need_here_doc) @@ -580,41 +601,42 @@ list: newlines list0 } ; -list0: list1 - | list1 '\n' newlines - | list1 '&' newlines +compound_list: list + | newline_list list1 + { + $$ = $2; + } + ; + +list0: list1 '\n' newline_list + | list1 '&' newline_list { if ($1->type == cm_connection) $$ = connect_async_list ($1, (COMMAND *)NULL, '&'); else $$ = command_connect ($1, (COMMAND *)NULL, '&'); } - | list1 ';' newlines + | list1 ';' newline_list ; -list1: list1 AND_AND newlines list1 +list1: list1 AND_AND newline_list list1 { $$ = command_connect ($1, $4, AND_AND); } - | list1 OR_OR newlines list1 + | list1 OR_OR newline_list list1 { $$ = command_connect ($1, $4, OR_OR); } - | list1 '&' newlines list1 + | list1 '&' newline_list list1 { if ($1->type == cm_connection) $$ = connect_async_list ($1, $4, '&'); else $$ = command_connect ($1, $4, '&'); } - | list1 ';' newlines list1 + | list1 ';' newline_list list1 { $$ = command_connect ($1, $4, ';'); } - | list1 '\n' newlines list1 + | list1 '\n' newline_list list1 { $$ = command_connect ($1, $4, ';'); } - | pipeline + | pipeline_command { $$ = $1; } - | BANG pipeline - { - $2->flags |= CMD_INVERT_RETURN; - $$ = $2; - } ; list_terminator:'\n' @@ -622,8 +644,8 @@ list_terminator:'\n' | yacc_EOF ; -newlines: - | newlines '\n' +newline_list: + | newline_list '\n' ; /* A simple_list is a list that contains no significant newlines @@ -655,9 +677,9 @@ simple_list: simple_list1 } ; -simple_list1: simple_list1 AND_AND newlines simple_list1 +simple_list1: simple_list1 AND_AND newline_list simple_list1 { $$ = command_connect ($1, $4, AND_AND); } - | simple_list1 OR_OR newlines simple_list1 + | simple_list1 OR_OR newline_list simple_list1 { $$ = command_connect ($1, $4, OR_OR); } | simple_list1 '&' simple_list1 { @@ -668,45 +690,104 @@ simple_list1: simple_list1 AND_AND newlines simple_list1 } | simple_list1 ';' simple_list1 { $$ = command_connect ($1, $3, ';'); } - | pipeline + + | pipeline_command + { $$ = $1; } + ; + +pipeline_command: pipeline { $$ = $1; } | BANG pipeline { $2->flags |= CMD_INVERT_RETURN; $$ = $2; } + | timespec pipeline + { + $2->flags |= $1; + $$ = $2; + } + | timespec BANG pipeline + { + $3->flags |= $1; + $$ = $3; + } + | BANG timespec pipeline + { + $3->flags |= $2|CMD_INVERT_RETURN; + $$ = $3; + } ; pipeline: - pipeline '|' newlines pipeline + pipeline '|' newline_list pipeline { $$ = command_connect ($1, $4, '|'); } | command { $$ = $1; } ; + +timespec: TIME + { $$ = CMD_TIME_PIPELINE; } + | TIME TIMEOPT + { $$ = CMD_TIME_PIPELINE|CMD_TIME_POSIX; } + ; %% +/* Possible states for the parser that require it to do special things. */ +#define PST_CASEPAT 0x001 /* in a case pattern list */ +#define PST_ALEXPNEXT 0x002 /* expand next word for aliases */ +#define PST_ALLOWOPNBRC 0x004 /* allow open brace for function def */ +#define PST_NEEDCLOSBRC 0x008 /* need close brace */ +#define PST_DBLPAREN 0x010 /* double-paren parsing */ +#define PST_SUBSHELL 0x020 /* ( ... ) subshell */ +#define PST_CMDSUBST 0x040 /* $( ... ) command substitution */ +#define PST_CASESTMT 0x080 /* parsing a case statement */ + /* Initial size to allocate for tokens, and the amount to grow them by. */ #define TOKEN_DEFAULT_GROW_SIZE 512 +/* Shell meta-characters that, when unquoted, separate words. */ +#define shellmeta(c) (strchr ("()<>;&|", (c)) != 0) +#define shellbreak(c) (strchr ("()<>;&| \t\n", (c)) != 0) +#define shellquote(c) ((c) == '"' || (c) == '`' || (c) == '\'') +#define shellexp(c) ((c) == '$' || (c) == '<' || (c) == '>') + /* The token currently being read. */ -static int current_token = 0; +static int current_token; /* The last read token, or NULL. read_token () uses this for context checking. */ -static int last_read_token = 0; +static int last_read_token; /* The token read prior to last_read_token. */ -static int token_before_that = 0; +static int token_before_that; + +/* The token read prior to token_before_that. */ +static int two_tokens_ago; /* If non-zero, it is the token that we want read_token to return regardless of what text is (or isn't) present to be read. This - is reset by read_token. */ -static int token_to_read = 0; + is reset by read_token. If token_to_read == WORD or + ASSIGNMENT_WORD, yylval.word should be set to word_desc_to_read. */ +static int token_to_read; +static WORD_DESC *word_desc_to_read; + +/* The current parser state. */ +static int parser_state; /* Global var is non-zero when end of file has been reached. */ int EOF_Reached = 0; +void +debug_parser (i) + int i; +{ +#if YYDEBUG != 0 + yydebug = i; +#endif +} + /* yy_getc () returns the next available character from input or EOF. yy_ungetc (c) makes `c' the next character to read. init_yy_io (get, unget, type, location) makes the function GET the @@ -716,6 +797,7 @@ int EOF_Reached = 0; the input is coming from. */ /* Unconditionally returns end-of-file. */ +int return_EOF () { return (EOF); @@ -725,11 +807,13 @@ return_EOF () See ./input.h for a clearer description. */ BASH_INPUT bash_input; -/* Set all of the fields in BASH_INPUT to NULL. */ +/* Set all of the fields in BASH_INPUT to NULL. Free bash_input.name if it + is non-null, avoiding a memory leak. */ void initialize_bash_input () { - bash_input.type = 0; + bash_input.type = st_none; + FREE (bash_input.name); bash_input.name = (char *)NULL; bash_input.location.file = (FILE *)NULL; bash_input.location.string = (char *)NULL; @@ -748,12 +832,9 @@ init_yy_io (get, unget, type, name, location) { bash_input.type = type; FREE (bash_input.name); + bash_input.name = name ? savestring (name) : (char *)NULL; - if (name) - bash_input.name = savestring (name); - else - bash_input.name = (char *)NULL; - + /* XXX */ #if defined (CRAY) memcpy((char *)&bash_input.location.string, (char *)&location.string, sizeof(location)); #else @@ -764,6 +845,7 @@ init_yy_io (get, unget, type, name, location) } /* Call this to get the next character of input. */ +int yy_getc () { return (*(bash_input.getter)) (); @@ -771,6 +853,7 @@ yy_getc () /* Call this to unget C. That is, to make C the next character to be read. */ +int yy_ungetc (c) int c; { @@ -787,6 +870,7 @@ input_file_descriptor () return (fileno (bash_input.location.file)); case st_bstream: return (bash_input.location.buffered_fd); + case st_stdin: default: return (fileno (stdin)); } @@ -807,11 +891,11 @@ int current_readline_line_index = 0; static int yy_readline_get () { + SigHandler *old_sigint; + int line_len, c; + if (!current_readline_line) { - SigHandler *old_sigint; - int line_len; - if (!bash_readline_initialized) initialize_readline (); @@ -826,10 +910,8 @@ yy_readline_get () interrupt_immediately++; } - if (!current_readline_prompt) - current_readline_line = readline (""); - else - current_readline_line = readline (current_readline_prompt); + current_readline_line = readline (current_readline_prompt ? + current_readline_prompt : ""); if (signal_is_ignored (SIGINT) == 0) { @@ -837,22 +919,23 @@ yy_readline_get () set_signal_handler (SIGINT, old_sigint); } - /* Reset the prompt to whatever is in the decoded value of - prompt_string_pointer. */ +#if 0 + /* Reset the prompt to the decoded value of prompt_string_pointer. */ reset_readline_prompt (); +#endif - current_readline_line_index = 0; - - if (!current_readline_line) + if (current_readline_line == 0) return (EOF); + current_readline_line_index = 0; line_len = strlen (current_readline_line); + current_readline_line = xrealloc (current_readline_line, 2 + line_len); current_readline_line[line_len++] = '\n'; current_readline_line[line_len] = '\0'; } - if (!current_readline_line[current_readline_line_index]) + if (current_readline_line[current_readline_line_index] == 0) { free (current_readline_line); current_readline_line = (char *)NULL; @@ -860,20 +943,21 @@ yy_readline_get () } else { - int c = (unsigned char)current_readline_line[current_readline_line_index++]; + c = (unsigned char)current_readline_line[current_readline_line_index++]; return (c); } } static int yy_readline_unget (c) + int c; { if (current_readline_line_index && current_readline_line) current_readline_line[--current_readline_line_index] = c; return (c); } -void +void with_input_from_stdin () { INPUT_STREAM location; @@ -904,7 +988,7 @@ with_input_from_stdin () static int yy_string_get () { - register unsigned char *string; + register char *string; register int c; string = bash_input.location.string; @@ -913,7 +997,7 @@ yy_string_get () /* If the string doesn't exist, or is empty, EOF found. */ if (string && *string) { - c = *string++; + c = *(unsigned char *)string++; bash_input.location.string = string; } return (c); @@ -929,13 +1013,11 @@ yy_string_unget (c) void with_input_from_string (string, name) - char *string; - char *name; + char *string, *name; { INPUT_STREAM location; location.string = string; - init_yy_io (yy_string_get, yy_string_unget, st_string, name, location); } @@ -951,11 +1033,14 @@ yy_stream_get () int result = EOF; if (bash_input.location.file) -#if defined (NO_READ_RESTART_ON_SIGNAL) - result = (unsigned char)getc_with_restart (bash_input.location.file); -#else - result = (unsigned char)getc (bash_input.location.file); -#endif /* !NO_READ_RESTART_ON_SIGNAL */ + { +#if !defined (HAVE_RESTARTABLE_SYSCALLS) + result = getc_with_restart (bash_input.location.file); +#else /* HAVE_RESTARTABLE_SYSCALLS */ + result = getc (bash_input.location.file); + result = (feof (bash_input.location.file)) ? EOF : (unsigned char)result; +#endif /* HAVE_RESTARTABLE_SYSCALLS */ + } return (result); } @@ -963,11 +1048,11 @@ static int yy_stream_unget (c) int c; { -#if defined (NO_READ_RESTART_ON_SIGNAL) +#if !defined (HAVE_RESTARTABLE_SYSCALLS) return (ungetc_with_restart (c, bash_input.location.file)); -#else +#else /* HAVE_RESTARTABLE_SYSCALLS */ return (ungetc (c, bash_input.location.file)); -#endif +#endif /* HAVE_RESTARTABLE_SYSCALLS */ } void @@ -995,7 +1080,9 @@ int line_number = 0; STREAM_SAVER *stream_list = (STREAM_SAVER *)NULL; -push_stream () +void +push_stream (reset_lineno) + int reset_lineno; { STREAM_SAVER *saver = (STREAM_SAVER *)xmalloc (sizeof (STREAM_SAVER)); @@ -1015,13 +1102,14 @@ push_stream () bash_input.name = (char *)NULL; saver->next = stream_list; stream_list = saver; - EOF_Reached = line_number = 0; + EOF_Reached = 0; + if (reset_lineno) + line_number = 0; } +void pop_stream () { - int temp; - if (!stream_list) EOF_Reached = 1; else @@ -1067,36 +1155,35 @@ pop_stream () /* Return 1 if a stream of type TYPE is saved on the stack. */ int stream_on_stack (type) - int type; + enum stream_type type; { register STREAM_SAVER *s; - + for (s = stream_list; s; s = s->next) if (s->bash_input.type == type) return 1; return 0; } - /* * This is used to inhibit alias expansion and reserved word recognition - * inside case statement pattern lists. A `case statement pattern list' - * is: + * inside case statement pattern lists. A `case statement pattern list' is: + * * everything between the `in' in a `case word in' and the next ')' * or `esac' * everything between a `;;' and the next `)' or `esac' */ -static int in_case_pattern_list = 0; #if defined (ALIAS) + +#define END_OF_ALIAS 0 + /* * Pseudo-global variables used in implementing token-wise alias expansion. */ -static int expand_next_token = 0; - /* - * Pushing and popping strings. This works together with shell_getc to + * Pushing and popping strings. This works together with shell_getc to * implement alias expansion on a per-token basis. */ @@ -1104,13 +1191,12 @@ typedef struct string_saver { struct string_saver *next; int expand_alias; /* Value to set expand_alias to when string is popped. */ char *saved_line; + alias_t *expander; /* alias that caused this line to be pushed. */ int saved_line_size, saved_line_index, saved_line_terminator; } STRING_SAVER; STRING_SAVER *pushed_string_list = (STRING_SAVER *)NULL; -static void save_expansion (); - /* * Push the current shell_input_line onto a stack of such lines and make S * the current input. Used when expanding aliases. EXPAND is used to set @@ -1120,10 +1206,10 @@ static void save_expansion (); * into S; it is saved and used to prevent infinite recursive expansion. */ static void -push_string (s, expand, token) +push_string (s, expand, ap) char *s; int expand; - char *token; + alias_t *ap; { STRING_SAVER *temp = (STRING_SAVER *) xmalloc (sizeof (STRING_SAVER)); @@ -1132,16 +1218,17 @@ push_string (s, expand, token) temp->saved_line_size = shell_input_line_size; temp->saved_line_index = shell_input_line_index; temp->saved_line_terminator = shell_input_line_terminator; + temp->expander = ap; temp->next = pushed_string_list; pushed_string_list = temp; - save_expansion (token); + ap->flags |= AL_BEINGEXPANDED; shell_input_line = s; shell_input_line_size = strlen (s); shell_input_line_index = 0; shell_input_line_terminator = '\0'; - expand_next_token = 0; + parser_state &= ~PST_ALEXPNEXT; } /* @@ -1160,102 +1247,38 @@ pop_string () shell_input_line_index = pushed_string_list->saved_line_index; shell_input_line_size = pushed_string_list->saved_line_size; shell_input_line_terminator = pushed_string_list->saved_line_terminator; - expand_next_token = pushed_string_list->expand_alias; + + if (pushed_string_list->expand_alias) + parser_state |= PST_ALEXPNEXT; + else + parser_state &= ~PST_ALEXPNEXT; t = pushed_string_list; pushed_string_list = pushed_string_list->next; - free((char *)t); + + t->expander->flags &= ~AL_BEINGEXPANDED; + + free ((char *)t); } static void free_string_list () { - register STRING_SAVER *t = pushed_string_list, *t1; + register STRING_SAVER *t, *t1; - while (t) + for (t = pushed_string_list; t; ) { t1 = t->next; FREE (t->saved_line); + t->expander->flags &= ~AL_BEINGEXPANDED; free ((char *)t); t = t1; } pushed_string_list = (STRING_SAVER *)NULL; } -/* This is a stack to save the values of all tokens for which alias - expansion has been performed during the current call to read_token (). - It is used to prevent alias expansion loops: - - alias foo=bar - alias bar=baz - alias baz=foo - - Ideally this would be taken care of by push and pop string, but because - of when strings are popped the stack will not contain the correct - strings to test against. (The popping is done in shell_getc, so that when - the current string is exhausted, shell_getc can simply pop that string off - the stack, restore the previous string, and continue with the character - following the token whose expansion was originally pushed on the stack.) - - What we really want is a record of all tokens that have been expanded for - aliases during the `current' call to read_token(). This does that, at the - cost of being somewhat special-purpose (OK, OK vile and unclean). */ - -typedef struct _exp_saver { - struct _exp_saver *next; - char *saved_token; -} EXPANSION_SAVER; - -EXPANSION_SAVER *expanded_token_stack = (EXPANSION_SAVER *)NULL; - -static void -save_expansion (s) - char *s; -{ - EXPANSION_SAVER *t; - - t = (EXPANSION_SAVER *) xmalloc (sizeof (EXPANSION_SAVER)); - t->saved_token = savestring (s); - t->next = expanded_token_stack; - expanded_token_stack = t; -} - -/* Return 1 if TOKEN has already been expanded in the current `stack' of - expansions. If it has been expanded already, it will appear as the value - of saved_token for some entry in the stack of expansions created for the - current token being expanded. */ -static int -token_has_been_expanded (token) - char *token; -{ - register EXPANSION_SAVER *t = expanded_token_stack; - - while (t) - { - if (STREQ (token, t->saved_token)) - return (1); - t = t->next; - } - return (0); -} - -static void -free_expansion_stack () -{ - register EXPANSION_SAVER *t = expanded_token_stack, *t1; - - while (t) - { - t1 = t->next; - free (t->saved_token); - free (t); - t = t1; - } - expanded_token_stack = (EXPANSION_SAVER *)NULL; -} - #endif /* ALIAS */ - + /* Return a line of text, taken from wherever yylex () reads input. If there is no more input, then we return NULL. If REMOVE_QUOTED_NEWLINE is non-zero, we remove unquoted \ pairs. This is used by @@ -1268,6 +1291,13 @@ read_a_line (remove_quoted_newline) static int buffer_size = 0; int indx = 0, c, peekc, pass_next; +#if defined (READLINE) + if (interactive && bash_input.type != st_string && no_line_editing) +#else + if (interactive && bash_input.type != st_string) +#endif + print_prompt (); + pass_next = 0; while (1) { @@ -1282,17 +1312,15 @@ read_a_line (remove_quoted_newline) /* If there is no more input, then we return NULL. */ if (c == EOF) { + if (interactive && bash_input.type == st_stream) + clearerr (stdin); if (indx == 0) return ((char *)NULL); c = '\n'; } /* `+2' in case the final character in the buffer is a newline. */ - if (indx + 2 > buffer_size) - if (!buffer_size) - line_buffer = xmalloc (buffer_size = 128); - else - line_buffer = xrealloc (line_buffer, buffer_size += 128); + RESIZE_MALLOCED_BUFFER (line_buffer, indx, 2, buffer_size, 128); /* IF REMOVE_QUOTED_NEWLINES is non-zero, we are reading a here document with an unquoted delimiter. In this case, @@ -1342,7 +1370,6 @@ read_secondary_line (remove_quoted_newline) return (read_a_line (remove_quoted_newline)); } - /* **************************************************************** */ /* */ /* YYLEX () */ @@ -1369,21 +1396,56 @@ STRING_INT_ALIST word_token_alist[] = { { "done", DONE }, { "in", IN }, { "function", FUNCTION }, +#if defined (COMMAND_TIMING) + { "time", TIME }, +#endif { "{", '{' }, { "}", '}' }, { "!", BANG }, { (char *)NULL, 0} }; +/* These are used by read_token_word, but appear up here so that shell_getc + can use them to decide when to add otherwise blank lines to the history. */ + +/* The primary delimiter stack. */ +struct dstack dstack = { (char *)NULL, 0, 0 }; + +/* A temporary delimiter stack to be used when decoding prompt strings. + This is needed because command substitutions in prompt strings (e.g., PS2) + can screw up the parser's quoting state. */ +static struct dstack temp_dstack = { (char *)NULL, 0, 0 }; + +/* Macro for accessing the top delimiter on the stack. Returns the + delimiter or zero if none. */ +#define current_delimiter(ds) \ + (ds.delimiter_depth ? ds.delimiters[ds.delimiter_depth - 1] : 0) + +#define push_delimiter(ds, character) \ + do \ + { \ + if (ds.delimiter_depth + 2 > ds.delimiter_space) \ + ds.delimiters = xrealloc \ + (ds.delimiters, (ds.delimiter_space += 10) * sizeof (char)); \ + ds.delimiters[ds.delimiter_depth] = character; \ + ds.delimiter_depth++; \ + } \ + while (0) + +#define pop_delimiter(ds) ds.delimiter_depth-- + /* Return the next shell input character. This always reads characters from shell_input_line; when that line is exhausted, it is time to read the next line. This is called by read_token when the shell is processing normal command input. */ + static int shell_getc (remove_quoted_newline) int remove_quoted_newline; { + register int i; int c; + static int mustpop = 0; QUIT; @@ -1398,10 +1460,6 @@ shell_getc (remove_quoted_newline) if (!shell_input_line || !shell_input_line[shell_input_line_index]) #endif /* !ALIAS */ { - register int i, l; - - restart_read_next_line: - line_number++; restart_read: @@ -1437,16 +1495,14 @@ shell_getc (remove_quoted_newline) /* Allow immediate exit if interrupted during input. */ QUIT; - if (i + 2 > shell_input_line_size) - shell_input_line = - xrealloc (shell_input_line, shell_input_line_size += 256); + RESIZE_MALLOCED_BUFFER (shell_input_line, i, 2, shell_input_line_size, 256); if (c == EOF) { if (bash_input.type == st_stream) clearerr (stdin); - if (!i) + if (i == 0) shell_input_line_terminator = EOF; shell_input_line[i] = '\0'; @@ -1466,11 +1522,23 @@ shell_getc (remove_quoted_newline) shell_input_line_len = i; /* == strlen (shell_input_line) */ #if defined (HISTORY) - if (interactive && shell_input_line && shell_input_line[0]) + if (remember_on_history && shell_input_line && shell_input_line[0]) { char *expansions; - +# if defined (BANG_HISTORY) + int old_hist; + + /* If the current delimiter is a single quote, we should not be + performing history expansion, even if we're on a different + line from the original single quote. */ + old_hist = history_expansion_inhibited; + if (current_delimiter (dstack) == '\'') + history_expansion_inhibited = 1; +# endif expansions = pre_process_line (shell_input_line, 1, 1); +# if defined (BANG_HISTORY) + history_expansion_inhibited = old_hist; +# endif free (shell_input_line); shell_input_line = expansions; @@ -1484,6 +1552,18 @@ shell_getc (remove_quoted_newline) true allocated size of shell_input_line anymore. */ shell_input_line_size = shell_input_line_len; } + /* XXX - this is grotesque */ + else if (remember_on_history && shell_input_line && + shell_input_line[0] == '\0' && + current_command_line_count > 1 && current_delimiter (dstack)) + { + /* We know shell_input_line[0] == 0 and we're reading some sort of + quoted string. This means we've got a line consisting of only + a newline in a quoted string. We want to make sure this line + gets added to the history. */ + maybe_add_history (shell_input_line); + } + #endif /* HISTORY */ if (shell_input_line) @@ -1506,17 +1586,15 @@ shell_getc (remove_quoted_newline) not already end in an EOF character. */ if (shell_input_line_terminator != EOF) { - l = shell_input_line_len; /* was a call to strlen */ - - if (l + 3 > shell_input_line_size) + if (shell_input_line_len + 3 > shell_input_line_size) shell_input_line = xrealloc (shell_input_line, 1 + (shell_input_line_size += 2)); - shell_input_line[l] = '\n'; - shell_input_line[l + 1] = '\0'; + shell_input_line[shell_input_line_len] = '\n'; + shell_input_line[shell_input_line_len + 1] = '\0'; } } - + c = shell_input_line[shell_input_line_index]; if (c) @@ -1526,7 +1604,8 @@ shell_getc (remove_quoted_newline) shell_input_line[shell_input_line_index] == '\n') { prompt_again (); - goto restart_read_next_line; + line_number++; + goto restart_read; } #if defined (ALIAS) @@ -1537,20 +1616,24 @@ shell_getc (remove_quoted_newline) to. */ if (!c && (pushed_string_list != (STRING_SAVER *)NULL)) { - pop_string (); - c = shell_input_line[shell_input_line_index]; - if (c) - shell_input_line_index++; + if (mustpop) + { + pop_string (); + c = shell_input_line[shell_input_line_index]; + if (c) + shell_input_line_index++; + mustpop--; + } + else + { + mustpop++; + c = ' '; + } } #endif /* ALIAS */ if (!c && shell_input_line_terminator == EOF) - { - if (shell_input_line_index != 0) - return ('\n'); - else - return (EOF); - } + return ((shell_input_line_index != 0) ? '\n' : EOF); return ((unsigned char)c); } @@ -1564,7 +1647,15 @@ shell_ungetc (c) shell_input_line[--shell_input_line_index] = c; } -/* Discard input until CHARACTER is seen. */ +static void +shell_ungetchar () +{ + if (shell_input_line && shell_input_line_index) + shell_input_line_index--; +} + +/* Discard input until CHARACTER is seen, then push that character back + onto the input stream. */ static void discard_until (character) int character; @@ -1577,13 +1668,6 @@ discard_until (character) if (c != EOF) shell_ungetc (c); } - -/* Place to remember the token. We try to keep the buffer - at a reasonable size, but it can grow. */ -static char *token = (char *)NULL; - -/* Current size of the token buffer. */ -static int token_buffer_size = 0; void execute_prompt_command (command) @@ -1611,10 +1695,17 @@ execute_prompt_command (command) bind_variable ("_", last_lastarg); FREE (last_lastarg); - if (token_to_read == '\n') + if (token_to_read == '\n') /* reset_parser was called */ token_to_read = 0; } +/* Place to remember the token. We try to keep the buffer + at a reasonable size, but it can grow. */ +static char *token = (char *)NULL; + +/* Current size of the token buffer. */ +static int token_buffer_size; + /* Command to read_token () explaining what we want it to do. */ #define READ 0 #define RESET 1 @@ -1623,10 +1714,10 @@ execute_prompt_command (command) /* Function for yyparse to call. yylex keeps track of the last two tokens read, and calls read_token. */ - +static int yylex () { - if (interactive && (!current_token || current_token == '\n')) + if (interactive && (current_token == 0 || current_token == '\n')) { /* Before we print a prompt, we might have to check mailboxes. We do this only if it is time to do so. Notice that only here @@ -1644,35 +1735,16 @@ yylex () prompt_again (); } + two_tokens_ago = token_before_that; token_before_that = last_read_token; last_read_token = current_token; current_token = read_token (READ); return (current_token); } -/* Called from shell.c when Control-C is typed at top level. Or - by the error rule at top level. */ -reset_parser () -{ - read_token (RESET); -} - /* When non-zero, we have read the required tokens which allow ESAC to be the next one read. */ -static int allow_esac_as_next = 0; - -/* When non-zero, accept single '{' as a token itself. */ -static int allow_open_brace = 0; - -/* DELIMITERS is a stack of the nested delimiters that we have - encountered so far. */ -static char *delimiters = (char *)NULL; - -/* Offset into the stack of delimiters. */ -int delimiter_depth = 0; - -/* How many slots are allocated to DELIMITERS. */ -static int delimiter_space = 0; +static int esacs_needed_count; void gather_here_documents () @@ -1685,32 +1757,16 @@ gather_here_documents () } } -/* Macro for accessing the top delimiter on the stack. Returns the - delimiter or zero if none. */ -#define current_delimiter() \ - (delimiter_depth ? delimiters[delimiter_depth - 1] : 0) - -#define push_delimiter(character) \ - do \ - { \ - if (delimiter_depth + 2 > delimiter_space) \ - delimiters = xrealloc \ - (delimiters, (delimiter_space += 10) * sizeof (char)); \ - delimiters[delimiter_depth] = character; \ - delimiter_depth++; \ - } \ - while (0) - /* When non-zero, an open-brace used to create a group is awaiting a close brace partner. */ -static int open_brace_awaiting_satisfaction = 0; +static int open_brace_count; #define command_token_position(token) \ (((token) == ASSIGNMENT_WORD) || \ ((token) != SEMI_SEMI && reserved_word_acceptable(token))) #define assignment_acceptable(token) command_token_position(token) && \ - (in_case_pattern_list == 0) + ((parser_state & PST_CASEPAT) == 0) /* Check to see if TOKEN is a reserved word and return the token value if it is. */ @@ -1723,101 +1779,217 @@ static int open_brace_awaiting_satisfaction = 0; for (i = 0; word_token_alist[i].word != (char *)NULL; i++) \ if (STREQ (tok, word_token_alist[i].word)) \ { \ - if (in_case_pattern_list && (word_token_alist[i].token != ESAC)) \ + if ((parser_state & PST_CASEPAT) && (word_token_alist[i].token != ESAC)) \ break; \ -\ if (word_token_alist[i].token == ESAC) \ - in_case_pattern_list = 0; \ -\ - if (word_token_alist[i].token == '{') \ - open_brace_awaiting_satisfaction++; \ -\ - if (word_token_alist[i].token == '}' && open_brace_awaiting_satisfaction) \ - open_brace_awaiting_satisfaction--; \ -\ + parser_state &= ~(PST_CASEPAT|PST_CASESTMT); \ + else if (word_token_alist[i].token == CASE) \ + parser_state |= PST_CASESTMT; \ + else if (word_token_alist[i].token == '{') \ + open_brace_count++; \ + else if (word_token_alist[i].token == '}' && open_brace_count) \ + open_brace_count--; \ return (word_token_alist[i].token); \ } \ } \ } while (0) -/* Read the next token. Command can be READ (normal operation) or - RESET (to normalize state). */ -static int -read_token (command) - int command; +#if defined (ALIAS) + + /* OK, we have a token. Let's try to alias expand it, if (and only if) + it's eligible. + + It is eligible for expansion if the shell is in interactive mode, and + the token is unquoted and the last token read was a command + separator (or expand_next_token is set), and we are currently + processing an alias (pushed_string_list is non-empty) and this + token is not the same as the current or any previously + processed alias. + + Special cases that disqualify: + In a pattern list in a case statement (parser_state & PST_CASEPAT). */ +static int +alias_expand_token (token) + char *token; { - int character; /* Current character. */ - int peek_char; /* Temporary look-ahead character. */ - int result; /* The thing to return. */ - WORD_DESC *the_word; /* The value for YYLVAL when a WORD is read. */ + char *expanded; + alias_t *ap; - if (token_buffer_size < TOKEN_DEFAULT_GROW_SIZE) + if (((parser_state & PST_ALEXPNEXT) || command_token_position (last_read_token)) && + (parser_state & PST_CASEPAT) == 0) { - FREE (token); - token = xmalloc (token_buffer_size = TOKEN_DEFAULT_GROW_SIZE); + ap = find_alias (token); + + /* Currently expanding this token. */ + if (ap && (ap->flags & AL_BEINGEXPANDED)) + return (NO_EXPANSION); + + expanded = ap ? savestring (ap->value) : (char *)NULL; + if (expanded) + { + push_string (expanded, ap->flags & AL_EXPANDNEXT, ap); + return (RE_READ_TOKEN); + } + else + /* This is an eligible token that does not have an expansion. */ + return (NO_EXPANSION); } + return (NO_EXPANSION); +} +#endif /* ALIAS */ - if (command == RESET) +/* Handle special cases of token recognition: + IN is recognized if the last token was WORD and the token + before that was FOR or CASE or SELECT. + + DO is recognized if the last token was WORD and the token + before that was FOR or SELECT. + + ESAC is recognized if the last token caused `esacs_needed_count' + to be set + + `{' is recognized if the last token as WORD and the token + before that was FUNCTION. + + `}' is recognized if there is an unclosed `{' prsent. +*/ + +static int +special_case_tokens (token) + char *token; +{ + if ((last_read_token == WORD) && +#if defined (SELECT_COMMAND) + ((token_before_that == FOR) || (token_before_that == CASE) || (token_before_that == SELECT)) && +#else + ((token_before_that == FOR) || (token_before_that == CASE)) && +#endif + (token[0] == 'i' && token[1] == 'n' && token[2] == 0)) { - delimiter_depth = 0; /* No delimiters found so far. */ - open_brace_awaiting_satisfaction = 0; - in_case_pattern_list = 0; + if (token_before_that == CASE) + { + parser_state |= PST_CASEPAT; + esacs_needed_count++; + } + return (IN); + } -#if defined (ALIAS) - if (pushed_string_list) + if (last_read_token == WORD && +#if defined (SELECT_COMMAND) + (token_before_that == FOR || token_before_that == SELECT) && +#else + (token_before_that == FOR) && +#endif + (token[0] == 'd' && token[1] == 'o' && token[2] == '\0')) + return (DO); + + /* Ditto for ESAC in the CASE case. + Specifically, this handles "case word in esac", which is a legal + construct, certainly because someone will pass an empty arg to the + case construct, and we don't want it to barf. Of course, we should + insist that the case construct has at least one pattern in it, but + the designers disagree. */ + if (esacs_needed_count) + { + esacs_needed_count--; + if (STREQ (token, "esac")) { - free_string_list (); - pushed_string_list = (STRING_SAVER *)NULL; + parser_state &= ~PST_CASEPAT; + return (ESAC); } + } - if (expanded_token_stack) + /* The start of a shell function definition. */ + if (parser_state & PST_ALLOWOPNBRC) + { + parser_state &= ~PST_ALLOWOPNBRC; + if (token[0] == '{' && token[1] == '\0') /* } */ { - free_expansion_stack (); - expanded_token_stack = (EXPANSION_SAVER *)NULL; + open_brace_count++; + function_bstart = line_number; + return ('{'); /* } */ } + } + + if (open_brace_count && reserved_word_acceptable (last_read_token) && token[0] == '}' && !token[1]) + { + open_brace_count--; /* { */ + return ('}'); + } + + /* Handle -p after `time'. */ + if (last_read_token == TIME && token[0] == '-' && token[1] == 'p' && !token[2]) + return (TIMEOPT); - expand_next_token = 0; + return (-1); +} + +/* Called from shell.c when Control-C is typed at top level. Or + by the error rule at top level. */ +void +reset_parser () +{ + dstack.delimiter_depth = 0; /* No delimiters found so far. */ + open_brace_count = 0; + + parser_state = 0; + +#if defined (ALIAS) + if (pushed_string_list) + { + free_string_list (); + pushed_string_list = (STRING_SAVER *)NULL; + } #endif /* ALIAS */ - if (shell_input_line) - { - free (shell_input_line); - shell_input_line = (char *)NULL; - shell_input_line_size = shell_input_line_index = 0; - } - last_read_token = '\n'; - token_to_read = '\n'; + if (shell_input_line) + { + free (shell_input_line); + shell_input_line = (char *)NULL; + shell_input_line_size = shell_input_line_index = 0; + } + + FREE (word_desc_to_read); + word_desc_to_read = (WORD_DESC *)NULL; + + last_read_token = '\n'; + token_to_read = '\n'; +} + +/* Read the next token. Command can be READ (normal operation) or + RESET (to normalize state). */ +static int +read_token (command) + int command; +{ + int character; /* Current character. */ + int peek_char; /* Temporary look-ahead character. */ + int result; /* The thing to return. */ + + if (command == RESET) + { + reset_parser (); return ('\n'); } if (token_to_read) { - int rt = token_to_read; + result = token_to_read; + if (token_to_read == WORD || token_to_read == ASSIGNMENT_WORD) + yylval.word = word_desc_to_read; token_to_read = 0; - return (rt); + return (result); } #if defined (ALIAS) - /* If we hit read_token () and there are no saved strings on the - pushed_string_list, then we are no longer currently expanding a - token. This can't be done in pop_stream, because pop_stream - may pop the stream before the current token has finished being - completely expanded (consider what happens when we alias foo to foo, - and then try to expand it). */ - if (!pushed_string_list && expanded_token_stack) - { - free_expansion_stack (); - expanded_token_stack = (EXPANSION_SAVER *)NULL; - } - /* This is a place to jump back to once we have successfully expanded a token with an alias and pushed the string with push_string () */ re_read_token: - #endif /* ALIAS */ /* Read a single word from input. Start by skipping blanks. */ - while ((character = shell_getc (1)) != EOF && whitespace (character)); + while ((character = shell_getc (1)) != EOF && whitespace (character)) + ; if (character == EOF) { @@ -1830,17 +2002,7 @@ read_token (command) /* A comment. Discard until EOL or EOF, and then return a newline. */ discard_until ('\n'); shell_getc (0); - - /* If we're about to return an unquoted newline, we can go and collect - the text of any pending here documents. */ - if (need_here_doc) - gather_here_documents (); - -#if defined (ALIAS) - expand_next_token = 0; -#endif /* ALIAS */ - - return ('\n'); + character = '\n'; /* this will take the next if statement and return. */ } if (character == '\n') @@ -1851,31 +2013,30 @@ read_token (command) gather_here_documents (); #if defined (ALIAS) - expand_next_token = 0; + parser_state &= ~PST_ALEXPNEXT; #endif /* ALIAS */ return (character); } - if (member (character, "()<>;&|")) + /* Shell meta-characters. */ + if (shellmeta (character) && ((parser_state & PST_DBLPAREN) == 0)) { #if defined (ALIAS) /* Turn off alias tokenization iff this character sequence would not leave us ready to read a command. */ if (character == '<' || character == '>') - expand_next_token = 0; + parser_state &= ~PST_ALEXPNEXT; #endif /* ALIAS */ - /* Please note that the shell does not allow whitespace to - appear in between tokens which are character pairs, such as - "<<" or ">>". I believe this is the correct behaviour. */ - if (character == (peek_char = shell_getc (1))) + peek_char = shell_getc (1); + if (character == peek_char) { switch (character) { + case '<': /* If '<' then we could be at "<<" or at "<<-". We have to look ahead one more character. */ - case '<': peek_char = shell_getc (1); if (peek_char == '-') return (LESS_LESS_MINUS); @@ -1889,9 +2050,9 @@ read_token (command) return (GREATER_GREATER); case ';': - in_case_pattern_list = 1; + parser_state |= PST_CASEPAT; #if defined (ALIAS) - expand_next_token = 0; + parser_state &= ~PST_ALEXPNEXT; #endif /* ALIAS */ return (SEMI_SEMI); @@ -1900,526 +2061,637 @@ read_token (command) case '|': return (OR_OR); - } - } - else - { - if (peek_char == '&') - { - switch (character) + +#if defined (DPAREN_ARITHMETIC) + case '(': /* ) */ + if (reserved_word_acceptable (last_read_token)) { - case '<': return (LESS_AND); - case '>': return (GREATER_AND); + parser_state |= PST_DBLPAREN; + yylval.word = make_word ("let"); + return (WORD); } + break; +#endif } - if (character == '<' && peek_char == '>') - return (LESS_GREATER); - if (character == '>' && peek_char == '|') - return (GREATER_BAR); - if (peek_char == '>' && character == '&') - return (AND_GREATER); } + else if (character == '<' && peek_char == '&') + return (LESS_AND); + else if (character == '>' && peek_char == '&') + return (GREATER_AND); + else if (character == '<' && peek_char == '>') + return (LESS_GREATER); + else if (character == '>' && peek_char == '|') + return (GREATER_BAR); + else if (peek_char == '>' && character == '&') + return (AND_GREATER); + shell_ungetc (peek_char); /* If we look like we are reading the start of a function definition, then let the reader know about it so that we will do the right thing with `{'. */ - if (character == ')' && - last_read_token == '(' && token_before_that == WORD) + if (character == ')' && last_read_token == '(' && token_before_that == WORD) { - allow_open_brace = 1; + parser_state |= PST_ALLOWOPNBRC; #if defined (ALIAS) - expand_next_token = 0; + parser_state &= ~PST_ALEXPNEXT; #endif /* ALIAS */ + function_dstart = line_number; } - if (in_case_pattern_list && (character == ')')) - in_case_pattern_list = 0; + /* case pattern lists may be preceded by an optional left paren. If + we're not trying to parse a case pattern list, the left paren + indicates a subshell. */ + if (character == '(' && (parser_state & PST_CASEPAT) == 0) /* ) */ + parser_state |= PST_SUBSHELL; + /*(*/ + else if ((parser_state & PST_CASEPAT) && character == ')') + parser_state &= ~PST_CASEPAT; + /*(*/ + else if ((parser_state & PST_SUBSHELL) && character == ')') + parser_state &= ~PST_SUBSHELL; #if defined (PROCESS_SUBSTITUTION) /* Check for the constructs which introduce process substitution. Shells running in `posix mode' don't do process substitution. */ if (posixly_correct || - (((character == '>' || character == '<') && peek_char == '(') == 0)) + ((character != '>' && character != '<') || peek_char != '(')) #endif /* PROCESS_SUBSTITUTION */ return (character); } /* Hack <&- (close stdin) case. */ - if (character == '-') - { - switch (last_read_token) - { - case LESS_AND: - case GREATER_AND: - return (character); - } - } - + if (character == '-' && (last_read_token == LESS_AND || last_read_token == GREATER_AND)) + return (character); + /* Okay, if we got this far, we have to read a word. Read one, and then check it against the known ones. */ - { - /* Index into the token that we are building. */ - int token_index = 0; - - /* ALL_DIGITS becomes zero when we see a non-digit. */ - int all_digits = digit (character); + result = read_token_word (character); +#if defined (ALIAS) + if (result == RE_READ_TOKEN) + goto re_read_token; +#endif + return result; +} - /* DOLLAR_PRESENT becomes non-zero if we see a `$'. */ - int dollar_present = 0; +/* Match a $(...) or other grouping construct. This has to handle embedded + quoted strings ('', ``, "") and nested constructs. It also must handle + reprompting the user, if necessary, after reading a newline, and returning + correct error values if it reads EOF. */ +static char matched_pair_error; +static char * +parse_matched_pair (qc, open, close, lenp, flags) + int qc; /* `"' if this construct is within double quotes */ + int open, close; + int *lenp, flags; +{ + int count, ch, was_dollar; + int pass_next_character, nestlen, start_lineno; + char *ret, *nestret; + int retind, retsize; - /* QUOTED becomes non-zero if we see one of ("), ('), (`), or (\). */ - int quoted = 0; + count = 1; + pass_next_character = was_dollar = 0; - /* Non-zero means to ignore the value of the next character, and just - to add it no matter what. */ - int pass_next_character = 0; + ret = xmalloc (retsize = 64); + retind = 0; - /* Non-zero means parsing a dollar-paren construct. It is the count of - un-quoted closes we need to see. */ - int dollar_paren_level = 0; + start_lineno = line_number; + while (count) + { + ch = shell_getc (qc != '\'' && pass_next_character == 0); + if (ch == EOF) + { + free (ret); + parser_error (start_lineno, "unexpected EOF while looking for matching `%c'", close); + EOF_Reached = 1; /* XXX */ + return (&matched_pair_error); + } - /* Non-zero means parsing a dollar-bracket construct ($[...]). It is - the count of un-quoted `]' characters we need to see. */ - int dollar_bracket_level = 0; + /* Possible reprompting. */ + if (ch == '\n' && interactive && + (bash_input.type == st_stdin || bash_input.type == st_stream)) + prompt_again (); - /* Non-zero means parsing a `${' construct. It is the count of - un-quoted `}' we need to see. */ - int dollar_brace_level = 0; + if (pass_next_character) /* last char was backslash */ + { + pass_next_character = 0; + if (qc != '\'' && ch == '\n') /* double-quoted \ disappears. */ + { + if (retind > 0) retind--; /* swallow previously-added backslash */ + continue; + } - /* A level variable for parsing '${ ... }' constructs inside of double - quotes. */ - int delimited_brace_level = 0; + RESIZE_MALLOCED_BUFFER (ret, retind, 2, retsize, 64); + if (ch == CTLESC || ch == CTLNUL) + ret[retind++] = CTLESC; + ret[retind++] = ch; + continue; + } + else if (ch == CTLESC || ch == CTLNUL) /* special shell escapes */ + { + RESIZE_MALLOCED_BUFFER (ret, retind, 2, retsize, 64); + ret[retind++] = CTLESC; + ret[retind++] = ch; + continue; + } + else if (ch == close) /* ending delimiter */ + count--; + else if (ch == open) /* nested begin */ + count++; - /* A boolean variable denoting whether or not we are currently parsing - a double-quoted string embedded in a $( ) or ${ } construct. */ - int embedded_quoted_string = 0; + /* Add this character. */ + RESIZE_MALLOCED_BUFFER (ret, retind, 1, retsize, 64); + ret[retind++] = ch; - /* Another level variable. This one is for dollar_parens inside of - double-quotes. */ - int delimited_paren_level = 0; + if (open == '\'') /* '' inside grouping construct */ + continue; - /* The current delimiting character. */ - int cd; + if (ch == '\\') /* backslashes */ + pass_next_character++; - for (;;) - { - if (character == EOF) - goto got_token; + if (open != close) /* a grouping construct */ + { + if (shellquote (ch)) + { + /* '', ``, or "" inside $(...) or other grouping construct. */ + push_delimiter (dstack, ch); + nestret = parse_matched_pair (ch, ch, ch, &nestlen, 0); + pop_delimiter (dstack); + if (nestret == &matched_pair_error) + { + free (ret); + return &matched_pair_error; + } + if (nestlen) + { + RESIZE_MALLOCED_BUFFER (ret, retind, nestlen, retsize, 64); + strcpy (ret + retind, nestret); + retind += nestlen; + } + FREE (nestret); + } + } + /* Parse an old-style command substitution within double quotes as a + single word. */ + /* XXX - sh and ksh93 don't do this - XXX */ + else if (open == '"' && ch == '`') + { + nestret = parse_matched_pair (0, '`', '`', &nestlen, 0); + if (nestret == &matched_pair_error) + { + free (ret); + return &matched_pair_error; + } + if (nestlen) + { + RESIZE_MALLOCED_BUFFER (ret, retind, nestlen, retsize, 64); + strcpy (ret + retind, nestret); + retind += nestlen; + } + FREE (nestret); + } + else if (was_dollar && (ch == '(' || ch == '{' || ch == '[')) /* ) } ] */ + /* check for $(), $[], or ${} inside quoted string. */ + { + if (open == ch) /* undo previous increment */ + count--; + if (ch == '(') /* ) */ + nestret = parse_matched_pair (0, '(', ')', &nestlen, 0); + else if (ch == '{') /* } */ + nestret = parse_matched_pair (0, '{', '}', &nestlen, 0); + else if (ch == '[') /* ] */ + nestret = parse_matched_pair (0, '[', ']', &nestlen, 0); + if (nestret == &matched_pair_error) + { + free (ret); + return &matched_pair_error; + } + if (nestlen) + { + RESIZE_MALLOCED_BUFFER (ret, retind, nestlen, retsize, 64); + strcpy (ret + retind, nestret); + retind += nestlen; + } + FREE (nestret); + } + was_dollar = (ch == '$'); + } - if (pass_next_character) - { - pass_next_character = 0; - goto got_character; - } + ret[retind] = '\0'; + if (lenp) + *lenp = retind; + return ret; +} - cd = current_delimiter (); +static int +read_token_word (character) + int character; +{ + /* The value for YYLVAL when a WORD is read. */ + WORD_DESC *the_word; - if (cd && character == '\\' && cd != '\'') - { - peek_char = shell_getc (0); - if (peek_char != '\\') - shell_ungetc (peek_char); - else - { - token[token_index++] = character; - goto got_character; - } - } - - /* Handle backslashes. Quote lots of things when not inside of - double-quotes, quote some things inside of double-quotes. */ - - if (character == '\\' && (!delimiter_depth || cd != '\'')) - { - peek_char = shell_getc (0); - - /* Backslash-newline is ignored in all cases excepting - when quoted with single quotes. */ - if (peek_char == '\n') - { - character = '\n'; - goto next_character; - } - else - { - shell_ungetc (peek_char); + /* Index into the token that we are building. */ + int token_index; - /* If the next character is to be quoted, do it now. */ - if (!cd || cd == '`' || - (cd == '"' && member (peek_char, slashify_in_quotes))) - { - pass_next_character++; - quoted = 1; - goto got_character; - } - } - } - - /* This is a hack, in its present form. If a backquote substitution - appears within double quotes, everything within the backquotes - should be read as part of a single word. Jesus. Now I see why - Korn introduced the $() form. */ - if (delimiter_depth && (cd == '"') && (character == '`')) - { - push_delimiter (character); - goto got_character; - } - - cd = current_delimiter (); /* XXX - may not need */ - if (delimiter_depth) - { - if (character == cd) - { - /* If we see a double quote while parsing a double-quoted - $( ) or ${ }, and we have not seen ) or }, respectively, - note that we are in the middle of reading an embedded - quoted string. */ - if ((delimited_paren_level || delimited_brace_level) && - (character == '"')) - { - embedded_quoted_string = !embedded_quoted_string; - goto got_character; - } - - delimiter_depth--; - goto got_character; - } - } + /* ALL_DIGITS becomes zero when we see a non-digit. */ + int all_digits; - if (cd != '\'') - { -#if defined (PROCESS_SUBSTITUTION) - if (character == '$' || character == '<' || character == '>') -#else - if (character == '$') -#endif /* !PROCESS_SUBSTITUTION */ - { - /* If we're in the middle of parsing a $( ) or ${ } - construct with an embedded quoted string, don't - bother looking at this character any further. */ - if (embedded_quoted_string) - goto got_character; - - peek_char = shell_getc (1); - shell_ungetc (peek_char); - if (peek_char == '(') - { - if (!delimiter_depth) - dollar_paren_level++; - else - delimited_paren_level++; + /* DOLLAR_PRESENT becomes non-zero if we see a `$'. */ + int dollar_present; - pass_next_character++; - goto got_character; - } - else if (peek_char == '[' && character == '$') - { - if (!delimiter_depth) - dollar_bracket_level++; + /* QUOTED becomes non-zero if we see one of ("), ('), (`), or (\). */ + int quoted; - pass_next_character++; - goto got_character; - } - /* This handles ${...} constructs. */ - else if (peek_char == '{' && character == '$') - { - if (!delimiter_depth) - dollar_brace_level++; - else - delimited_brace_level++; + /* Non-zero means to ignore the value of the next character, and just + to add it no matter what. */ + int pass_next_character; - pass_next_character++; - goto got_character; - } - } + /* The current delimiting character. */ + int cd; + int result, peek_char; + char *ttok, *ttrans; + int ttoklen, ttranslen; - /* If we are parsing a $() or $[] construct, we need to balance - parens and brackets inside the construct. This whole function - could use a rewrite. */ - if (character == '(' && !embedded_quoted_string) - { - if (delimiter_depth && delimited_paren_level) - delimited_paren_level++; + if (token_buffer_size < TOKEN_DEFAULT_GROW_SIZE) + { + FREE (token); + token = xmalloc (token_buffer_size = TOKEN_DEFAULT_GROW_SIZE); + } - if (!delimiter_depth && dollar_paren_level) - dollar_paren_level++; - } + token_index = 0; + all_digits = digit (character); + dollar_present = quoted = pass_next_character = 0; - if (character == '[') - { - if (!delimiter_depth && dollar_bracket_level) - dollar_bracket_level++; - } + for (;;) + { + if (character == EOF) + goto got_token; - if (character == '{' && !embedded_quoted_string) - { - if (delimiter_depth && delimited_brace_level) - delimited_brace_level++; + if (pass_next_character) + { + pass_next_character = 0; + goto got_character; + } - if (!delimiter_depth && dollar_brace_level) - dollar_brace_level++; - } + cd = current_delimiter (dstack); - /* This code needs to take into account whether we are inside a - case statement pattern list, and whether this paren is supposed - to terminate it (hey, it could happen). It's not as simple - as just using in_case_pattern_list, because we're not parsing - anything while we're reading a $( ) construct. Maybe we - should move that whole mess into the yacc parser. */ - if (character == ')' && !embedded_quoted_string) - { - if (delimiter_depth && delimited_paren_level) - delimited_paren_level--; + /* Handle backslashes. Quote lots of things when not inside of + double-quotes, quote some things inside of double-quotes. */ + if (character == '\\') + { + peek_char = shell_getc (0); - if (!delimiter_depth && dollar_paren_level) - { - dollar_paren_level--; - goto got_character; - } - } + /* Backslash-newline is ignored in all cases except + when quoted with single quotes. */ + if (peek_char == '\n') + { + character = '\n'; + goto next_character; + } + else + { + shell_ungetc (peek_char); - if (character == ']') - { - if (!delimiter_depth && dollar_bracket_level) - { - dollar_bracket_level--; - goto got_character; - } - } + /* If the next character is to be quoted, note it now. */ + if (cd == 0 || cd == '`' || + (cd == '"' && member (peek_char, slashify_in_quotes))) + pass_next_character++; - if (character == '}' && !embedded_quoted_string) - { - if (delimiter_depth && delimited_brace_level) - delimited_brace_level--; + quoted = 1; + goto got_character; + } + } - if (!delimiter_depth && dollar_brace_level) - { - dollar_brace_level--; - goto got_character; - } - } - } +#if defined (DPAREN_ARITHMETIC) + /* Parse a ksh-style ((...)) expression. */ + if (parser_state & PST_DBLPAREN) + { + int exp_lineno; - if (!dollar_paren_level && !dollar_bracket_level && - !dollar_brace_level && !delimiter_depth && - member (character, " \t\n;&()|<>")) - { + /* If we've already consumed a right paren that should be part of + the expression, push it back so the paren matching code won't + return prematurely. */ + if (character == '(') /* ) */ shell_ungetc (character); - goto got_token; - } - - if (!delimiter_depth) - { - if (character == '"' || character == '`' || character == '\'') - { - push_delimiter (character); - - quoted = 1; - goto got_character; - } - } - - if (all_digits) - all_digits = digit (character); - if (character == '$') - dollar_present = 1; + exp_lineno = line_number; + ttok = parse_matched_pair (0, '(', ')', &ttoklen, 0); + parser_state &= ~PST_DBLPAREN; + if (ttok == &matched_pair_error) + return -1; + /* Check that the next character is the closing right paren. If + not, this is a syntax error. ( */ + if (shell_getc (0) != ')') + { + FREE (ttok); /* ( */ + parser_error (exp_lineno, "missing closing `)' for arithmetic expression"); + return -1; + } + RESIZE_MALLOCED_BUFFER (token, token_index, ttoklen + 4, + token_buffer_size, TOKEN_DEFAULT_GROW_SIZE); + token[token_index++] = '"'; + if (character != '(') /* ) */ + token[token_index++] = character; + strncpy (token + token_index, ttok, ttoklen - 1); + token_index += ttoklen - 1; + token[token_index++] = '"'; + FREE (ttok); + dollar_present = all_digits = 0; + quoted = 1; + goto got_token; + } +#endif /* DPAREN_ARITHMETIC */ - got_character: + /* Parse a matched pair of quote characters. */ + if (shellquote (character)) + { + push_delimiter (dstack, character); + ttok = parse_matched_pair (character, character, character, &ttoklen, 0); + pop_delimiter (dstack); + if (ttok == &matched_pair_error) + return -1; /* Bail immediately. */ + RESIZE_MALLOCED_BUFFER (token, token_index, ttoklen + 2, + token_buffer_size, TOKEN_DEFAULT_GROW_SIZE); + token[token_index++] = character; + strcpy (token + token_index, ttok); + token_index += ttoklen; + all_digits = 0; + quoted = 1; + dollar_present |= (character == '"' && strchr (ttok, '$') != 0); + FREE (ttok); + goto next_character; + } - if (character == CTLESC || character == CTLNUL) - token[token_index++] = CTLESC; + /* If the delimiter character is not single quote, parse some of + the shell expansions that must be read as a single word. */ +#if defined (PROCESS_SUBSTITUTION) + if (character == '$' || character == '<' || character == '>') +#else + if (character == '$') +#endif /* !PROCESS_SUBSTITUTION */ + { + peek_char = shell_getc (1); + /* $(...), <(...), >(...), $((...)), ${...}, and $[...] constructs */ + if (peek_char == '(' || + ((peek_char == '{' || peek_char == '[') && character == '$')) /* ) ] } */ + { + if (peek_char == '{') /* } */ + ttok = parse_matched_pair (cd, '{', '}', &ttoklen, 0); + else if (peek_char == '(') /* ) */ + ttok = parse_matched_pair (cd, '(', ')', &ttoklen, 0); + else + ttok = parse_matched_pair (cd, '[', ']', &ttoklen, 0); + if (ttok == &matched_pair_error) + return -1; /* Bail immediately. */ + RESIZE_MALLOCED_BUFFER (token, token_index, ttoklen + 2, + token_buffer_size, + TOKEN_DEFAULT_GROW_SIZE); + token[token_index++] = character; + token[token_index++] = peek_char; + strcpy (token + token_index, ttok); + token_index += ttoklen; + FREE (ttok); + dollar_present = 1; + all_digits = 0; + goto next_character; + } + /* This handles $'...' and $"..." new-style quoted strings. */ + else if (character == '$' && (peek_char == '\'' || peek_char == '"')) + { + ttok = parse_matched_pair (peek_char, peek_char, peek_char, &ttoklen, 0); + if (ttok == &matched_pair_error) + return -1; + if (peek_char == '\'') + ttrans = ansiexpand (ttok, 0, ttoklen - 1, &ttranslen); + else + ttrans = localeexpand (ttok, 0, ttoklen - 1, &ttranslen); + free (ttok); + RESIZE_MALLOCED_BUFFER (token, token_index, ttranslen + 2, + token_buffer_size, + TOKEN_DEFAULT_GROW_SIZE); + token[token_index++] = peek_char; + strcpy (token + token_index, ttrans); + token_index += ttranslen; + token[token_index++] = peek_char; + FREE (ttrans); + quoted = 1; + all_digits = 0; + goto next_character; + } + else + shell_ungetc (peek_char); + } - token[token_index++] = character; +#if defined (ARRAY_VARS) + /* Identify possible compound array variable assignment. */ + else if (character == '=') + { + peek_char = shell_getc (1); + if (peek_char == '(') /* ) */ + { + ttok = parse_matched_pair (cd, '(', ')', &ttoklen, 0); + if (ttok == &matched_pair_error) + return -1; /* Bail immediately. */ + RESIZE_MALLOCED_BUFFER (token, token_index, ttoklen + 2, + token_buffer_size, + TOKEN_DEFAULT_GROW_SIZE); + token[token_index++] = character; + token[token_index++] = peek_char; + strcpy (token + token_index, ttok); + token_index += ttoklen; + FREE (ttok); + all_digits = 0; + goto next_character; + } + else + shell_ungetc (peek_char); + } +#endif - if (token_index == (token_buffer_size - 1)) - { - token_buffer_size += TOKEN_DEFAULT_GROW_SIZE; - token = xrealloc (token, token_buffer_size); - } - next_character: - if (character == '\n' && interactive && bash_input.type != st_string) - prompt_again (); + /* When not parsing a multi-character word construct, shell meta- + characters break words. */ + if (shellbreak (character)) + { + shell_ungetc (character); + goto got_token; + } - /* We want to remove quoted newlines (that is, a \ pair) - unless we are within single quotes or pass_next_character is - set (the shell equivalent of literal-next). */ - character = shell_getc - ((current_delimiter () != '\'') && (!pass_next_character)); - } + got_character: - got_token: + all_digits &= digit (character); + dollar_present |= character == '$'; - token[token_index] = '\0'; - - if ((delimiter_depth || dollar_paren_level || dollar_bracket_level) && - character == EOF) - { - char reporter = '\0'; + if (character == CTLESC || character == CTLNUL) + token[token_index++] = CTLESC; - if (!delimiter_depth) - { - if (dollar_paren_level) - reporter = ')'; - else if (dollar_bracket_level) - reporter = ']'; - } + token[token_index++] = character; - if (!reporter) - reporter = current_delimiter (); + RESIZE_MALLOCED_BUFFER (token, token_index, 1, token_buffer_size, + TOKEN_DEFAULT_GROW_SIZE); - report_error ("unexpected EOF while looking for `%c'", reporter); - return (-1); - } + next_character: + if (character == '\n' && interactive && + (bash_input.type == st_stdin || bash_input.type == st_stream)) + prompt_again (); - if (all_digits) - { - /* Check to see what thing we should return. If the last_read_token - is a `<', or a `&', or the character which ended this token is - a '>' or '<', then, and ONLY then, is this input token a NUMBER. - Otherwise, it is just a word, and should be returned as such. */ - - if (character == '<' || character == '>' || - last_read_token == LESS_AND || last_read_token == GREATER_AND) - { - yylval.number = atoi (token); - return (NUMBER); - } - } + /* We want to remove quoted newlines (that is, a \ pair) + unless we are within single quotes or pass_next_character is + set (the shell equivalent of literal-next). */ + cd = current_delimiter (dstack); + character = shell_getc (cd != '\'' && pass_next_character == 0); + } /* end for (;;) */ - /* Handle special case. IN is recognized if the last token - was WORD and the token before that was FOR or CASE. */ - if ((last_read_token == WORD) && -#if defined (SELECT_COMMAND) - ((token_before_that == FOR) || (token_before_that == CASE) || (token_before_that == SELECT)) && -#else - ((token_before_that == FOR) || (token_before_that == CASE)) && -#endif - (token[0] == 'i' && token[1] == 'n' && !token[2])) - { - if (token_before_that == CASE) - { - in_case_pattern_list = 1; - allow_esac_as_next++; - } - return (IN); - } +got_token: - /* Ditto for DO in the FOR case. */ -#if defined (SELECT_COMMAND) - if ((last_read_token == WORD) && ((token_before_that == FOR) || (token_before_that == SELECT)) && -#else - if ((last_read_token == WORD) && (token_before_that == FOR) && -#endif - (token[0] == 'd' && token[1] == 'o' && !token[2])) - return (DO); - - /* Ditto for ESAC in the CASE case. - Specifically, this handles "case word in esac", which is a legal - construct, certainly because someone will pass an empty arg to the - case construct, and we don't want it to barf. Of course, we should - insist that the case construct has at least one pattern in it, but - the designers disagree. */ - if (allow_esac_as_next) - { - allow_esac_as_next--; - if (STREQ (token, "esac")) - { - in_case_pattern_list = 0; - return (ESAC); - } - } + token[token_index] = '\0'; - /* Ditto for `{' in the FUNCTION case. */ - if (allow_open_brace) + /* Check to see what thing we should return. If the last_read_token + is a `<', or a `&', or the character which ended this token is + a '>' or '<', then, and ONLY then, is this input token a NUMBER. + Otherwise, it is just a word, and should be returned as such. */ + if (all_digits && (character == '<' || character == '>' || + last_read_token == LESS_AND || + last_read_token == GREATER_AND)) { - allow_open_brace = 0; - if (token[0] == '{' && !token[1]) - { - open_brace_awaiting_satisfaction++; - return ('{'); - } + yylval.number = atoi (token); + return (NUMBER); } - if (posixly_correct) - CHECK_FOR_RESERVED_WORD (token); + /* Check for special case tokens. */ + result = special_case_tokens (token); + if (result >= 0) + return result; #if defined (ALIAS) - /* OK, we have a token. Let's try to alias expand it, if (and only if) - it's eligible. + /* Posix.2 does not allow reserved words to be aliased, so check for all + of them, including special cases, before expanding the current token + as an alias. */ + if (posixly_correct) + CHECK_FOR_RESERVED_WORD (token); + + /* Aliases are expanded iff EXPAND_ALIASES is non-zero, and quoting + inhibits alias expansion. */ + if (expand_aliases && quoted == 0) + { + result = alias_expand_token (token); + if (result == RE_READ_TOKEN) + return (RE_READ_TOKEN); + else if (result == NO_EXPANSION) + parser_state &= ~PST_ALEXPNEXT; + } - It is eligible for expansion if the shell is in interactive mode, and - the token is unquoted and the last token read was a command - separator (or expand_next_token is set), and we are currently - processing an alias (pushed_string_list is non-empty) and this - token is not the same as the current or any previously - processed alias. + /* If not in Posix.2 mode, check for reserved words after alias + expansion. */ + if (posixly_correct == 0) +#endif + CHECK_FOR_RESERVED_WORD (token); + + the_word = (WORD_DESC *)xmalloc (sizeof (WORD_DESC)); + the_word->word = xmalloc (1 + token_index); + the_word->flags = 0; + strcpy (the_word->word, token); + if (dollar_present) + the_word->flags |= W_HASDOLLAR; + if (quoted) + the_word->flags |= W_QUOTED; + /* A word is an assignment if it appears at the beginning of a + simple command, or after another assignment word. This is + context-dependent, so it cannot be handled in the grammar. */ + if (assignment (token)) + { + the_word->flags |= W_ASSIGNMENT; + /* Don't perform word splitting on assignment statements. */ + if (assignment_acceptable (last_read_token)) + the_word->flags |= W_NOSPLIT; + } - Special cases that disqualify: - In a pattern list in a case statement (in_case_pattern_list). */ - if (interactive_shell && !quoted && !in_case_pattern_list && - (expand_next_token || command_token_position (last_read_token))) - { - char *alias_expand_word (), *expanded; + yylval.word = the_word; - if (expanded_token_stack && token_has_been_expanded (token)) - goto no_expansion; + result = ((the_word->flags & (W_ASSIGNMENT|W_NOSPLIT)) == (W_ASSIGNMENT|W_NOSPLIT)) + ? ASSIGNMENT_WORD : WORD; - expanded = alias_expand_word (token); - if (expanded) - { - int len = strlen (expanded), expand_next; + if (last_read_token == FUNCTION) + { + parser_state |= PST_ALLOWOPNBRC; + function_dstart = line_number; + } - /* Erase the current token. */ - token_index = 0; + return (result); +} - expand_next = (expanded[len - 1] == ' ') || - (expanded[len - 1] == '\t'); +/* $'...' ANSI-C expand the portion of STRING between START and END and + return the result. The result cannot be longer than the input string. */ +static char * +ansiexpand (string, start, end, lenp) + char *string; + int start, end, *lenp; +{ + char *temp, *t; + int len, tlen; - push_string (expanded, expand_next, token); - goto re_read_token; - } - else - /* This is an eligible token that does not have an expansion. */ -no_expansion: - expand_next_token = 0; - } - else - { - expand_next_token = 0; - } -#endif /* ALIAS */ + temp = xmalloc (end - start + 1); + for (tlen = 0, len = start; len < end; ) + temp[tlen++] = string[len++]; + temp[tlen] = '\0'; - if (!posixly_correct) - CHECK_FOR_RESERVED_WORD (token); + if (*temp) + { + t = ansicstr (temp, tlen, (int *)NULL); + free (temp); + if (lenp) + *lenp = strlen (t); + return (t); + } + else + { + if (lenp) + *lenp = 0; + return (temp); + } +} - /* What if we are attempting to satisfy an open-brace grouper? */ - if (open_brace_awaiting_satisfaction && token[0] == '}' && !token[1]) - { - open_brace_awaiting_satisfaction--; - return ('}'); - } +/* $"..." -- Translate the portion of STRING between START and END + according to current locale using gettext (if available) and return + the result. The caller will take care of leaving the quotes intact. + The string will be left without the leading `$' by the caller. + If translation is performed, the translated string will be double-quoted + by the caller. The length of the translated string is returned in LENP, + if non-null. */ +static char * +localeexpand (string, start, end, lenp) + char *string; + int start, end, *lenp; +{ + int len, tlen; + char *temp, *t; - the_word = (WORD_DESC *)xmalloc (sizeof (WORD_DESC)); - the_word->word = xmalloc (1 + token_index); - strcpy (the_word->word, token); - the_word->dollar_present = dollar_present; - the_word->quoted = quoted; - the_word->assignment = assignment (token); - - yylval.word = the_word; - result = WORD; - - /* A word is an assignment if it appears at the beginning of a - simple command, or after another assignment word. This is - context-dependent, so it cannot be handled in the grammar. */ - if (assignment_acceptable (last_read_token) && the_word->assignment) - result = ASSIGNMENT_WORD; - - if (last_read_token == FUNCTION) - allow_open_brace = 1; - } - return (result); + temp = xmalloc (end - start + 1); + for (tlen = 0, len = start; len < end; ) + temp[tlen++] = string[len++]; + temp[tlen] = '\0'; + + /* If we're just dumping translatable strings, don't do anything. */ + if (dump_translatable_strings) + { + printf ("\"%s\"\n", temp); + if (lenp) + *lenp = tlen; + return (temp); + } + else if (*temp) + { + t = localetrans (temp, tlen, &len); + free (temp); + if (lenp) + *lenp = len; + return (t); + } + else + { + if (lenp) + *lenp = 0; + return (temp); + } } /* Return 1 if TOKEN is a token that after being read would allow @@ -2428,15 +2700,12 @@ static int reserved_word_acceptable (token) int token; { -#if 0 - if (member (token, "\n;()|&{") || -#else if (token == '\n' || token == ';' || token == '(' || token == ')' || token == '|' || token == '&' || token == '{' || -#endif token == '}' || /* XXX */ token == AND_AND || token == BANG || + token == TIME || token == TIMEOPT || token == DO || token == ELIF || token == ELSE || @@ -2462,12 +2731,13 @@ find_reserved_word (token) char *token; { int i; - for (i = 0; word_token_alist[i].word != (char *)NULL; i++) + for (i = 0; word_token_alist[i].word; i++) if (STREQ (token, word_token_alist[i].word)) return i; return -1; } +#if 0 #if defined (READLINE) /* Called after each time readline is called. This insures that whatever the new prompt string is gets propagated to readline's local prompt @@ -2475,11 +2745,11 @@ find_reserved_word (token) static void reset_readline_prompt () { + char *temp_prompt; + if (prompt_string_pointer) { - char *temp_prompt; - - temp_prompt = *prompt_string_pointer + temp_prompt = (*prompt_string_pointer) ? decode_prompt_string (*prompt_string_pointer) : (char *)NULL; @@ -2490,11 +2760,11 @@ reset_readline_prompt () } FREE (current_readline_prompt); - current_readline_prompt = temp_prompt; } } #endif /* READLINE */ +#endif /* 0 */ #if defined (HISTORY) /* A list of tokens which can be followed by newlines, but not by @@ -2502,29 +2772,48 @@ reset_readline_prompt () newline separator for such tokens is replaced with a space. */ static int no_semi_successors[] = { '\n', '{', '(', ')', ';', '&', '|', - CASE, DO, ELSE, IF, IN, SEMI_SEMI, THEN, UNTIL, WHILE, AND_AND, OR_OR, + CASE, DO, ELSE, IF, SEMI_SEMI, THEN, UNTIL, WHILE, AND_AND, OR_OR, IN, 0 }; /* If we are not within a delimited expression, try to be smart about which separators can be semi-colons and which must be - newlines. */ + newlines. Returns the string that should be added into the + history entry. */ char * history_delimiting_chars () { - if (!delimiter_depth) + register int i; + + if (dstack.delimiter_depth != 0) + return ("\n"); + + /* First, handle some special cases. */ + /*(*/ + /* If we just read `()', assume it's a function definition, and don't + add a semicolon. If the token before the `)' was not `(', and we're + not in the midst of parsing a case statement, assume it's a + parenthesized command and add the semicolon. */ + /*)(*/ + if (token_before_that == ')') { - register int i; + if (two_tokens_ago == '(') /*)*/ /* function def */ + return " "; + /* This does not work for subshells inside case statement + command lists. It's a suboptimal solution. */ + else if (parser_state & PST_CASESTMT) /* case statement pattern */ + return " "; + else + return "; "; /* (...) subshell */ + } - for (i = 0; no_semi_successors[i]; i++) - { - if (token_before_that == no_semi_successors[i]) - return (" "); - } - return ("; "); + for (i = 0; no_semi_successors[i]; i++) + { + if (token_before_that == no_semi_successors[i]) + return (" "); } - else - return ("\n"); + + return ("; "); } #endif /* HISTORY */ @@ -2544,7 +2833,7 @@ prompt_again () if (!prompt_string_pointer) prompt_string_pointer = &ps1_prompt; - temp_prompt = (*prompt_string_pointer) + temp_prompt = *prompt_string_pointer ? decode_prompt_string (*prompt_string_pointer) : (char *)NULL; @@ -2580,37 +2869,47 @@ print_prompt () /* Return a string which will be printed as a prompt. The string may contain special characters which are decoded as follows: - - \t the time - \d the date + + \a bell (ascii 07) + \e escape (ascii 033) + \d the date in Day Mon Date format + \h the hostname up to the first `.' + \H the hostname \n CRLF \s the name of the shell + \t the time in 24-hour hh:mm:ss format + \T the time in 12-hour hh:mm:ss format + \@ the time in 12-hour am/pm format + \v the version of bash (e.g., 2.00) + \V the release of bash, version + patchlevel (e.g., 2.00.0) \w the current working directory - \W the last element of PWD + \W the last element of $PWD \u your username - \h the hostname \# the command number of this command \! the history number of this command \$ a $ or a # if you are root - \ character code in octal + \nnn character code nnn in octal \\ a backslash + \[ begin a sequence of non-printing chars + \] end a sequence of non-printing chars */ #define PROMPT_GROWTH 50 char * decode_prompt_string (string) char *string; { - int result_size = PROMPT_GROWTH; - int result_index = 0; - char *result; - int c; - char *temp = (char *)NULL; WORD_LIST *list; - + char *result, *t; + struct dstack save_dstack; #if defined (PROMPT_STRING_DECODE) + int result_size, result_index; + int c, n; + char *temp, octal_string[4]; + time_t the_time; - result = xmalloc (PROMPT_GROWTH); - result[0] = 0; + result = xmalloc (result_size = PROMPT_GROWTH); + result[result_index = 0] = 0; + temp = (char *)NULL; while (c = *string++) { @@ -2631,7 +2930,7 @@ decode_prompt_string (string) string--; /* add_string increments string again. */ goto add_string; } - } + } if (c == '\\') { c = *string; @@ -2646,171 +2945,199 @@ decode_prompt_string (string) case '5': case '6': case '7': - { - char octal_string[4]; - int n; + strncpy (octal_string, string, 3); + octal_string[3] = '\0'; - strncpy (octal_string, string, 3); - octal_string[3] = '\0'; + n = read_octal (octal_string); + temp = xmalloc (3); - n = read_octal (octal_string); - temp = xmalloc (3); + if (n == CTLESC || n == CTLNUL) + { + string += 3; + temp[0] = CTLESC; + temp[1] = n; + temp[2] = '\0'; + } + else if (n == -1) + { + temp[0] = '\\'; + temp[1] = '\0'; + } + else + { + string += 3; + temp[0] = n; + temp[1] = '\0'; + } - if (n == CTLESC || n == CTLNUL) - { - string += 3; - temp[0] = CTLESC; - temp[1] = n; - temp[2] = '\0'; - } - else if (n == -1) - { - temp[0] = '\\'; - temp[1] = '\0'; - } - else - { - string += 3; - temp[0] = n; - temp[1] = '\0'; - } + c = 0; + goto add_string; - c = 0; - goto add_string; - } - case 't': case 'd': + case 'T': + case '@': /* Make the current time/date into a string. */ - { - time_t the_time = time (0); - char *ttemp = ctime (&the_time); - temp = savestring (ttemp); + the_time = time (0); + temp = ctime (&the_time); - if (c == 't') - { - strcpy (temp, temp + 11); - temp[8] = '\0'; - } - else - temp[10] = '\0'; + temp = (c != 'd') ? savestring (temp + 11) : savestring (temp); + temp[(c != 'd') ? 8 : 10] = '\0'; - goto add_string; - } + /* quick and dirty conversion to 12-hour time */ + if (c == 'T' || c == '@') + { + if (c == '@') + { + temp[5] = 'a'; /* am/pm format */ + temp[6] = 'm'; + temp[7] = '\0'; + } + c = temp[2]; + temp[2] = '\0'; + n = atoi (temp); + temp[2] = c; + n -= 12; + if (n > 0) + { + temp[0] = (n / 10) + '0'; + temp[1] = (n % 10) + '0'; + } + if (n >= 0 && temp[5] == 'a') + temp[5] = 'p'; + } + goto add_string; case 'n': - if (!no_line_editing) - temp = savestring ("\r\n"); - else - temp = savestring ("\n"); + temp = xmalloc (3); + temp[0] = no_line_editing ? '\n' : '\r'; + temp[1] = no_line_editing ? '\0' : '\n'; + temp[2] = '\0'; goto add_string; case 's': - { - temp = base_pathname (shell_name); - temp = savestring (temp); - goto add_string; - } - + temp = base_pathname (shell_name); + temp = savestring (temp); + goto add_string; + + case 'v': + case 'V': + temp = xmalloc (8); + if (c == 'v') + strcpy (temp, dist_version); + else + sprintf (temp, "%s.%d", dist_version, patch_level); + goto add_string; + case 'w': case 'W': { - /* Use the value of PWD because it is much more effecient. */ -#define EFFICIENT -#ifdef EFFICIENT - char *polite_directory_format (), t_string[MAXPATHLEN]; + /* Use the value of PWD because it is much more efficient. */ + char t_string[PATH_MAX]; temp = get_string_value ("PWD"); - if (!temp) - getwd (t_string); + if (temp == 0) + { + if (getcwd (t_string, sizeof(t_string)) == 0) + { + t_string[0] = '.'; + t_string[1] = '\0'; + } + } else strcpy (t_string, temp); -#else - getwd (t_string); -#endif /* EFFICIENT */ if (c == 'W') { - char *dir = (char *)strrchr (t_string, '/'); - if (dir && dir != t_string) - strcpy (t_string, dir + 1); - temp = savestring (t_string); + t = strrchr (t_string, '/'); + if (t && t != t_string) + strcpy (t_string, t + 1); } else - temp = savestring (polite_directory_format (t_string)); + strcpy (t_string, polite_directory_format (t_string)); + + /* If we're going to be expanding the prompt string later, + quote the directory name. */ + if (promptvars || posixly_correct) + temp = backslash_quote (t_string); + else + temp = savestring (t_string); + goto add_string; } - + case 'u': - { - temp = savestring (current_user.user_name); - goto add_string; - } + temp = savestring (current_user.user_name); + goto add_string; case 'h': - { - char *t_string; - - temp = savestring (current_host_name); - if (t_string = (char *)strchr (temp, '.')) - *t_string = '\0'; - goto add_string; - } + case 'H': + temp = savestring (current_host_name); + if (c == 'h' && (t = (char *)strchr (temp, '.'))) + *t = '\0'; + goto add_string; case '#': - { - temp = itos (current_command_number); - goto add_string; - } + temp = itos (current_command_number); + goto add_string; case '!': - { #if !defined (HISTORY) - temp = savestring ("1"); + temp = savestring ("1"); #else /* HISTORY */ - temp = itos (history_number ()); + temp = itos (history_number ()); #endif /* HISTORY */ - goto add_string; - } + goto add_string; case '$': - temp = savestring (geteuid () == 0 ? "#" : "$"); + temp = xmalloc (2); + temp[0] = current_user.euid == 0 ? '#' : '$'; + temp[1] = '\0'; goto add_string; #if defined (READLINE) case '[': case ']': - temp = xmalloc(3); + temp = xmalloc (3); temp[0] = '\001'; temp[1] = (c == '[') ? RL_PROMPT_START_IGNORE : RL_PROMPT_END_IGNORE; temp[2] = '\0'; goto add_string; -#endif +#endif /* READLINE */ case '\\': - temp = savestring ("\\"); + temp = xmalloc (2); + temp[0] = c; + temp[1] = '\0'; + goto add_string; + + case 'a': + case 'e': + temp = xmalloc (2); + temp[0] = (c == 'a') ? '\07' : '\033'; + temp[1] = '\0'; goto add_string; default: - temp = savestring ("\\ "); + temp = xmalloc (3); + temp[0] = '\\'; temp[1] = c; + temp[2] = '\0'; add_string: if (c) string++; result = sub_append_string (temp, result, &result_index, &result_size); - temp = (char *)NULL; /* Free ()'ed in sub_append_string (). */ + temp = (char *)NULL; /* Freed in sub_append_string (). */ result[result_index] = '\0'; break; } } else { - while (3 + result_index > result_size) - result = xrealloc (result, result_size += PROMPT_GROWTH); - + RESIZE_MALLOCED_BUFFER (result, result_index, 3, result_size, PROMPT_GROWTH); result[result_index++] = c; result[result_index] = '\0'; } @@ -2819,22 +3146,42 @@ decode_prompt_string (string) result = savestring (string); #endif /* !PROMPT_STRING_DECODE */ + /* Save the delimiter stack and point `dstack' to temp space so any + command substitutions in the prompt string won't result in screwing + up the parser's quoting state. */ + save_dstack = dstack; + dstack = temp_dstack; + dstack.delimiter_depth = 0; + /* Perform variable and parameter expansion and command substitution on the prompt string. */ - list = expand_string_unsplit (result, 1); - free (result); - result = string_list (list); - dispose_words (list); + if (promptvars || posixly_correct) + { + list = expand_string_unsplit (result, Q_DOUBLE_QUOTES); + free (result); + result = string_list (list); + dispose_words (list); + } + else + { + t = dequote_string (result); + free (result); + result = t; + } + + dstack = save_dstack; return (result); } /* Report a syntax error, and restart the parser. Call here for fatal errors. */ +int yyerror () { report_syntax_error ((char *)NULL); reset_parser (); + return (0); } /* Report a syntax error with line numbers, etc. @@ -2845,96 +3192,85 @@ static void report_syntax_error (message) char *message; { + char *msg, *t; + int token_end, i; + char msg2[2]; + if (message) { - if (!interactive) - { - char *name = bash_input.name ? bash_input.name : "stdin"; - report_error ("%s: line %d: `%s'", name, line_number, message); - } - else - { - if (EOF_Reached) - EOF_Reached = 0; - report_error ("%s", message); - } - + parser_error (line_number, "%s", message); + if (interactive && EOF_Reached) + EOF_Reached = 0; last_command_exit_value = EX_USAGE; return; } + /* If the line of input we're reading is not null, try to find the + objectionable token. */ if (shell_input_line && *shell_input_line) { - char *t = shell_input_line; - register int i = shell_input_line_index; - int token_end = 0; + t = shell_input_line; + i = shell_input_line_index; + token_end = 0; - if (!t[i] && i) + if (i && t[i] == '\0') i--; - while (i && (t[i] == ' ' || t[i] == '\t' || t[i] == '\n')) + while (i && (whitespace (t[i]) || t[i] == '\n')) i--; if (i) token_end = i + 1; - while (i && !member (t[i], " \n\t;|&")) + while (i && (member (t[i], " \n\t;|&") == 0)) i--; - while (i != token_end && member (t[i], " \t\n")) + while (i != token_end && (whitespace (t[i]) || t[i] == '\n')) i++; - if (token_end) + /* Print the offending token. */ + if (token_end || (i == 0 && token_end == 0)) { - char *error_token; - error_token = xmalloc (1 + (token_end - i)); - strncpy (error_token, t + i, token_end - i); - error_token[token_end - i] = '\0'; + if (token_end) + { + msg = xmalloc (1 + (token_end - i)); + strncpy (msg, t + i, token_end - i); + msg[token_end - i] = '\0'; + } + else /* one-character token */ + { + msg2[0] = t[i]; + msg2[1] = '\0'; + msg = msg2; + } - report_error ("syntax error near unexpected token `%s'", error_token); - free (error_token); - } - else if ((i == 0) && (token_end == 0)) /* a 1-character token */ - { - char etoken[2]; - etoken[0] = t[i]; - etoken[1] = '\0'; + parser_error (line_number, "syntax error near unexpected token `%s'", msg); - report_error ("syntax error near unexpected token `%s'", etoken); + if (msg != msg2) + free (msg); } - if (!interactive) + /* If not interactive, print the line containing the error. */ + if (interactive == 0) { - char *temp = savestring (shell_input_line); - char *name = bash_input.name ? bash_input.name : "stdin"; - int l = strlen (temp); - - while (l && temp[l - 1] == '\n') - temp[--l] = '\0'; + msg = savestring (shell_input_line); + token_end = strlen (msg); + while (token_end && msg[token_end - 1] == '\n') + msg[--token_end] = '\0'; - report_error ("%s: line %d: `%s'", name, line_number, temp); - free (temp); + parser_error (line_number, "`%s'", msg); + free (msg); } } else { - char *name, *msg; - if (!interactive) - name = bash_input.name ? bash_input.name : "stdin"; - if (EOF_Reached) - msg = "syntax error: unexpected end of file"; - else - msg = "syntax error"; - if (!interactive) - report_error ("%s: line %d: %s", name, line_number, msg); - else - { - /* This file uses EOF_Reached only for error reporting - when the shell is interactive. Other mechanisms are - used to decide whether or not to exit. */ - EOF_Reached = 0; - report_error (msg); - } + msg = EOF_Reached ? "syntax error: unexpected end of file" : "syntax error"; + parser_error (line_number, "%s", msg); + /* When the shell is interactive, this file uses EOF_Reached + only for error reporting. Other mechanisms are used to + decide whether or not to exit. */ + if (interactive && EOF_Reached) + EOF_Reached = 0; } last_command_exit_value = EX_USAGE; } @@ -2944,11 +3280,12 @@ report_syntax_error (message) allocated objects to the memory pool. In the case of no error, we want to throw away the information about where the allocated objects live. (dispose_command () will actually free the command. */ +static void discard_parser_constructs (error_p) int error_p; { } - + /* Do that silly `type "bye" to exit' stuff. You know, "ignoreeof". */ /* A flag denoting whether or not ignoreeof is set. */ @@ -2990,7 +3327,7 @@ handle_eof_input_unit () prompt_again (); last_read_token = current_token = '\n'; return; - } + } } /* In this case EOF should exit the shell. Do it now. */ diff --git a/parser.h b/parser.h index 247d78e..c264481 100644 --- a/parser.h +++ b/parser.h @@ -1,8 +1,22 @@ /* parser.h -- Everything you wanted to know about the parser, but were afraid to ask. */ +#if !defined (_PARSER_H_) +# define _PARSER_H_ -#if !defined (_PARSER_H) -# define _PARSER_H # include "command.h" # include "input.h" -#endif /* _PARSER_H */ + +/* Definition of the delimiter stack. Needed by parse.y and bashhist.c. */ +struct dstack { +/* DELIMITERS is a stack of the nested delimiters that we have + encountered so far. */ + char *delimiters; + +/* Offset into the stack of delimiters. */ + int delimiter_depth; + +/* How many slots are allocated to DELIMITERS. */ + int delimiter_space; +}; + +#endif /* _PARSER_H_ */ diff --git a/pathexp.c b/pathexp.c new file mode 100644 index 0000000..6404514 --- /dev/null +++ b/pathexp.c @@ -0,0 +1,355 @@ +/* pathexp.c -- The shell interface to the globbing library. */ + +/* Copyright (C) 1995 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, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "config.h" + +#include "bashtypes.h" +#include + +#if defined (HAVE_UNISTD_H) +# include +#endif + +#include "bashansi.h" + +#include "shell.h" +#include "pathexp.h" +#include "flags.h" + +#include +#include + +/* Control whether * matches .files in globbing. */ +int glob_dot_filenames; + +/* Return nonzero if STRING has any unquoted special globbing chars in it. */ +int +unquoted_glob_pattern_p (string) + register char *string; +{ + register int c; + int open; + + open = 0; + while (c = *string++) + { + switch (c) + { + case '?': + case '*': + return (1); + + case '[': + open++; + continue; + + case ']': + if (open) + return (1); + continue; + + case CTLESC: + case '\\': + if (*string++ == '\0') + return (0); + } + } + return (0); +} + +/* PATHNAME can contain characters prefixed by CTLESC; this indicates + that the character is to be quoted. We quote it here in the style + that the glob library recognizes. If CONVERT_QUOTED_NULLS is non-zero, + we change quoted null strings (pathname[0] == CTLNUL) into empty + strings (pathname[0] == 0). If this is called after quote removal + is performed, CONVERT_QUOTED_NULLS should be 0; if called when quote + removal has not been done (for example, before attempting to match a + pattern while executing a case statement), CONVERT_QUOTED_NULLS should + be 1. */ +char * +quote_string_for_globbing (pathname, convert_quoted_nulls) + char *pathname; + int convert_quoted_nulls; +{ + char *temp; + register int i; + + temp = savestring (pathname); + + if (convert_quoted_nulls && QUOTED_NULL (pathname)) + { + temp[0] = '\0'; + return temp; + } + + for (i = 0; temp[i]; i++) + { + if (temp[i] == CTLESC) + temp[i++] = '\\'; + } + + return (temp); +} + +char * +quote_globbing_chars (string) + char *string; +{ + char *temp, *s, *t; + + temp = xmalloc (strlen (string) * 2 + 1); + for (t = temp, s = string; *s; ) + { + switch (*s) + { + case '*': + case '[': + case ']': + case '?': + case '\\': + *t++ = '\\'; + break; + } + *t++ = *s++; + } + *t = '\0'; + return temp; +} + +/* Call the glob library to do globbing on PATHNAME. */ +char ** +shell_glob_filename (pathname) + char *pathname; +{ +#if defined (USE_POSIX_GLOB_LIBRARY) + register int i; + char *temp, **return_value; + glob_t filenames; + int glob_flags; + + temp = quote_string_for_globbing (pathname, 0); + + filenames.gl_offs = 0; + + glob_flags = glob_dot_filenames ? GLOB_PERIOD : 0; + glob_flags |= (GLOB_ERR | GLOB_DOOFFS); + + i = glob (temp, glob_flags, (Function *)NULL, &filenames); + + free (temp); + + if (i == GLOB_NOSPACE || i == GLOB_ABEND) + return ((char **)NULL); + + if (i == GLOB_NOMATCH) + filenames.gl_pathv[0] = (char *)NULL; + + return (filenames.gl_pathv); + +#else /* !USE_POSIX_GLOB_LIBRARY */ + + char *temp, **results; + + noglob_dot_filenames = glob_dot_filenames == 0; + + temp = quote_string_for_globbing (pathname, 0); + + results = glob_filename (temp); + free (temp); + + if (results && ((GLOB_FAILED (results)) == 0)) + { + if (should_ignore_glob_matches ()) + ignore_glob_matches (results); + if (results && results[0]) + sort_char_array (results); + else + { + FREE (results); + results = (char **)&glob_error_return; + } + } + + return (results); +#endif /* !USE_POSIX_GLOB_LIBRARY */ +} + +/* Stuff for GLOBIGNORE. */ + +static struct ignorevar globignore = +{ + "GLOBIGNORE", + (struct ign *)0, + 0, + (char *)0, + (Function *)0, +}; + +/* Set up to ignore some glob matches because the value of GLOBIGNORE + has changed. If GLOBIGNORE is being unset, we also need to disable + the globbing of filenames beginning with a `.'. */ +void +setup_glob_ignore (name) + char *name; +{ + char *v; + + v = get_string_value (name); + setup_ignore_patterns (&globignore); + + if (globignore.num_ignores) + glob_dot_filenames = 1; + else if (v == 0) + glob_dot_filenames = 0; +} + +int +should_ignore_glob_matches () +{ + return globignore.num_ignores; +} + +/* Return 0 if NAME matches a pattern in the globignore.ignores list. */ +static int +glob_name_is_acceptable (name) + char *name; +{ + struct ign *p; + + /* . and .. are never matched */ + if (name[0] == '.' && (name[1] == '\0' || (name[1] == '.' && name[2] == '\0'))) + return (0); + + for (p = globignore.ignores; p->val; p++) + { + if (fnmatch (p->val, name, FNM_PATHNAME) != FNM_NOMATCH) + return (0); + } + return (1); +} + +/* Internal function to test whether filenames in NAMES should be + ignored. NAME_FUNC is a pointer to a function to call with each + name. It returns non-zero if the name is acceptable to the particular + ignore function which called _ignore_names; zero if the name should + be removed from NAMES. */ + +static void +ignore_globbed_names (names, name_func) + char **names; + Function *name_func; +{ + char **newnames; + int n, i; + + for (i = 0; names[i]; i++) + ; + newnames = (char **)xmalloc ((i + 1) * sizeof (char *)); + + for (n = i = 0; names[i]; i++) + { + if ((*name_func) (names[i])) + newnames[n++] = names[i]; + else + free (names[i]); + } + + newnames[n] = (char *)NULL; + + if (n == 0) + { + names[0] = (char *)NULL; + free (newnames); + return; + } + + /* Copy the acceptable names from NEWNAMES back to NAMES and set the + new array end. */ + for (n = 0; newnames[n]; n++) + names[n] = newnames[n]; + names[n] = (char *)NULL; +} + +void +ignore_glob_matches (names) + char **names; +{ + if (globignore.num_ignores == 0) + return; + + ignore_globbed_names (names, glob_name_is_acceptable); +} + +void +setup_ignore_patterns (ivp) + struct ignorevar *ivp; +{ + int numitems, maxitems, ptr; + char *colon_bit, *this_ignoreval; + struct ign *p; + + this_ignoreval = get_string_value (ivp->varname); + + /* If nothing has changed then just exit now. */ + if ((this_ignoreval && ivp->last_ignoreval && STREQ (this_ignoreval, ivp->last_ignoreval)) || + (!this_ignoreval && !ivp->last_ignoreval)) + return; + + /* Oops. The ignore variable has changed. Re-parse it. */ + ivp->num_ignores = 0; + + if (ivp->ignores) + { + for (p = ivp->ignores; p->val; p++) + free(p->val); + free (ivp->ignores); + ivp->ignores = (struct ign *)NULL; + } + + if (ivp->last_ignoreval) + { + free (ivp->last_ignoreval); + ivp->last_ignoreval = (char *)NULL; + } + + if (this_ignoreval == 0 || *this_ignoreval == '\0') + return; + + ivp->last_ignoreval = savestring (this_ignoreval); + + numitems = maxitems = ptr = 0; + + while (colon_bit = extract_colon_unit (this_ignoreval, &ptr)) + { + if (numitems + 1 >= maxitems) + { + maxitems += 10; + ivp->ignores = (struct ign *)xrealloc (ivp->ignores, maxitems * sizeof (struct ign)); + } + ivp->ignores[numitems].val = colon_bit; + ivp->ignores[numitems].len = strlen (colon_bit); + ivp->ignores[numitems].flags = 0; + if (ivp->item_func) + (*ivp->item_func) (&ivp->ignores[numitems]); + numitems++; + } + ivp->ignores[numitems].val = (char *)NULL; + ivp->num_ignores = numitems; +} diff --git a/pathexp.h b/pathexp.h new file mode 100644 index 0000000..a164de1 --- /dev/null +++ b/pathexp.h @@ -0,0 +1,80 @@ +/* pathexp.h -- The shell interface to the globbing library. */ + +/* Copyright (C) 1987,1989 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, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#if !defined (_PATHEXP_H_) +#define _PATHEXP_H_ + +#if defined (USE_POSIX_GLOB_LIBRARY) +# define GLOB_FAILED(glist) !(glist) +#else /* !USE_POSIX_GLOB_LIBRARY */ +# define GLOB_FAILED(glist) (glist) == (char **)&glob_error_return +extern int noglob_dot_filenames; +extern char *glob_error_return; +#endif /* !USE_POSIX_GLOB_LIBRARY */ + +extern int glob_dot_filenames; + +extern int unquoted_glob_pattern_p __P((char *)); + +/* PATHNAME can contain characters prefixed by CTLESC;; this indicates + that the character is to be quoted. We quote it here in the style + that the glob library recognizes. If CONVERT_QUOTED_NULLS is non-zero, + we change quoted null strings (pathname[0] == CTLNUL) into empty + strings (pathname[0] == 0). If this is called after quote removal + is performed, CONVERT_QUOTED_NULLS should be 0; if called when quote + removal has not been done (for example, before attempting to match a + pattern while executing a case statement), CONVERT_QUOTED_NULLS should + be 1. */ +extern char *quote_string_for_globbing __P((char *, int)); + +extern char *quote_globbing_chars __P((char *)); + +/* Call the glob library to do globbing on PATHNAME. */ +extern char **shell_glob_filename __P((char *)); + +/* Filename completion ignore. Used to the "fignore" facility of + tcsh and GLOBIGNORE (like ksh-93 FIGNORE). + + It is passed a NULL-terminated array of (char *)'s that must be + free()'d if they are deleted. The first element (names[0]) is the + least-common-denominator string of the matching patterns (i.e. + u produces names[0] = "und", names[1] = "under.c", names[2] = + "undun.c", name[3] = NULL). */ + +struct ign { + char *val; + int len, flags; +}; + +struct ignorevar { + char *varname; /* FIGNORE or GLOBIGNORE */ + struct ign *ignores; /* Store the ignore strings here */ + int num_ignores; /* How many are there? */ + char *last_ignoreval; /* Last value of variable - cached for speed */ + Function *item_func; /* Called when each item is parsed from $`varname' */ +}; + +extern void setup_ignore_patterns __P((struct ignorevar *)); + +extern void setup_glob_ignore __P((char *)); +extern int should_ignore_glob_matches __P((void)); +extern void ignore_glob_matches __P((char **)); + +#endif diff --git a/pathnames.h b/pathnames.h new file mode 100644 index 0000000..2800118 --- /dev/null +++ b/pathnames.h @@ -0,0 +1,30 @@ +/* pathnames.h -- absolute filenames that bash wants for various defaults. */ + +/* Copyright (C) 1987,1991 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 1, 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, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#if !defined (_PATHNAMES_H_) +#define _PATHNAMES_H_ + +/* The default file for hostname completion. */ +#define DEFAULT_HOSTS_FILE "/etc/hosts" + +/* The default login shell startup file. */ +#define SYS_PROFILE "/etc/profile" + +#endif /* _PATHNAMES_H */ diff --git a/portbash/README b/portbash/README deleted file mode 100644 index 93a9348..0000000 --- a/portbash/README +++ /dev/null @@ -1 +0,0 @@ -run sh mkdesc.sh for a first cut at a machines.h entry diff --git a/portbash/libc.sh b/portbash/libc.sh deleted file mode 100644 index 28429b3..0000000 --- a/portbash/libc.sh +++ /dev/null @@ -1,172 +0,0 @@ -#! /bin/sh - -CC=cc -export CC - -cat > x.c < /dev/null 2>&1; then - : -else - echo '#undef HAVE_ALLOCA' -fi -rm -f x.c x.o a.out - -cat > x.c << EOF -#include -#include -extern char *getwd(); -main() -{ - getwd(); -} -EOF - -if ${CC} x.c > /dev/null 2>&1; then - echo '#define HAVE_GETWD' -else - echo '#undef HAVE_GETWD' - rm -f x.c x.o a.out - - cat > x.c << EOF -extern char *getcwd(); - -main() -{ - getcwd(); -} -EOF - - if ${CC} x.c >/dev/null 2>&1; then - echo '#define HAVE_GETCWD' - fi -fi -rm -f a.out x.c x.o - -cat > x.c << EOF -/* - * exit 0 if we have bcopy in libc and it works as in BSD - */ - -extern int bcopy(); - -char x[] = "12345"; -char y[] = "67890"; - -main() -{ - bcopy(x, y, 5); - exit(strcmp(x, y)); -} -EOF - -if ${CC} x.c > /dev/null 2>&1 && ./a.out ; then - BC='-DHAVE_BCOPY' -fi - -rm -f x.c x.o a.out - -cat > x.c << EOF -/* - * If this compiles, the system has uid_t and gid_t - */ - -#include - -uid_t u; -gid_t g; - -main() -{ - exit(0); -} -EOF - -if ${CC} x.c > /dev/null 2>&1; then - UIDT='-DHAVE_UID_T' -fi - -rm -f x.c x.o a.out - -cat > x.c < - -extern char *sys_siglist[]; - -main() -{ - char *x; - - x = sys_siglist[3]; - write(2, x, strlen(x)); - exit(0); -} -EOF - -if ${CC} ./x.c >/dev/null 2>&1; then - echo '#define HAVE_SYS_SIGLIST' -else - - cat > x.c < - -extern char *_sys_siglist[]; - -main() -{ - exit(0); -} -EOF - - if ${CC} ./x.c >/dev/null 2>&1; then - echo '#define HAVE_SYS_SIGLIST' - SL='-Dsys_siglist=_sys_siglist' - fi -fi - -PG= -if ${CC} pgrp.c >/dev/null 2>&1; then - PG=`./a.out` -fi - -if [ -f /unix ] && [ -f /usr/ccs/lib/libc.so ]; then - R4="-DUSGr4" -fi - -touch not_a_directory -if [ -f /usr/include/dirent.h ]; then - d='' -else - d='' -fi - -cat > x.c << EOF -/* - * exit 0 if opendir does not check whether its argument is a directory - */ - -#include $d -DIR *dir; - -main() -{ - dir = opendir("not_a_directory"); - exit (dir == 0); -} -EOF - -if ${CC} x.c > /dev/null 2>&1 && ./a.out ; then - OD='-DOPENDIR_NOT_ROBUST' -fi - -rm -f x.c x.o a.out pgrp.o not_a_directory -echo "#define SYSDEP_CFLAGS $BC $UIDT $SL $PG $R4 $OD" -exit 0 diff --git a/portbash/mkdesc.sh b/portbash/mkdesc.sh deleted file mode 100644 index 77e8232..0000000 --- a/portbash/mkdesc.sh +++ /dev/null @@ -1,11 +0,0 @@ -#! /bin/sh - -if [ -f /unix ]; then - echo '#define M_OS "USG"' -fi - -sh signals.sh -sh stdio.sh -sh strings.sh -sh syscalls.sh -sh libc.sh diff --git a/portbash/pgrp.c b/portbash/pgrp.c deleted file mode 100644 index 5198dd6..0000000 --- a/portbash/pgrp.c +++ /dev/null @@ -1,48 +0,0 @@ -/* - * If this system has a BSD-style getpgrp() call which takes a pid - * as an argument, output a -DBSD_GETPGRP. - */ -#include -#include - -int pid; -int pg1, pg2, pg3, pg4; -int ng, np, s, child; - -main() -{ - pid = getpid(); - pg1 = getpgrp(0); - pg2 = getpgrp(); - pg3 = getpgrp(pid); - pg4 = getpgrp(1); - - /* - * If all of these values are the same, it's pretty sure that - * we're on a system that ignores getpgrp's first argument. - */ - if (pg2 == pg4 && pg1 == pg3 && pg2 == pg3) - exit(0); - - child = fork(); - if (child < 0) - exit(1); - else if (child == 0) { - np = getpid(); - /* - * If this is Sys V, this will not work; pgrp will be - * set to np because setpgrp just changes a pgrp to be - * the same as the pid. - */ - setpgrp(np, pg1); - ng = getpgrp(0); /* Same result for Sys V and BSD */ - if (ng == pg1) { - printf("-DBSD_GETPGRP\n"); - exit(0); - } else - exit(1); - } else { - wait(&s); - exit(s>>8); - } -} diff --git a/portbash/signals.sh b/portbash/signals.sh deleted file mode 100644 index bcdb5ff..0000000 --- a/portbash/signals.sh +++ /dev/null @@ -1,64 +0,0 @@ -#! /bin/sh -# -CC=cc -export CC - -cat > x.c < - -main() -{ -} -EOF - -${CC} -E x.c > x.i || { rm -f x.c x.i ; exit 1; } - -if egrep 'void.*signal' x.i >/dev/null 2>&1 -then - echo '#define VOID_SIGHANDLER' -fi -rm -f x.c x.i - -cat > x.c << EOF -#include -sigset_t set, oset; -main() -{ - sigemptyset(&set); - sigemptyset(&oset); - sigaddset(&set, 2); - sigprocmask(SIG_BLOCK, &set, &oset); -} -EOF -if ${CC} x.c >/dev/null 2>&1; then - echo '#define HAVE_POSIX_SIGNALS' -else - cat > x.c << EOF -#include -main() -{ - long omask = sigblock(sigmask(2)); - sigsetmask(omask); -} -EOF - if ${CC} x.c >/dev/null 2>&1; then - echo '#define HAVE_BSD_SIGNALS' - else - cat > x.c << EOF -#include -main() -{ - int n; - n = sighold(2); - sigrelse(2); -} -EOF - if ${CC} x.c >/dev/null 2>&1; then - echo '#define HAVE_USG_SIGHOLD' - fi - fi -fi - -rm -f x.c x.o a.out - -exit 0 diff --git a/portbash/stdio.sh b/portbash/stdio.sh deleted file mode 100644 index 6a1be93..0000000 --- a/portbash/stdio.sh +++ /dev/null @@ -1,87 +0,0 @@ -#! /bin/sh -# -# test certain aspects of stdio -CC=cc -export CC - -cat > x.c << EOF -#include -#include - -xp(va_alist) -va_dcl -{ - va_list args; - va_start (args); - vfprintf(stdout, "abcde", args); -} - -main() -{ - xp(); - exit(0); -} -EOF - -if ${CC} x.c >/dev/null 2>&1 -then - echo '#define HAVE_VFPRINTF' - rm -f x.c x.o a.out -else - - cat > x.c << EOF -#include - -main() -{ - _doprnt(); -} -EOF - - if ${CC} x.c >/dev/null 2>&1 - then - echo '#define USE_VFPRINTF_EMULATION' - rm -f x.c x.o a.out - fi -fi - -cat > x.c << EOF -#include -main() -{ - setlinebuf(stdout); -} -EOF - -if ${CC} x.c > /dev/null 2>&1 -then - rm -f x.c x.o a.out - echo '#define HAVE_SETLINEBUF' -else - # check for setvbuf - # If this compiles, the system has setvbuf. If this segfaults while - # running, non-reversed systems get a seg violation - - cat > x.c << EOF -#include - -main() -{ - setvbuf(stdout, _IOLBF, (char *)0, BUFSIZ); /* reversed */ - exit(0); /* non-reversed systems segv */ -} -EOF - - if ${CC} x.c >/dev/null 2>&1 ; then - echo '#define HAVE_SETVBUF' - if a.out; then - : - else - rm -f core - echo '#define REVERSED_SETVBUF_ARGS' - fi - fi -fi - -rm -f x.c x.o a.out -exit 0 diff --git a/portbash/strings.sh b/portbash/strings.sh deleted file mode 100644 index 99a686a..0000000 --- a/portbash/strings.sh +++ /dev/null @@ -1,87 +0,0 @@ -#! /bin/sh -CC=cc -export CC - -if [ -f /usr/include/string.h ]; then - STRINGH='' -elif [ -f /usr/include/strings.h ]; then - STRINGH='' -else - exit 1 -fi - -cat > x.c << EOF -#include $STRINGH - -#ifndef strchr -extern char *strchr(); -#endif - -char *x = "12345"; - -main() -{ - char *s; - - s = strchr(x, '2'); - if (s) - exit(0); - exit(1); -} -EOF - -if ${CC} x.c >/dev/null 2>&1 -then - if ./a.out - then - echo '#define HAVE_STRCHR' - fi -fi - -rm -f x.c x.o a.out - -cat > x.c << EOF -extern char *strerror(); - -main() -{ - char *s; - - s = strerror(2); - if (s) - exit(0); - exit(1); -} -EOF - -if ${CC} x.c >/dev/null 2>&1 -then - if ./a.out - then - echo '#define HAVE_STRERROR' - fi -fi - -rm -f x.c x.o a.out - - -cat > x.c << EOF - -main() -{ - if (strcasecmp("abc", "AbC") == 0) - exit(0); - exit(1); -} -EOF - -if ${CC} x.c >/dev/null 2>&1 -then - if ./a.out - then - echo '#define HAVE_STRCASECMP' - fi -fi - -rm -f x.c x.o a.out -exit 0 diff --git a/portbash/syscalls.sh b/portbash/syscalls.sh deleted file mode 100644 index e89a742..0000000 --- a/portbash/syscalls.sh +++ /dev/null @@ -1,80 +0,0 @@ -#! /bin/sh -CC=cc -export CC - -cat > x.c << EOF -/* - * exit 0 if we have the getgroups system or library call. - */ - -main() -{ - int g[100], ng; - - ng = getgroups(100, g); - if (ng) - exit(0); - exit(1); -} -EOF -if ${CC} x.c > /dev/null 2>&1 && ./a.out ; then - echo '#define HAVE_GETGROUPS' -fi -rm -f x.c x.o a.out - -cat > x.c << EOF -extern int dup2(); -main() -{ - exit(dup2(1, 2) == -1); -} -EOF - -if ${CC} x.c > /dev/null 2>&1 && ./a.out ; then - echo '#define HAVE_DUP2' -fi -rm -f a.out x.c x.o - -cat > x.c << EOF -extern int getpageesize(); -main() -{ - int n = getpagesize(); -} -EOF - -if ${CC} x.c > /dev/null 2>&1 -then - echo '#define HAVE_GETPAGESIZE' -fi -rm -f a.out x.c x.o - -cat > x.c << EOF -extern int getdtablesize(); -main() -{ - int n = getdtablesize(); -} -EOF - -if ${CC} x.c > /dev/null 2>&1 -then - echo '#define HAVE_GETDTABLESIZE' -fi -rm -f a.out x.c x.o - -cat > x.c << EOF -extern int setdtablesize(); -main() -{ - int n = setdtablesize(128); -} -EOF - -if ${CC} x.c > /dev/null 2>&1 -then - echo '#define HAVE_SETDTABLESIZE' -fi -rm -f a.out x.c x.o - -exit 0 diff --git a/posixdir.h b/posixdir.h new file mode 100644 index 0000000..8b0e5bc --- /dev/null +++ b/posixdir.h @@ -0,0 +1,49 @@ +/* posixdir.h -- Posix directory reading includes and defines. */ + +/* Copyright (C) 1987,1991 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 1, 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, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* This file should be included instead of or . */ + +#if !defined (_POSIXDIR_H_) +#define _POSIXDIR_H_ + +#if defined (HAVE_DIRENT_H) +# include +# define D_NAMLEN(d) (strlen ((d)->d_name)) +#else +# if defined (HAVE_SYS_NDIR_H) +# include +# endif +# if defined (HAVE_SYS_DIR_H) +# include +# endif +# if defined (HAVE_NDIR_H) +# include +# endif +# if !defined (dirent) +# define dirent direct +# endif /* !dirent */ +# define D_NAMLEN(d) ((d)->d_namlen) +#endif /* !HAVE_DIRENT_H */ + +#if defined (STRUCT_DIRENT_HAS_D_INO) +# define d_fileno d_ino +#endif + +#endif /* !_POSIXDIR_H_ */ diff --git a/posixstat.h b/posixstat.h index 7d1cece..bfce8c0 100644 --- a/posixstat.h +++ b/posixstat.h @@ -21,34 +21,27 @@ /* This file should be included instead of . It relies on the local sys/stat.h to work though. */ -#if !defined (_POSIXSTAT_H) -#define _POSIXSTAT_H +#if !defined (_POSIXSTAT_H_) +#define _POSIXSTAT_H_ #include -#if defined (isc386) -# if !defined (S_IFDIR) -# define S_IFDIR 0040000 -# endif /* !S_IFDIR */ -# if !defined (S_IFMT) -# define S_IFMT 0170000 -# endif /* !S_IFMT */ -#endif /* isc386 */ - -/* This text is taken directly from the Cadmus I was trying to - compile on: - the following MACROs are defined for X/OPEN compatibility - however, is the param correct ?? - #define S_ISBLK(s) ((s.st_mode & S_IFMT) == S_IFBLK) - - Well, the answer is no. Thus... */ -#if defined (BrainDeath) +#if defined (STAT_MACROS_BROKEN) # undef S_ISBLK # undef S_ISCHR # undef S_ISDIR # undef S_ISFIFO # undef S_ISREG -#endif /* BrainDeath */ +# undef S_ISLNK +#endif /* STAT_MACROS_BROKEN */ + +/* These are guaranteed to work only on isc386 */ +#if !defined (S_IFDIR) && !defined (S_ISDIR) +# define S_IFDIR 0040000 +#endif /* !S_IFDIR && !S_ISDIR */ +#if !defined (S_IFMT) +# define S_IFMT 0170000 +#endif /* !S_IFMT */ /* Posix 1003.1 5.6.1.1 file types */ @@ -114,7 +107,7 @@ /* * POSIX 1003.1 5.6.1.2 File Modes */ - + #if !defined (S_IRWXU) # if !defined (S_IREAD) # define S_IREAD 00400 @@ -146,4 +139,4 @@ #define S_IWUGO (S_IWUSR | S_IWGRP | S_IWOTH) #define S_IXUGO (S_IXUSR | S_IXGRP | S_IXOTH) -#endif /* _POSIXSTAT_H */ +#endif /* _POSIXSTAT_H_ */ diff --git a/print_cmd.c b/print_cmd.c index b70e8d4..4b95d8f 100644 --- a/print_cmd.c +++ b/print_cmd.c @@ -17,32 +17,41 @@ 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, 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include "config.h" + #include -#if defined (HAVE_VARARGS_H) -# include +#if defined (HAVE_UNISTD_H) +# include +#endif + +#if defined (PREFER_STDARG) +# include +#else +# if defined (PREFER_VARARGS) +# include +# endif #endif -#if defined (HAVE_STRING_H) -# include -#else /* !HAVE_STRING_H */ -# include -#endif /* !HAVE_STRING_H */ +#include "bashansi.h" #include "shell.h" #include "y.tab.h" #include "stdc.h" #include "builtins/common.h" -#if defined (__GNUC__) || defined (ardent) +#if !defined (PRINTF_DECLARED) extern int printf __P((const char *, ...)); /* Yuck. Double yuck. */ #endif -static int indentation = 0; +static int indentation; static int indentation_amount = 4; -static void cprintf (), newline (), indent (), the_printed_command_resize (); +static void cprintf __P((char *, ...)); + +static void newline (), indent (), the_printed_command_resize (); static void semicolon (); +static void xprintf (); static void make_command_string_internal (); static void command_print_word_list (); @@ -69,12 +78,12 @@ int the_printed_command_size = 0; int command_string_index = 0; /* Non-zero means the stuff being printed is inside of a function def. */ -static int inside_function_def = 0; -static int skip_this_indent = 0; +static int inside_function_def; +static int skip_this_indent; /* The depth of the group commands that we are currently printing. This includes the group command that is a function body. */ -static int group_command_nesting = 0; +static int group_command_nesting; /* Print COMMAND (a command tree) on standard output. */ void @@ -103,7 +112,7 @@ static void make_command_string_internal (command) COMMAND *command; { - if (!command) + if (command == 0) cprintf (""); else { @@ -115,6 +124,9 @@ make_command_string_internal (command) if (command->flags & CMD_WANT_SUBSHELL) cprintf ("( "); + if (command->flags & CMD_TIME_PIPELINE) + cprintf ("time "); + if (command->flags & CMD_INVERT_RETURN) cprintf ("! "); @@ -150,7 +162,7 @@ make_command_string_internal (command) print_simple_command (command->value.Simple); break; - case cm_connection: + case cm_connection: skip_this_indent++; make_command_string_internal (command->value.Connection->first); @@ -181,7 +193,7 @@ make_command_string_internal (command) if (command->value.Connection->second) skip_this_indent++; break; - + case ';': cprintf (";"); @@ -203,7 +215,7 @@ make_command_string_internal (command) make_command_string_internal (command->value.Connection->second); break; - + case cm_function_def: print_function_def (command->value.Function_def); break; @@ -231,20 +243,40 @@ _print_word_list (list, separator, pfunc) char *separator; VFunction *pfunc; { - while (list) - { - (*pfunc) ("%s", list->word->word); - list = list->next; - if (list) - (*pfunc) ("%s", separator); - } + WORD_LIST *w; + + for (w = list; w; w = w->next) + (*pfunc) ("%s%s", w->word->word, w->next ? separator : ""); } -void print_word_list (list, separator) +void +print_word_list (list, separator) WORD_LIST *list; char *separator; { - _print_word_list (list, separator, (VFunction *)printf); + _print_word_list (list, separator, xprintf); +} + +/* A function to print the words of a simple command when set -x is on. */ +void +xtrace_print_word_list (list) + WORD_LIST *list; +{ + WORD_LIST *w; + char *t; + + fprintf (stderr, "%s", indirection_level_string ()); + for (w = list; w; w = w->next) + { + t = w->word->word; + if (t == 0 || *t == '\0') + fprintf (stderr, "''%s", w->next ? " " : ""); + else if (contains_shell_metas (t)) + fprintf (stderr, "'%s'%s", t, w->next ? " " : ""); + else + fprintf (stderr, "%s%s", t, w->next ? " " : ""); + } + fprintf (stderr, "\n"); } static void @@ -294,12 +326,12 @@ print_group_command (group_command) group_command_nesting++; cprintf ("{ "); - if (!inside_function_def) + if (inside_function_def == 0) skip_this_indent++; else { /* This is a group command { ... } inside of a function - definition, and should be handled as a `normal' group + definition, and should be printed as a multiline group command, using the current indentation. */ cprintf ("\n"); indentation += indentation_amount; @@ -307,17 +339,20 @@ print_group_command (group_command) make_command_string_internal (group_command->command); - cprintf ("\n"); - - if (group_command_nesting) + if (inside_function_def) { + cprintf ("\n"); indentation -= indentation_amount; indent (indentation); - if (!indentation) - cprintf (" "); } - + else + { + semicolon (); + cprintf (" "); + } + cprintf ("}"); + group_command_nesting--; } @@ -472,7 +507,7 @@ print_redirection (redirect) if (redirector != 0) cprintf ("%d", redirector); /* If the here document delimiter is quoted, single-quote it. */ - if (redirect->redirectee.filename->quoted) + if (redirect->redirectee.filename->flags & W_QUOTED) { char *x; x = single_quote (redirect->here_doc_eof); @@ -543,11 +578,10 @@ print_function_def (func) inside_function_def++; indentation += indentation_amount; - if (func->command->type == cm_group) - make_command_string_internal (func->command->value.Group->command); - else - make_command_string_internal (func->command); - + make_command_string_internal (func->command->type == cm_group + ? func->command->value.Group->command + : func->command); + remove_unwind_protect (); indentation -= indentation_amount; inside_function_def--; @@ -567,8 +601,10 @@ named_function_string (name, command, multi_line) int multi_line; { char *result; - int old_indent = indentation, old_amount = indentation_amount; + int old_indent, old_amount; + old_indent = indentation; + old_amount = indentation_amount; command_string_index = 0; if (name && *name) @@ -576,7 +612,7 @@ named_function_string (name, command, multi_line) cprintf ("() "); - if (!multi_line) + if (multi_line == 0) { indentation = 1; indentation_amount = 0; @@ -589,15 +625,11 @@ named_function_string (name, command, multi_line) inside_function_def++; - if (multi_line) - cprintf ("{ \n"); - else - cprintf ("{ "); + cprintf (multi_line ? "{ \n" : "{ "); - if (command->type == cm_group) - make_command_string_internal (command->value.Group->command); - else - make_command_string_internal (command); + make_command_string_internal (command->type == cm_group + ? command->value.Group->command + : command); indentation = old_indent; indentation_amount = old_amount; @@ -636,12 +668,21 @@ newline (string) cprintf ("%s", string); } +static char *indentation_string; +static int indentation_size; + static void indent (amount) int amount; { - while (amount-- > 0) - cprintf (" "); + register int i; + + RESIZE_MALLOCED_BUFFER (indentation_string, 0, amount, indentation_size, 16); + + for (i = 0; amount > 0; amount--) + indentation_string[i++] = ' '; + indentation_string[i] = '\0'; + cprintf (indentation_string); } static void @@ -652,7 +693,7 @@ semicolon () cprintf (";"); } -#if !defined (HAVE_VARARGS_H) +#if !defined (USE_VARARGS) /* How to make the string. */ static void cprintf (format, arg1, arg2) @@ -730,16 +771,24 @@ cprintf (format, arg1, arg2) /* How to make the string. */ static void -cprintf (va_alist) +#if defined (PREFER_STDARG) +cprintf (char *control, ...) +#else +cprintf (control, va_alist) + char *control; va_dcl +#endif { register char *s; - char *control, char_arg[2], *argp; + char char_arg[2], *argp; int digit_arg, arg_len, c; va_list args; +#if defined (PREFER_STDARG) + va_start (args, control); +#else va_start (args); - control = va_arg (args, char *); +#endif arg_len = strlen (control); the_printed_command_resize (arg_len + 1); @@ -748,8 +797,10 @@ cprintf (va_alist) s = control; while (s && *s) { - int free_argp = 0; + int free_argp; + free_argp = 0; c = *s++; + argp = (char *)NULL; if (c != '%' || !*s) { argp = s - 1; @@ -786,10 +837,11 @@ cprintf (va_alist) default: programming_error ("cprintf: bad `%%' argument (%c)", c); + /*NOTREACHED*/ } } - if (argp) + if (argp && arg_len) { the_printed_command_resize (arg_len + 1); FASTCOPY (argp, the_printed_command + command_string_index, arg_len); @@ -825,3 +877,29 @@ the_printed_command_resize (length) the_printed_command = xrealloc (the_printed_command, the_printed_command_size); } } + +#if defined (HAVE_VFPRINTF) + +static void +xprintf (va_alist) + va_dcl +{ + va_list args; + char *format; + + va_start (args); + format = va_arg (args, char *); + vfprintf (stdout, format, args); + va_end (args); +} + +#else + +static void +xprintf (format, arg1, arg2, arg3, arg4, arg5) + char *format; +{ + printf (format, arg1, arg2, arg3, arg4, arg5); +} + +#endif /* !HAVE_VFPRINTF */ diff --git a/quit.h b/quit.h index 57de7a0..a524efc 100644 --- a/quit.h +++ b/quit.h @@ -18,8 +18,8 @@ with Bash; see the file COPYING. If not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ -#if !defined (__QUIT_H__) -#define __QUIT_H__ +#if !defined (_QUIT_H_) +#define _QUIT_H_ /* Non-zero means SIGINT has already ocurred. */ extern int interrupt_state; @@ -30,4 +30,10 @@ extern void throw_to_top_level (); it is safe, put QUIT in the code, and the "interrupt" will take place. */ #define QUIT if (interrupt_state) throw_to_top_level () -#endif /* __QUIT_H__ */ +#define SETINTERRUPT interrupt_state = 1 +#define CLRINTERRUPT interrupt_state = 0 + +#define ADDINTERRUPT interrupt_state++ +#define DELINTERRUPT interrupt_state-- + +#endif /* _QUIT_H_ */ diff --git a/sh b/sh deleted file mode 120000 index 5d4150d..0000000 --- a/sh +++ /dev/null @@ -1 +0,0 @@ -/bin/bash \ No newline at end of file diff --git a/shell.c b/shell.c index 26b20c0..84932ee 100644 --- a/shell.c +++ b/shell.c @@ -32,22 +32,28 @@ */ #define INSTALL_DEBUG_MODE +#include "config.h" + #include "bashtypes.h" +#include +#include "posixstat.h" +#include "bashansi.h" #include #include #include -#include #include "filecntl.h" #include -#include "posixstat.h" -#include "bashansi.h" -#if defined (HAVE_VARARGS_H) -#include +#if defined (HAVE_UNISTD_H) +# include #endif #include "shell.h" #include "flags.h" +#include "trap.h" +#include "mailcheck.h" +#include "builtins.h" +#include "builtins/common.h" #if defined (JOB_CONTROL) #include "jobs.h" @@ -62,49 +68,31 @@ #endif #include +#include -#if defined (USG) && !defined (HAVE_GETPW_DECLS) +#if !defined (HAVE_GETPW_DECLS) extern struct passwd *getpwuid (); -#endif /* USG && !HAVE_GETPW_DECLS */ +#endif /* !HAVE_GETPW_DECLS */ -extern int yydebug; #if !defined (errno) extern int errno; #endif -extern char *dist_version; +extern char *dist_version, *release_status; extern int patch_level, build_version; -extern int subshell_environment; /* Found in execute_cmd.c. */ +extern int subshell_environment; extern int last_command_exit_value; -extern int return_catch_flag; -extern jmp_buf return_catch; -extern int need_here_doc, current_command_line_count, line_number; -extern char *ps1_prompt, **prompt_string_pointer; -extern int loop_level, continuing, breaking; -extern int parse_and_execute_level; +extern int line_number; +extern char *primary_prompt, *secondary_prompt; +extern int expand_aliases; extern char *this_command_name; /* Non-zero means that this shell has already been run; i.e. you should call shell_reinitialize () if you need to start afresh. */ -static int shell_initialized = 0; -static int sourced_env = 0; - -/* The current maintainer of the shell. You change this in the - Makefile. */ -#if !defined (MAINTAINER) -#define MAINTAINER "bash-maintainers@prep.ai.mit.edu" -#endif - -char *the_current_maintainer = MAINTAINER; - -char *primary_prompt = PPROMPT; -char *secondary_prompt = SPROMPT; +int shell_initialized = 0; COMMAND *global_command = (COMMAND *)NULL; -/* Non-zero after SIGINT. */ -int interrupt_state = 0; - /* Information about the current user. */ struct user_info current_user = { @@ -151,46 +139,44 @@ int executing = 0; /* The number of commands executed so far. */ int current_command_number = 1; -/* The environment at the top-level REP loop. We use this in the case of - error return. */ -jmp_buf top_level, catch; - -#if defined (JOB_CONTROL) || defined (_POSIX_VERSION) -/* The signal masks that this shell runs with. */ -sigset_t top_level_mask; -#endif /* JOB_CONTROL */ - /* Non-zero is the recursion depth for commands. */ int indirection_level = 0; -/* The number of times BASH has been executed. This is set - by initialize_variables () in variables.c. */ -int shell_level = 0; - /* The name of this shell, as taken from argv[0]. */ char *shell_name = (char *)NULL; /* time in seconds when the shell was started */ time_t shell_start_time; +/* Are we running in an emacs shell window? */ +int running_under_emacs; + /* The name of the .(shell)rc file. */ static char *bashrc_file = "~/.bashrc"; /* Non-zero means to act more like the Bourne shell on startup. */ -static int act_like_sh = 0; +static int act_like_sh; + +/* Non-zero if this shell is being run by `su'. */ +static int su_shell; + +/* Non-zero if we have already expanded and sourced $ENV. */ +static int sourced_env; + +/* Is this shell running setuid? */ +static int running_setuid; /* Values for the long-winded argument names. */ -static int debugging = 0; /* Do debugging things. */ -static int no_rc = 0; /* Don't execute ~/.bashrc */ -static int no_profile = 0; /* Don't execute .profile */ -static int do_version = 0; /* Display interesting version info. */ -static int quiet = 0; /* Be quiet when starting up. */ -static int make_login_shell = 0; /* Make this shell be a `-bash' shell. */ +static int debugging; /* Do debugging things. */ +static int no_rc; /* Don't execute ~/.bashrc */ +static int no_profile; /* Don't execute .profile */ +static int do_version; /* Display interesting version info. */ +static int make_login_shell; /* Make this shell be a `-bash' shell. */ +static int want_initial_help; /* --help option */ int no_line_editing = 0; /* Don't do fancy line editing. */ -int no_brace_expansion = 0; /* Non-zero means no foo{a,b} -> fooa foob. */ - int posixly_correct = 0; /* Non-zero means posix.2 superset. */ +int dump_translatable_strings; /* Dump strings in $"...", don't execute. */ /* Some long-winded argument names. These are obviously new. */ #define Int 1 @@ -202,15 +188,19 @@ struct { char **char_value; } long_args[] = { { "debug", Int, &debugging, (char **)0x0 }, - { "norc", Int, &no_rc, (char **)0x0 }, + { "dump-strings", Int, &dump_translatable_strings, (char **)0x0 }, + { "help", Int, &want_initial_help, (char **)0x0 }, + { "login", Int, &make_login_shell, (char **)0x0 }, + { "noediting", Int, &no_line_editing, (char **)0x0 }, { "noprofile", Int, &no_profile, (char **)0x0 }, + { "norc", Int, &no_rc, (char **)0x0 }, + { "posix", Int, &posixly_correct, (char **)0x0 }, { "rcfile", Charp, (int *)0x0, &bashrc_file }, +#if defined (RESTRICTED_SHELL) + { "restricted", Int, &restricted, (char **)0x0 }, +#endif + { "verbose", Int, &echo_input_at_read, (char **)0x0 }, { "version", Int, &do_version, (char **)0x0 }, - { "quiet", Int, &quiet, (char **)0x0 }, - { "login", Int, &make_login_shell, (char **)0x0 }, - { "nolineediting", Int, &no_line_editing, (char **)0x0 }, - { "nobraceexpansion", Int, &no_brace_expansion, (char **)0x0 }, - { "posix", Int, &posixly_correct, (char **)0x0 }, { (char *)0x0, Int, (int *)0x0, (char **)0x0 } }; @@ -218,7 +208,7 @@ struct { longjmp back to main to execute a shell script, instead of calling main () again and resulting in indefinite, possibly fatal, stack growth. */ -jmp_buf subshell_top_level; +procenv_t subshell_top_level; int subshell_argc; char **subshell_argv; char **subshell_envp; @@ -228,55 +218,53 @@ char **subshell_envp; int default_buffered_input = -1; #endif -static int want_pending_command; +static int read_from_stdin; /* -s flag supplied */ +static int want_pending_command; /* -c flag supplied */ static char *local_pending_command; -static int isnetconn (); +static FILE *default_input; + +static int parse_long_options (); +static int parse_shell_options (); static void run_startup_files (); +static int bind_args (); +static int open_shell_script (); +static void set_bash_input (); +static int run_one_command (); + +static int uidget (); +static int isnetconn (); +static void init_interactive (), init_noninteractive (); +static void set_shell_name (); static void shell_initialize (); static void shell_reinitialize (); -static void initialize_signals (); -static void initialize_terminating_signals (); +static void show_shell_usage (); + +int main (argc, argv, env) int argc; char **argv, **env; { register int i; - int arg_index, locally_skip_execution; - int top_level_arg_index, read_from_stdin; - FILE *default_input; - - /* There is a bug in the NeXT 2.1 rlogind that causes opens - of /dev/tty to fail. */ -#if defined (RLOGIN_PGRP_BUG) - { - int tty_fd; - - tty_fd = open ("/dev/tty", O_RDWR); - - if (tty_fd < 0) - { - char *tty; - tty = (char *)ttyname (fileno (stdin)); - tty_fd = open (tty, O_RDWR); - } - close (tty_fd); - } -#endif /* RLOGIN_PGRP_BUG */ + int code; + volatile int locally_skip_execution; + volatile int arg_index, top_level_arg_index; + + /* Catch early SIGINTs. */ + code = setjmp (top_level); + if (code) + exit (2); + + check_dev_tty (); /* Wait forever if we are debugging a login shell. */ while (debugging_login_shell); - current_user.uid = getuid (); - current_user.gid = getgid (); - current_user.euid = geteuid (); - current_user.egid = getegid (); + set_default_locale (); - /* See whether or not we are running setuid or setgid. */ - privileged_mode = (current_user.uid != current_user.euid) || - (current_user.gid != current_user.egid); + running_setuid = uidget (); posixly_correct = (getenv ("POSIXLY_CORRECT") != (char *)NULL) || (getenv ("POSIX_PEDANTIC") != (char *)NULL); @@ -293,12 +281,10 @@ main (argc, argv, env) sourced_env = 0; } - /* Initialize local variables for all `invocations' of main (). */ + /* Initialize `local' variables for all `invocations' of main (). */ arg_index = 1; local_pending_command = (char *)NULL; - want_pending_command = 0; - locally_skip_execution = 0; - read_from_stdin = 0; + want_pending_command = locally_skip_execution = read_from_stdin = 0; default_input = stdin; #if defined (BUFFERED_INPUT) default_buffered_input = -1; @@ -321,75 +307,28 @@ main (argc, argv, env) exit (2); } - /* Here's a hack. If the name of this shell is "sh", then don't do - any startup files; just try to be more like /bin/sh. */ - /* XXX - next version - make this be the same as -posix. */ - shell_name = base_pathname (argv[0]); - if (*shell_name == '-') - shell_name++; - if (shell_name[0] == 's' && shell_name[1] == 'h' && !shell_name[2]) - act_like_sh++; - - yydebug = 0; - shell_environment = env; - shell_name = argv[0]; - dollar_vars[0] = savestring (shell_name); - - if (*shell_name == '-') - { - shell_name++; - login_shell++; - } - -#if defined (JOB_CONTROL) - if (act_like_sh) - job_control = 0; /* XXX - not posix */ -#endif /* JOB_CONTROL */ - + set_shell_name (argv[0]); shell_start_time = NOW; /* NOW now defined in general.h */ - /* A program may start an interactive shell with - "execl ("/bin/bash", "-", NULL)". - If so, default the name of this shell to our name. */ - if (!shell_name || !*shell_name || (shell_name[0] == '-' && !shell_name[1])) - shell_name = "bash"; - /* Parse argument flags from the input line. */ /* Find full word arguments first. */ - while ((arg_index != argc) && *(argv[arg_index]) == '-') + arg_index = parse_long_options (argv, arg_index, argc); + + if (want_initial_help) { - for (i = 0; long_args[i].name; i++) - { - if (STREQ (&(argv[arg_index][1]), long_args[i].name)) - { - if (long_args[i].type == Int) - *long_args[i].int_value = 1; - else - { - if (!argv[++arg_index]) - { - report_error ("option `%s' expected an argument", - long_args[i].name); - exit (1); - } - else - *long_args[i].char_value = argv[arg_index]; - } - goto handle_next_arg; - } - } - break; /* No such argument. Maybe flag arg. */ - handle_next_arg: - arg_index++; + show_shell_usage (stdout); + exit (EXECUTION_SUCCESS); } - /* If we're in a strict Posix.2 mode, turn on interactive comments. */ - if (posixly_correct) - interactive_comments = 1; + if (do_version) + { + show_shell_version (1); + exit (EXECUTION_SUCCESS); + } - /* If user supplied the "-login" flag, then set and invert LOGIN_SHELL. */ + /* If user supplied the "--login" flag, then set and invert LOGIN_SHELL. */ if (make_login_shell) { login_shell++; @@ -398,66 +337,18 @@ main (argc, argv, env) /* All done with full word options; do standard shell option parsing.*/ this_command_name = shell_name; /* for error reporting */ - while (arg_index != argc && argv[arg_index] && - (*argv[arg_index] == '-' || *argv[arg_index] == '+')) - { - /* There are flag arguments, so parse them. */ - int arg_character, on_or_off, next_arg; - char *o_option, *arg_string; - - i = 1; - next_arg = arg_index + 1; - arg_string = argv[arg_index]; - on_or_off = arg_string[0]; - - /* A single `-' signals the end of options. From the 4.3 BSD sh. - An option `--' means the same thing; this is the standard - getopt(3) meaning. */ - if (arg_string[0] == '-' && - (arg_string[1] == '\0' || - (arg_string[1] == '-' && arg_string[2] == '\0'))) - { - arg_index++; - break; - } + arg_index = parse_shell_options (argv, arg_index, argc); - while (arg_character = arg_string[i++]) - { - switch (arg_character) - { - case 'c': - want_pending_command = 1; - break; - - case 's': - read_from_stdin = 1; - break; - - case 'o': - o_option = argv[next_arg]; - if (!o_option) - { - list_minus_o_opts (); - break; - } - if (set_minus_o_option (on_or_off, o_option) != EXECUTION_SUCCESS) - exit (1); - next_arg++; - break; + if (dump_translatable_strings) + read_but_dont_execute = 1; - default: - if (change_flag (arg_character, on_or_off) == FLAG_ERROR) - { - report_error ("%c%c: bad option", on_or_off, arg_character); - exit (1); - } + /* If we're in a strict Posix.2 mode, turn on interactive comments and + other Posix.2 things. */ + if (posixly_correct) + posix_initialize (posixly_correct); - } - } - /* Can't do just a simple increment anymore -- what about - "bash -abouo emacs ignoreeof -hP"? */ - arg_index = next_arg; - } + if (running_setuid && privileged_mode == 0) + disable_priv_mode (); /* Need to get the argument to a -c option processed in the above loop. The next arg is a command to execute, and the @@ -465,14 +356,14 @@ main (argc, argv, env) if (want_pending_command) { local_pending_command = argv[arg_index]; - if (!local_pending_command) + if (local_pending_command == 0) { - report_error ("`-c' requires an argument"); - exit (1); + report_error ("option `-c' requires an argument"); + exit (EX_USAGE); } arg_index++; } - this_command_name = (char *)NULL; + this_command_name = (char *)NULL; /* First, let the outside world know about our interactive status. A shell is interactive if the `-i' flag was given, or if all of @@ -489,23 +380,9 @@ main (argc, argv, env) read_from_stdin) && /* -s flag with args, and */ isatty (fileno (stdin)) && /* Input is a terminal and */ isatty (fileno (stdout)))) /* output is a terminal. */ - { - interactive_shell = startup_state = interactive = 1; - } + init_interactive (); else - { -#if defined (HISTORY) -# if defined (BANG_HISTORY) - history_expansion = 0; -# endif - remember_on_history = 0; -#endif /* HISTORY */ - interactive_shell = startup_state = interactive = 0; - no_line_editing = 1; -#if defined (JOB_CONTROL) - job_control = 0; -#endif /* JOB_CONTROL */ - } + init_noninteractive (); #define CLOSE_FDS_AT_LOGIN #if defined (CLOSE_FDS_AT_LOGIN) @@ -527,43 +404,42 @@ main (argc, argv, env) Variables from the environment are expected to be set, etc. */ shell_initialize (); + set_default_locale_vars (); + if (interactive_shell) { - char *term = getenv ("TERM"); + char *term; + + term = getenv ("TERM"); no_line_editing |= term && (STREQ (term, "emacs")); + term = getenv ("EMACS"); + running_under_emacs = term ? ((fnmatch ("*term*", term, 0) == 0) ? 2 : 1) + : 0; } top_level_arg_index = arg_index; - if (!quiet && do_version) - show_shell_version (); - /* Give this shell a place to longjmp to before executing the startup files. This allows users to press C-c to abort the lengthy startup. */ - { - int code; - - code = setjmp (top_level); - - if (code) - { - if (code == EXITPROG) - goto exit_shell; - else - locally_skip_execution++; - } - } + code = setjmp (top_level); + if (code) + { + if (code == EXITPROG) + exit_shell (last_command_exit_value); + else + locally_skip_execution++; + } arg_index = top_level_arg_index; /* Execute the start-up scripts. */ - if (!interactive_shell) + if (interactive_shell == 0) { makunbound ("PS1", shell_variables); makunbound ("PS2", shell_variables); - interactive = 0; + interactive = expand_aliases = 0; } else { @@ -571,43 +447,52 @@ main (argc, argv, env) interactive = 1; } - if (!locally_skip_execution) + if (locally_skip_execution == 0 && running_setuid == 0) run_startup_files (); + /* If we are invoked as `sh', turn on Posix mode. */ + if (act_like_sh) + posix_initialize (posixly_correct = 1); + #if defined (RESTRICTED_SHELL) - /* I turn on the restrictions afterwards because it is explictly - stated in the POSIX spec that PATH cannot be set in a restricted - shell, except in .profile. */ - maybe_make_restricted (shell_name); + /* Turn on the restrictions after parsing the startup files. */ + maybe_make_restricted (shell_name); #endif /* RESTRICTED_SHELL */ - if (local_pending_command) - { - /* Bind remaining args to $0 ... $n */ - WORD_LIST *args = (WORD_LIST *)NULL; - while (arg_index != argc) - args = make_word_list (make_word (argv[arg_index++]), args); - if (args) - { - args = REVERSE_LIST (args, WORD_LIST *); - /* Posix.2 4.56.3 says that the first argument after - sh -c command becomes $0, and the rest of the arguments - are bound to $1 ... $N. */ - shell_name = savestring (args->word->word); /* XXX */ - dollar_vars[0] = savestring (args->word->word); - remember_args (args->next, 1); - dispose_words (args); - } - - startup_state = 2; + if (local_pending_command) + { + arg_index = bind_args (argv, arg_index, argc, 0); + + startup_state = 2; #if defined (ONESHOT) - run_one_command (local_pending_command); - goto exit_shell; + run_one_command (local_pending_command); + exit_shell (last_command_exit_value); #else /* ONESHOT */ - with_input_from_string (local_pending_command, "-c"); - goto read_and_execute; + with_input_from_string (local_pending_command, "-c"); + goto read_and_execute; #endif /* !ONESHOT */ - } + } + + /* Get possible input filename and set up default_buffered_input or + default_input as appropriate. */ + if (arg_index != argc && read_from_stdin == 0) + { + open_shell_script (argv[arg_index]); + arg_index++; + } + else if (interactive == 0) + /* In this mode, bash is reading a script from stdin, which is a + pipe or redirected file. */ +#if defined (BUFFERED_INPUT) + default_buffered_input = fileno (stdin); /* == 0 */ +#else + setbuf (default_input, (char *)NULL); +#endif /* !BUFFERED_INPUT */ + + set_bash_input (); + + /* Bind remaining args to $1 ... $n */ + arg_index = bind_args (argv, arg_index, argc, 1); /* Do the things that should be done only for interactive shells. */ if (interactive_shell) @@ -618,7 +503,8 @@ main (argc, argv, env) #if defined (HISTORY) /* Initialize the interactive history stuff. */ - if (!shell_initialized) + bash_initialize_history (); + if (shell_initialized == 0) load_history (); #endif /* HISTORY */ @@ -627,242 +513,185 @@ main (argc, argv, env) get_tty_state (); } - /* Get possible input filename. */ - if ((arg_index != argc) && !read_from_stdin) - { - int fd; - char *filename; +#if !defined (ONESHOT) + read_and_execute: +#endif /* !ONESHOT */ - free (dollar_vars[0]); - dollar_vars[0] = savestring (argv[arg_index]); - filename = savestring (argv[arg_index]); + shell_initialized = 1; - fd = open (filename, O_RDONLY); - if ((fd < 0) && (errno == ENOENT) && (absolute_program (filename) == 0)) - { - char *path_filename; - /* If it's not in the current directory, try looking through PATH - for it. */ - path_filename = find_path_file (argv[arg_index]); - if (path_filename) - { - free (filename); - filename = path_filename; - fd = open (filename, O_RDONLY); - } - } + /* Read commands until exit condition. */ + reader_loop (); + exit_shell (last_command_exit_value); +} - arg_index++; - if (fd < 0) +static int +parse_long_options (argv, arg_start, arg_end) + char **argv; + int arg_start, arg_end; +{ + int arg_index, longarg, i; + char *arg_string; + + arg_index = arg_start; + while ((arg_index != arg_end) && (arg_string = argv[arg_index]) && + (*arg_string == '-')) + { + longarg = 0; + + /* Make --login equivalent to -login. */ + if (arg_string[1] == '-' && arg_string[2]) { - file_error (filename); - exit (1); + longarg = 1; + arg_string++; } - /* Only do this with file descriptors we can seek on. */ - if (lseek (fd, 0L, 1) != -1) + for (i = 0; long_args[i].name; i++) { - unsigned char sample[80]; - int sample_len; - - /* Check to see if the `file' in `bash file' is a binary file - according to the same tests done by execute_simple_command (), - and report an error and exit if it is. */ - sample_len = read (fd, sample, sizeof (sample)); - if (sample_len > 0 && (check_binary_file (sample, sample_len))) + if (STREQ (arg_string + 1, long_args[i].name)) { - report_error ("%s: cannot execute binary file", filename); - exit (EX_BINARY_FILE); + if (long_args[i].type == Int) + *long_args[i].int_value = 1; + else if (argv[++arg_index] == 0) + { + report_error ("option `%s' requires an argument", + long_args[i].name); + exit (EX_USAGE); + } + else + *long_args[i].char_value = argv[arg_index]; + + break; } - /* Now rewind the file back to the beginning. */ - lseek (fd, 0L, 0); } - -#if defined (BUFFERED_INPUT) - default_buffered_input = fd; - if (default_buffered_input == -1) + if (long_args[i].name == 0) { - file_error (filename); - exit (127); + if (longarg) + { + report_error ("%s: unrecognized option", argv[arg_index]); + exit (EX_USAGE); + } + break; /* No such argument. Maybe flag arg. */ } - SET_CLOSE_ON_EXEC (default_buffered_input); -#else /* !BUFFERED_INPUT */ + arg_index++; + } + + return (arg_index); +} + +static int +parse_shell_options (argv, arg_start, arg_end) + char **argv; + int arg_start, arg_end; +{ + int arg_index; + int arg_character, on_or_off, next_arg, i; + char *o_option, *arg_string; + + arg_index = arg_start; + while (arg_index != arg_end && (arg_string = argv[arg_index]) && + (*arg_string == '-' || *arg_string == '+')) + { + /* There are flag arguments, so parse them. */ + next_arg = arg_index + 1; + + /* A single `-' signals the end of options. From the 4.3 BSD sh. + An option `--' means the same thing; this is the standard + getopt(3) meaning. */ + if (arg_string[0] == '-' && + (arg_string[1] == '\0' || + (arg_string[1] == '-' && arg_string[2] == '\0'))) + return (next_arg); - /* Open the script. But try to move the file descriptor to a randomly - large one, in the hopes that any descriptors used by the script will - not match with ours. */ - { - int script_fd, nfds; - - nfds = getdtablesize (); - if (nfds <= 0) - nfds = 20; - if (nfds > 256) - nfds = 256; - script_fd = dup2 (fd, nfds - 1); - if (script_fd) - { - close (fd); - fd = script_fd; - } - } - - default_input = fdopen (fd, "r"); - - if (!default_input) + i = 1; + on_or_off = arg_string[0]; + while (arg_character = arg_string[i++]) { - file_error (filename); - exit (127); + switch (arg_character) + { + case 'c': + want_pending_command = 1; + break; + + case 's': + read_from_stdin = 1; + break; + + case 'o': + o_option = argv[next_arg]; + if (o_option == 0) + { + list_minus_o_opts (); + break; + } + if (set_minus_o_option (on_or_off, o_option) != EXECUTION_SUCCESS) + exit (EX_USAGE); + next_arg++; + break; + + case 'D': + dump_translatable_strings = 1; + break; + + default: + if (change_flag (arg_character, on_or_off) == FLAG_ERROR) + { + report_error ("%c%c: unrecognized option", on_or_off, arg_character); + exit (EX_USAGE); + } + } } + /* Can't do just a simple increment anymore -- what about + "bash -abouo emacs ignoreeof -hP"? */ + arg_index = next_arg; + } - SET_CLOSE_ON_EXEC (fd); - if (fileno (default_input) != fd) - SET_CLOSE_ON_EXEC (fileno (default_input)); + return (arg_index); +} -#endif /* !BUFFERED_INPUT */ +/* Exit the shell with status S. */ +int +exit_shell (s) + int s; +{ + /* Do trap[0] if defined. Allow it to override the exit status + passed to us. */ + if (signal_is_trapped (0)) + s = run_exit_trap (); + +#if defined (PROCESS_SUBSTITUTION) + unlink_fifo_list (); +#endif /* PROCESS_SUBSTITUTION */ - if (!interactive_shell || (!isatty (fd))) - { #if defined (HISTORY) -# if defined (BANG_HISTORY) - history_expansion = 0; -# endif - remember_on_history = 0; + if (interactive_shell) + maybe_save_shell_history (); #endif /* HISTORY */ - interactive = interactive_shell = 0; - no_line_editing = 1; + #if defined (JOB_CONTROL) - set_job_control (0); -#endif /* JOB_CONTROL */ - } - else - { - /* I don't believe that this code is ever executed, even in - the presence of /dev/fd. */ - dup2 (fd, 0); - close (fd); - fclose (default_input); - } - } - else if (!interactive) - /* In this mode, bash is reading a script from stdin, which is a - pipe or redirected file. */ -#if defined (BUFFERED_INPUT) - default_buffered_input = fileno (stdin); /* == 0 */ -#else - setbuf (default_input, (char *)NULL); -#endif /* !BUFFERED_INPUT */ - - /* Bind remaining args to $1 ... $n */ - { - WORD_LIST *args = (WORD_LIST *)NULL; - while (arg_index != argc) - args = make_word_list (make_word (argv[arg_index++]), args); - args = REVERSE_LIST (args, WORD_LIST *); - remember_args (args, 1); - dispose_words (args); - } - -#if defined (BUFFERED_INPUT) - if (!interactive) - unset_nodelay_mode (default_buffered_input); - else - unset_nodelay_mode (fileno (stdin)); -#else - unset_nodelay_mode (fileno (stdin)); -#endif /* !BUFFERED_INPUT */ - - /* with_input_from_stdin really means `with_input_from_readline' */ - if (interactive && !no_line_editing) - with_input_from_stdin (); - else -#if defined (BUFFERED_INPUT) - { - if (!interactive) - with_input_from_buffered_stream (default_buffered_input, dollar_vars[0]); - else - with_input_from_stream (default_input, dollar_vars[0]); - } -#else /* !BUFFERED_INPUT */ - with_input_from_stream (default_input, dollar_vars[0]); -#endif /* !BUFFERED_INPUT */ - -#if !defined (ONESHOT) - read_and_execute: -#endif /* !ONESHOT */ - - shell_initialized = 1; - - /* Read commands until exit condition. */ - reader_loop (); - - exit_shell: - /* Do trap[0] if defined. */ - if (signal_is_trapped (0)) - last_command_exit_value = run_exit_trap (); - -#if defined (PROCESS_SUBSTITUTION) - unlink_fifo_list (); -#endif /* PROCESS_SUBSTITUTION */ - -#if defined (HISTORY) - if (interactive_shell) - maybe_save_shell_history (); -#endif /* HISTORY */ - -#if defined (JOB_CONTROL) - /* If this shell is interactive, terminate all stopped jobs and - restore the original terminal process group. */ - end_job_control (); + /* If this shell is interactive, terminate all stopped jobs and + restore the original terminal process group. */ + end_job_control (); #endif /* JOB_CONTROL */ /* Always return the exit status of the last command to our parent. */ - exit (last_command_exit_value); + exit (s); } -#if !defined (SYS_PROFILE) -# define SYS_PROFILE "/etc/profile" -#endif /* !SYS_PROFILE */ - /* Source the bash startup files. If POSIXLY_CORRECT is non-zero, we obey the Posix.2 startup file rules: $ENV is expanded, and if the file it names exists, that file is sourced. The Posix.2 rules are in effect - for both interactive and non-interactive shells (section 4.56.5.3) */ -static void -run_startup_files () -{ - if (!posixly_correct) - { - if (login_shell) - { - /* We don't execute .bashrc for login shells. */ - no_rc++; - if (no_profile == 0) - maybe_execute_file (SYS_PROFILE, 1); - } + for interactive shells only. (section 4.56.5.3) */ - if (login_shell && !no_profile) - { - if (act_like_sh) - maybe_execute_file ("~/.profile", 1); - else - { - if (maybe_execute_file ("~/.bash_profile", 1) == 0) - if (maybe_execute_file ("~/.bash_login", 1) == 0) - maybe_execute_file ("~/.profile", 1); - } - } - - /* Execute ~/.bashrc for most shells. Never execute it if - ACT_LIKE_SH is set, or if NO_RC is set. +/* Execute ~/.bashrc for most shells. Never execute it if + ACT_LIKE_SH is set, or if NO_RC is set. - If the executable file "/usr/gnu/src/bash/foo" contains: + If the executable file "/usr/gnu/src/bash/foo" contains: - #!/usr/gnu/bin/bash - echo hello + #!/usr/gnu/bin/bash + echo hello - then: + then: COMMAND EXECUTE BASHRC -------------------------------- @@ -874,154 +703,158 @@ run_startup_files () echo ls | bash NO login NO bash YES - */ - if (!act_like_sh && !no_rc && - (interactive_shell || (isnetconn (fileno (stdin)) && - local_pending_command))) - maybe_execute_file (bashrc_file, 1); +*/ + +static void +execute_env_file (env_file) + char *env_file; +{ + char *fn; + WORD_LIST *list; + + if (env_file && *env_file) + { + list = expand_string_unsplit (env_file, Q_DOUBLE_QUOTES); + if (list) + { + fn = string_list (list); + dispose_words (list); + + if (fn && *fn) + maybe_execute_file (fn, 1); + FREE (fn); + } } +} - /* Try a TMB suggestion. If running a script, then execute the - file mentioned in the ENV variable. */ - if (!privileged_mode && sourced_env++ == 0 && act_like_sh == 0 && - (posixly_correct || !interactive_shell)) +static void +run_startup_files () +{ + /* get the rshd case out of the way first. */ + if (interactive_shell == 0 && no_rc == 0 && login_shell == 0 && + act_like_sh == 0 && local_pending_command && isnetconn (fileno (stdin))) { - char *env_file = (char *)NULL; +#ifdef SYS_BASHRC + maybe_execute_file (SYS_BASHRC, 1); +#endif + maybe_execute_file (bashrc_file, 1); + return; + } - if (!posixly_correct) - env_file = getenv ("BASH_ENV"); - if (!env_file) - env_file = getenv ("ENV"); + /* A non-interactive shell not named `sh' and not in posix mode reads and + executes commands from $BASH_ENV. If `su' starts a shell with `-c cmd' + and `-su' as the name of the shell, we want to read the startup files. + No other non-interactive shells read any startup files. */ + if (interactive_shell == 0 && !(su_shell && login_shell)) + { + if (posixly_correct == 0 && act_like_sh == 0 && privileged_mode == 0 && + sourced_env++ == 0) + execute_env_file (get_string_value ("BASH_ENV")); + return; + } - if (env_file && *env_file) - { - WORD_LIST *list; - char *expanded_file_name; + /* Interactive shell or `-su' shell. */ + if (posixly_correct == 0) /* bash, sh */ + { + /* We don't execute .bashrc for login shells. */ + if (login_shell) + no_rc++; - list = expand_string_unsplit (env_file, 1); - if (list) - { - expanded_file_name = string_list (list); - dispose_words (list); + /* Execute /etc/profile and one of the personal login shell + initialization files. */ + if (login_shell && no_profile == 0) + { + maybe_execute_file (SYS_PROFILE, 1); - if (expanded_file_name && *expanded_file_name) - maybe_execute_file (expanded_file_name, 1); + if (act_like_sh) /* sh */ + maybe_execute_file ("~/.profile", 1); + else if ((maybe_execute_file ("~/.bash_profile", 1) == 0) && + (maybe_execute_file ("~/.bash_login", 1) == 0)) /* bash */ + maybe_execute_file ("~/.profile", 1); + } - if (expanded_file_name) - free (expanded_file_name); - } + /* bash */ + if (act_like_sh == 0 && no_rc == 0) + { +#ifdef SYS_BASHRC + maybe_execute_file (SYS_BASHRC, 1); +#endif + maybe_execute_file (bashrc_file, 1); } + /* sh */ + else if (act_like_sh && privileged_mode == 0 && sourced_env++ == 0) + execute_env_file (get_string_value ("ENV")); + } + else /* bash --posix, sh --posix */ + { + /* bash and sh */ + if (interactive_shell && privileged_mode == 0 && sourced_env++ == 0) + execute_env_file (get_string_value ("ENV")); } } #if defined (RESTRICTED_SHELL) -/* Perhaps make this shell a `restricted' one, based on NAME. - If the basename of NAME is "rbash", then this shell is restricted. +/* Perhaps make this shell a `restricted' one, based on NAME. If the + basename of NAME is "rbash", then this shell is restricted. The + name of the restricted shell is a configurable option, see config.h. In a restricted shell, PATH and SHELL are read-only and non-unsettable. Do this also if `restricted' is already set to 1; maybe the shell was started with -r. */ +int maybe_make_restricted (name) char *name; { char *temp; temp = base_pathname (shell_name); - if (restricted || (STREQ (temp, "rbash"))) + if (restricted || (STREQ (temp, RESTRICTED_SHELL_NAME))) { set_var_read_only ("PATH"); - non_unsettable ("PATH"); set_var_read_only ("SHELL"); - non_unsettable ("SHELL"); restricted++; } + return (restricted); } #endif /* RESTRICTED_SHELL */ -/* Try to execute the contents of FNAME. If FNAME doesn't exist, - that is not an error, but other kinds of errors are. A non-zero - FORCE_NONINTERACTIVE means to set the value of `interactive' to - 0 so things like job control are disabled; the value is unchanged - otherwise. Returns -1 in the case of an error, 0 in the case that - the file was not found, and 1 if the file was found and executed. */ -maybe_execute_file (fname, force_noninteractive) - char *fname; - int force_noninteractive; +/* Fetch the current set of uids and gids and return 1 if we're running + setuid or setgid. */ +static int +uidget () { - jmp_buf old_return_catch; - int return_val, fd, tresult, old_interactive; - char *filename, *string; - struct stat file_info; - - filename = tilde_expand (fname); - fd = open (filename, O_RDONLY); - - if (fd < 0) - { -file_error_and_exit: - if (errno != ENOENT) - file_error (filename); - free (filename); - return ((errno == ENOENT) ? 0 : -1); - } - - if (fstat (fd, &file_info) == -1) - goto file_error_and_exit; - - if (S_ISDIR (file_info.st_mode)) - { - internal_error ("%s: cannot execute directories", filename); - free (filename); - return -1; - } - - string = (char *)xmalloc (1 + (int)file_info.st_size); - tresult = read (fd, string, file_info.st_size); - - { - int tt = errno; - close (fd); - errno = tt; - } - - if (tresult != file_info.st_size) - { - free (string); - goto file_error_and_exit; - } - string[file_info.st_size] = '\0'; - - return_catch_flag++; - xbcopy ((char *)return_catch, (char *)old_return_catch, sizeof (jmp_buf)); + uid_t u; - if (force_noninteractive) + u = getuid (); + if (current_user.uid != u) { - old_interactive = interactive; - interactive = 0; + FREE (current_user.user_name); + FREE (current_user.shell); + FREE (current_user.home_dir); + current_user.user_name = current_user.shell = current_user.home_dir = (char *)NULL; } + current_user.uid = u; + current_user.gid = getgid (); + current_user.euid = geteuid (); + current_user.egid = getegid (); - return_val = setjmp (return_catch); - - /* If `return' was seen outside of a function, but in the script, then - force parse_and_execute () to clean up. */ - if (return_val) - parse_and_execute_cleanup (); - else - tresult = parse_and_execute (string, filename, -1); - - if (force_noninteractive) - interactive = old_interactive; - - return_catch_flag--; - xbcopy ((char *)old_return_catch, (char *)return_catch, sizeof (jmp_buf)); - - free (filename); + /* See whether or not we are running setuid or setgid. */ + return (current_user.uid != current_user.euid) || + (current_user.gid != current_user.egid); +} - return (1); +void +disable_priv_mode () +{ + setuid (current_user.uid); + setgid (current_user.gid); + current_user.euid = current_user.uid; + current_user.egid = current_user.gid; } #if defined (ONESHOT) /* Run one command, given as the argument to the -c option. Tell parse_and_execute not to fork for a simple command. */ +static int run_one_command (command) char *command; { @@ -1044,232 +877,229 @@ run_one_command (command) case DISCARD: return last_command_exit_value = 1; default: - programming_error ("Bad jump %d", code); + programming_error ("run_one_command: bad jump: code %d", code); } } return (parse_and_execute (savestring (command), "-c", -1)); } #endif /* ONESHOT */ -reader_loop () +static int +bind_args (argv, arg_start, arg_end, start_index) + char **argv; + int arg_start, arg_end, start_index; { - int our_indirection_level; - COMMAND *current_command = (COMMAND *)NULL; - - our_indirection_level = ++indirection_level; + register int i; + WORD_LIST *args; - while (!EOF_Reached) + for (i = arg_start, args = (WORD_LIST *)NULL; i != arg_end; i++) + args = make_word_list (make_word (argv[i]), args); + if (args) { - int code; - - code = setjmp (top_level); - -#if defined (PROCESS_SUBSTITUTION) - unlink_fifo_list (); -#endif /* PROCESS_SUBSTITUTION */ - - if (interactive_shell && signal_is_ignored (SIGINT) == 0) - set_signal_handler (SIGINT, sigint_sighandler); - - if (code != NOT_JUMPED) + args = REVERSE_LIST (args, WORD_LIST *); + if (start_index == 0) /* bind to $0...$n for sh -c command */ { - indirection_level = our_indirection_level; - - switch (code) - { - /* Some kind of throw to top_level has occured. */ - case FORCE_EOF: - case EXITPROG: - current_command = (COMMAND *)NULL; - EOF_Reached = EOF; - goto exec_done; - - case DISCARD: - /* Obstack free command elements, etc. */ - if (current_command) - { - dispose_command (current_command); - current_command = (COMMAND *)NULL; - } - last_command_exit_value = 1; - break; - - default: - programming_error ("Bad jump %d", code); - } + /* Posix.2 4.56.3 says that the first argument after sh -c command + becomes $0, and the rest of the arguments become $1...$n */ + shell_name = savestring (args->word->word); + dollar_vars[0] = savestring (args->word->word); + remember_args (args->next, 1); } + else /* bind to $1...$n for shell script */ + remember_args (args, 1); - executing = 0; - dispose_used_env_vars (); + dispose_words (args); + } -#if (defined (Ultrix) && defined (mips)) || !defined (HAVE_ALLOCA) - /* Attempt to reclaim memory allocated with alloca (). */ - (void) alloca (0); -#endif + return (i); +} - if (read_command () == 0) - { - if (global_command) - { - current_command = global_command; +void +unbind_args () +{ + remember_args ((WORD_LIST *)NULL, 1); +} - current_command_number++; +static int +open_shell_script (script_name) + char *script_name; +{ + int fd; + char *filename, *path_filename; + unsigned char sample[80]; + int sample_len; - /* POSIX spec: "-n: The shell reads commands but does - not execute them; this can be used to check for shell - script syntax errors. The shell ignores the -n option - for interactive shells. " */ - if (interactive_shell || !read_but_dont_execute) - { - executing = 1; - execute_command (current_command); - } + free (dollar_vars[0]); + dollar_vars[0] = savestring (script_name); + filename = savestring (script_name); - exec_done: - if (current_command) - { - dispose_command (current_command); - current_command = (COMMAND *)NULL; - } - QUIT; - } - } - else + fd = open (filename, O_RDONLY); + if ((fd < 0) && (errno == ENOENT) && (absolute_program (filename) == 0)) + { + /* If it's not in the current directory, try looking through PATH + for it. */ + path_filename = find_path_file (script_name); + if (path_filename) { - /* Parse error, maybe discard rest of stream if not interactive. */ - if (!interactive) - EOF_Reached = EOF; + free (filename); + filename = path_filename; + fd = open (filename, O_RDONLY); } - if (just_one_command) - EOF_Reached = EOF; } - indirection_level--; -} - -/* Return a string denoting what our indirection level is. */ -static char indirection_string[100]; -char * -indirection_level_string () -{ - register int i, j; - char *ps4; + if (fd < 0) + { + int e = errno; + file_error (filename); + exit ((e == ENOENT) ? EX_NOTFOUND : EX_NOINPUT); + } - indirection_string[0] = '\0'; - ps4 = get_string_value ("PS4"); + /* Only do this with file descriptors we can seek on. */ + if (lseek (fd, 0L, 1) != -1) + { + /* Check to see if the `file' in `bash file' is a binary file + according to the same tests done by execute_simple_command (), + and report an error and exit if it is. */ + sample_len = read (fd, sample, sizeof (sample)); + if (sample_len > 0 && (check_binary_file (sample, sample_len))) + { + internal_error ("%s: cannot execute binary file", filename); + exit (EX_BINARY_FILE); + } + /* Now rewind the file back to the beginning. */ + lseek (fd, 0L, 0); + } - if (ps4 == 0 || *ps4 == '\0') - return (indirection_string); - - ps4 = decode_prompt_string (ps4); +#if defined (BUFFERED_INPUT) + default_buffered_input = fd; + if (default_buffered_input == -1) + { + file_error (filename); + exit (EX_NOTFOUND); + } + SET_CLOSE_ON_EXEC (default_buffered_input); +#else /* !BUFFERED_INPUT */ + /* Open the script. But try to move the file descriptor to a randomly + large one, in the hopes that any descriptors used by the script will + not match with ours. */ + fd = move_to_high_fd (fd, 0); - for (i = 0; *ps4 && i < indirection_level && i < 99; i++) - indirection_string[i] = *ps4; + default_input = fdopen (fd, "r"); - for (j = 1; *ps4 && ps4[j] && i < 99; i++, j++) - indirection_string[i] = ps4[j]; + if (default_input == 0) + { + file_error (filename); + exit (EX_NOTFOUND); + } - indirection_string[i] = '\0'; - free (ps4); - return (indirection_string); -} + SET_CLOSE_ON_EXEC (fd); + if (fileno (default_input) != fd) + SET_CLOSE_ON_EXEC (fileno (default_input)); +#endif /* !BUFFERED_INPUT */ -static sighandler -alrm_catcher(i) - int i; -{ - printf ("%ctimed out waiting for input: auto-logout\n", '\07'); - longjmp (top_level, EXITPROG); -#if !defined (VOID_SIGHANDLER) - return (0); -#endif /* !VOID_SIGHANDLER */ + if (interactive_shell == 0 || isatty (fd) == 0) + init_noninteractive (); + else + { + /* I don't believe that this code is ever executed, even in + the presence of /dev/fd. */ + dup2 (fd, 0); + close (fd); + fd = 0; +#if defined (BUFFERED_INPUT) + default_buffered_input = 0; +#else + fclose (default_input); + default_input = stdin; +#endif + } + free (filename); + return (fd); } -parse_command () +/* Initialize the input routines for the parser. */ +static void +set_bash_input () { - int r; - - need_here_doc = 0; - run_pending_traps (); + /* Make sure the fd from which we are reading input is not in + no-delay mode. */ +#if defined (BUFFERED_INPUT) + if (interactive == 0) + unset_nodelay_mode (default_buffered_input); + else +#endif /* !BUFFERED_INPUT */ + unset_nodelay_mode (fileno (stdin)); - /* Allow the execution of a random command just before the printing - of each primary prompt. If the shell variable PROMPT_COMMAND - is set then the value of it is the command to execute. */ - if (interactive && bash_input.type != st_string) + /* with_input_from_stdin really means `with_input_from_readline' */ + if (interactive && no_line_editing == 0) + with_input_from_stdin (); + else +#if defined (BUFFERED_INPUT) { - char *command_to_execute; - - command_to_execute = get_string_value ("PROMPT_COMMAND"); - if (command_to_execute) - execute_prompt_command (command_to_execute); + if (interactive == 0) + with_input_from_buffered_stream (default_buffered_input, dollar_vars[0]); + else + with_input_from_stream (default_input, dollar_vars[0]); } - - current_command_line_count = 0; - r = yyparse (); - - if (need_here_doc) - gather_here_documents (); - - return (r); +#else /* !BUFFERED_INPUT */ + with_input_from_stream (default_input, dollar_vars[0]); +#endif /* !BUFFERED_INPUT */ } -read_command () +#if !defined (PROGRAM) +# define PROGRAM "bash" +#endif + +static void +set_shell_name (argv0) + char *argv0; { - SHELL_VAR *tmout_var = (SHELL_VAR *)NULL; - int tmout_len = 0, result; - SigHandler *old_alrm = (SigHandler *)NULL; + /* Here's a hack. If the name of this shell is "sh", then don't do + any startup files; just try to be more like /bin/sh. */ + shell_name = base_pathname (argv0); + if (*shell_name == '-') + shell_name++; + if (shell_name[0] == 's' && shell_name[1] == 'h' && shell_name[2] == '\0') + act_like_sh++; + if (shell_name[0] == 's' && shell_name[1] == 'u' && shell_name[2] == '\0') + su_shell++; - prompt_string_pointer = &ps1_prompt; - global_command = (COMMAND *)NULL; + shell_name = argv0; + FREE (dollar_vars[0]); + dollar_vars[0] = savestring (shell_name); - /* Only do timeouts if interactive. */ - if (interactive) + if (*shell_name == '-') { - tmout_var = find_variable ("TMOUT"); - - if (tmout_var && tmout_var->value) - { - tmout_len = atoi (tmout_var->value); - if (tmout_len > 0) - { - old_alrm = set_signal_handler (SIGALRM, alrm_catcher); - alarm (tmout_len); - } - } + shell_name++; + login_shell++; } - QUIT; - - current_command_line_count = 0; - result = parse_command (); + /* A program may start an interactive shell with + "execl ("/bin/bash", "-", NULL)". + If so, default the name of this shell to our name. */ + if (!shell_name || !*shell_name || (shell_name[0] == '-' && !shell_name[1])) + shell_name = PROGRAM; +} - if (interactive && tmout_var && (tmout_len > 0)) - { - alarm(0); - set_signal_handler (SIGALRM, old_alrm); - } - return (result); +static void +init_interactive () +{ + interactive_shell = startup_state = interactive = 1; + expand_aliases = 1; } -/* Cause STREAM to buffer lines as opposed to characters or blocks. */ static void -line_buffer_stream (stream) - FILE *stream; +init_noninteractive () { - /* If your machine doesn't have either of setlinebuf or setvbuf, - you can just comment out the buffering commands, and the shell - will still work. It will take more cycles, though. */ -#if defined (HAVE_SETLINEBUF) - setlinebuf (stream); -#else -# if defined (_IOLBF) -# if defined (REVERSED_SETVBUF_ARGS) - setvbuf (stream, _IOLBF, (char *)NULL, BUFSIZ); -# else /* !REVERSED_SETVBUF_ARGS */ - setvbuf (stream, (char *)NULL, _IOLBF, BUFSIZ); -# endif /* !REVERSED_SETVBUF_ARGS */ -# endif /* _IOLBF */ -#endif /* !HAVE_SETLINEBUF */ +#if defined (HISTORY) + bash_history_reinit (0); +#endif /* HISTORY */ + interactive_shell = startup_state = interactive = 0; + expand_aliases = 0; + no_line_editing = 1; +#if defined (JOB_CONTROL) + set_job_control (0); +#endif /* JOB_CONTROL */ } /* Do whatever is necessary to initialize the shell. @@ -1277,9 +1107,12 @@ line_buffer_stream (stream) static void shell_initialize () { + struct passwd *entry; + char hostname[256]; + /* Line buffer output for stderr and stdout. */ - line_buffer_stream (stderr); - line_buffer_stream (stdout); + setlinebuf (stderr); + setlinebuf (stdout); /* Sort the array of shell builtins so that the binary search in find_shell_builtin () works correctly. */ @@ -1292,40 +1125,48 @@ shell_initialize () initialize_traps (); initialize_signals (); - /* Initialize current_user.name and current_host_name. */ - { - struct passwd *entry = getpwuid (current_user.uid); - char hostname[256]; - - if (gethostname (hostname, 255) < 0) - current_host_name = "??host??"; - else - current_host_name = savestring (hostname); - - if (entry) - { - current_user.user_name = savestring (entry->pw_name); - if (entry->pw_shell && entry->pw_shell[0]) - current_user.shell = savestring (entry->pw_shell); - else + /* It's highly unlikely that this will change. */ + if (current_host_name == 0) + { + /* Initialize current_user.name and current_host_name. */ + if (gethostname (hostname, 255) < 0) + current_host_name = "??host??"; + else + current_host_name = savestring (hostname); + } + + /* Don't fetch this more than once. */ + if (current_user.user_name == 0) + { + entry = getpwuid (current_user.uid); + if (entry) + { + current_user.user_name = savestring (entry->pw_name); + current_user.shell = (entry->pw_shell && entry->pw_shell[0]) + ? savestring (entry->pw_shell) + : savestring ("/bin/sh"); + current_user.home_dir = savestring (entry->pw_dir); + } + else + { + current_user.user_name = savestring ("I have no name!"); current_user.shell = savestring ("/bin/sh"); - current_user.home_dir = savestring (entry->pw_dir); - } - else - { - current_user.user_name = savestring ("I have no name!"); - current_user.shell = savestring ("/bin/sh"); - current_user.home_dir = savestring ("/"); - } - - endpwent (); - } + current_user.home_dir = savestring ("/"); + } + endpwent (); + } /* Initialize our interface to the tilde expander. */ tilde_initialize (); - /* Initialize internal and environment variables. */ - initialize_shell_variables (shell_environment); + /* Initialize internal and environment variables. Don't import shell + functions from the environment if we are running in privileged or + restricted mode or if the shell is running setuid. */ +#if defined (RESTRICTED_SHELL) + initialize_shell_variables (shell_environment, privileged_mode||restricted||running_setuid); +#else + initialize_shell_variables (shell_environment, privileged_mode||running_setuid); +#endif /* Initialize filename hash tables. */ initialize_filename_hashing (); @@ -1335,6 +1176,9 @@ shell_initialize () /* Initialize input streams to null. */ initialize_bash_input (); + + /* Initialize the shell options. */ + initialize_shell_options (); } /* Function called by main () when it appears that the shell has already @@ -1360,12 +1204,10 @@ shell_reinitialize () login_shell = make_login_shell = interactive = executing = 0; debugging = do_version = line_number = last_command_exit_value = 0; forced_interactive = interactive_shell = subshell_environment = 0; + expand_aliases = 0; #if defined (HISTORY) -# if defined (BANG_HISTORY) - history_expansion = 0; -# endif - remember_on_history = 0; + bash_history_reinit (0); #endif /* HISTORY */ #if defined (RESTRICTED_SHELL) @@ -1378,383 +1220,58 @@ shell_reinitialize () /* Delete all variables and functions. They will be reinitialized when the environment is parsed. */ - delete_all_variables (shell_variables); delete_all_variables (shell_functions); +#if 0 /* Pretend the PATH variable has changed. */ - sv_path ("PATH"); -} - -static void -initialize_signals () -{ - initialize_terminating_signals (); - initialize_job_signals (); -#if defined (INITIALIZE_SIGLIST) - initialize_siglist (); + flush_hashed_filenames (); #endif } -void -reinitialize_signals () -{ - initialize_terminating_signals (); - initialize_job_signals (); -} - -/* 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; -}; - -#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, -#endif - -#ifdef SIGINT - SIGINT, NULL_HANDLER, -#endif - -#ifdef SIGILL - SIGILL, NULL_HANDLER, -#endif - -#ifdef SIGTRAP - SIGTRAP, NULL_HANDLER, -#endif - -#ifdef SIGIOT - SIGIOT, NULL_HANDLER, -#endif - -#ifdef SIGDANGER - SIGDANGER, NULL_HANDLER, -#endif - -#ifdef SIGEMT - SIGEMT, NULL_HANDLER, -#endif - -#ifdef SIGFPE - SIGFPE, NULL_HANDLER, -#endif - -#ifdef SIGBUS - SIGBUS, NULL_HANDLER, -#endif - -#ifdef SIGSEGV - SIGSEGV, NULL_HANDLER, -#endif - -#ifdef SIGSYS - SIGSYS, NULL_HANDLER, -#endif - -#ifdef SIGPIPE - SIGPIPE, NULL_HANDLER, -#endif - -#ifdef SIGALRM - SIGALRM, NULL_HANDLER, -#endif - -#ifdef SIGTERM - SIGTERM, NULL_HANDLER, -#endif - -#ifdef SIGXCPU - SIGXCPU, NULL_HANDLER, -#endif - -#ifdef SIGXFSZ - SIGXFSZ, NULL_HANDLER, -#endif - -#ifdef SIGVTALRM - SIGVTALRM, NULL_HANDLER, -#endif - -#ifdef SIGPROF - SIGPROF, NULL_HANDLER, -#endif - -#ifdef SIGLOST - SIGLOST, NULL_HANDLER, -#endif - -#ifdef SIGUSR1 - SIGUSR1, NULL_HANDLER, -#endif - -#ifdef SIGUSR2 - SIGUSR2, NULL_HANDLER, -#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) - -/* This function belongs here? */ -sighandler -termination_unwind_protect (sig) - int sig; -{ - if (sig == SIGINT && signal_is_trapped (SIGINT)) - run_interrupt_trap (); - -#if defined (HISTORY) - if (interactive_shell) - 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); - -#if !defined (VOID_SIGHANDLER) - return (0); -#endif /* VOID_SIGHANDLER */ -} - -/* Initialize signals that will terminate the shell to do some - unwind protection. */ static void -initialize_terminating_signals () +show_shell_usage (fp) + FILE *fp; { - register int i; - - /* 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 (_POSIX_VERSION) - struct sigaction act, oact; - - 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++) + int i; + char *set_opts, *s, *t; + + fprintf (fp, "GNU bash, version %s-(%s)\n", shell_version_string (), MACHTYPE); + fprintf (fp, "Usage:\t%s [GNU long option] [option] ...\n\t%s [GNU long option] [option] script-file ...\n", + shell_name, shell_name); + fputs ("GNU long options:\n", fp); + for (i = 0; long_args[i].name; i++) + fprintf (fp, "\t--%s\n", long_args[i].name); + + fputs ("Shell options:\n", fp); + fputs ("\t-irsD or -c command\t\t(invocation only)\n", fp); + + for (i = 0, set_opts = 0; shell_builtins[i].name; i++) + if (STREQ (shell_builtins[i].name, "set")) + set_opts = savestring (shell_builtins[i].short_doc); + if (set_opts) { - sigaction (XSIG (i), &act, &oact); - terminating_signals[i].orig_handler = oact.sa_handler; - /* Don't do anything with signals that are ignored at shell entry - if the shell is not interactive. */ - if (!interactive_shell && oact.sa_handler == SIG_IGN) - { - sigaction (XSIG (i), &oact, &act); - set_signal_ignored (XSIG (i)); - } + s = strchr (set_opts, '['); + if (s == 0) + s = set_opts; + while (*++s == '-') + ; + t = strchr (s, ']'); + if (t) + *t = '\0'; + fprintf (fp, "\t-%s or -o option\n", s); + free (set_opts); } -#else /* !_POSIX_VERSION */ - - for (i = 0; i < TERMSIGS_LENGTH; i++) - { - terminating_signals[i].orig_handler = - set_signal_handler (XSIG (i), termination_unwind_protect); - /* Don't do anything with signals that are ignored at shell entry - if the shell is not interactive. */ - if (!interactive_shell && terminating_signals[i].orig_handler == SIG_IGN) - { - set_signal_handler (XSIG (i), SIG_IGN); - set_signal_ignored (XSIG (i)); - } - } - -#endif /* !_POSIX_VERSION */ - -#if defined (JOB_CONTROL) || defined (_POSIX_VERSION) - /* 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); - sigdelset (&top_level_mask, SIGCHLD); -#endif /* JOB_CONTROL || _POSIX_VERSION */ - - /* 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); - } + fprintf (fp, "Type `%s -c \"help set\"' for more information about shell options.\n", shell_name); + fprintf (fp, "Type `%s -c help' for more information about shell builtin commands.\n", shell_name); + fprintf (fp, "Use the `bashbug' command to report bugs.\n"); } -void -reset_terminating_signals () -{ - register int i; - -#if defined (_POSIX_VERSION) - struct sigaction act; - - 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); - sigaction (XSIG (i), &act, (struct sigaction *) NULL); - } -#else - for (i = 0; i < TERMSIGS_LENGTH; i++) - { - if (signal_is_trapped (XSIG (i)) || signal_is_special (XSIG (i))) - continue; - - set_signal_handler (XSIG (i), XHANDLER (i)); - } -#endif -} -#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; - interrupt_state--; - } - - if (interrupt_state) - return; - - 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); -#endif /* JOB_CONTROL */ - -#if defined (JOB_CONTROL) || defined (_POSIX_VERSION) - 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))) - longjmp (top_level, DISCARD); - else - longjmp (top_level, EXITPROG); -} - -/* When non-zero, we throw_to_top_level (). */ -int interrupt_immediately = 0; - -/* What we really do when SIGINT occurs. */ -sighandler -sigint_sighandler (sig) - int sig; -{ -#if defined (USG) && !defined (_POSIX_VERSION) - set_signal_handler (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) - interrupt_state++; - - if (interrupt_immediately) - { - interrupt_immediately = 0; - throw_to_top_level (); - } -#if !defined (VOID_SIGHANDLER) - return (0); -#endif /* VOID_SIGHANDLER */ -} - -/* Give version information about this shell. */ -char * -shell_version_string () -{ - static char tt[16] = { '\0' }; - - if (!tt[0]) - sprintf (tt, "%s.%d(%d)", dist_version, patch_level, build_version); - return tt; -} - -void -show_shell_version () -{ - printf ("GNU %s, version %s\n", base_pathname (shell_name), - shell_version_string ()); -} - -#if !defined (USG) && defined (ENOTSOCK) -# if !defined (HAVE_SOCKETS) -# define HAVE_SOCKETS -# endif -#endif - -#if defined (HAVE_SOCKETS) -#include +/* The second and subsequent conditions must match those used to decide + whether or not to call getpeername() in isnetconn(). */ +#if defined (HAVE_SYS_SOCKET_H) && defined (HAVE_GETPEERNAME) && !defined (SVR4_2) +# include #endif /* Is FD a socket or network connection? */ @@ -1762,22 +1279,29 @@ static int isnetconn (fd) int fd; { -#if defined (USGr4) || defined (USGr4_2) +#if defined (HAVE_GETPEERNAME) && !defined (SVR4_2) + int rv, l; + struct sockaddr sa; + + l = sizeof(sa); + rv = getpeername(0, &sa, &l); + /* Solaris 2.5 getpeername() returns EINVAL if the fd is not a socket. */ + return ((rv < 0 && (errno == ENOTSOCK || errno == EINVAL)) ? 0 : 1); +#else /* !HAVE_GETPEERNAME || SVR4_2 */ +# if defined (SVR4) || defined (SVR4_2) /* Sockets on SVR4 and SVR4.2 are character special (streams) devices. */ struct stat sb; + if (isatty (fd)) + return (0); if (fstat (fd, &sb) < 0) return (0); +# if defined (S_ISFIFO) + if (S_ISFIFO (sb.st_mode)) + return (0); +# endif /* S_ISFIFO */ return (S_ISCHR (sb.st_mode)); -#else /* !USGr4 && !USGr4_2 */ -# if defined (HAVE_SOCKETS) - int rv, l; - struct sockaddr sa; - - l = sizeof(sa); - rv = getpeername(0, &sa, &l); - return ((rv < 0 && errno == ENOTSOCK) ? 0 : 1); -# else /* !HAVE_SOCKETS */ +# else /* !SVR4 && !SVR4_2 */ # if defined (S_ISSOCK) struct stat sb; @@ -1787,6 +1311,6 @@ isnetconn (fd) # else /* !S_ISSOCK */ return (0); # endif /* !S_ISSOCK */ -# endif /* !HAVE_SOCKETS */ -#endif /* !USGr4 && !USGr4_2 */ +# endif /* !SVR4 && !SVR4_2 */ +#endif /* !HAVE_GETPEERNAME || SVR4_2 */ } diff --git a/shell.h b/shell.h index b7d3132..0b1623e 100644 --- a/shell.h +++ b/shell.h @@ -19,6 +19,9 @@ Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "config.h" + +#include "bashjmp.h" + #include "command.h" #include "general.h" #include "error.h" @@ -29,6 +32,8 @@ #include "dispose_cmd.h" #include "make_cmd.h" #include "subst.h" +#include "sig.h" +#include "pathnames.h" #include "externs.h" extern int EOF_Reached; @@ -39,32 +44,31 @@ extern int EOF_Reached; #define NO_VARIABLE -1 -/* A bunch of stuff for flow of control using setjmp () and longjmp (). */ -#include -extern jmp_buf top_level, catch; - -#define NOT_JUMPED 0 /* Not returning from a longjmp. */ -#define FORCE_EOF 1 /* We want to stop parsing. */ -#define DISCARD 2 /* Discard current command. */ -#define EXITPROG 3 /* Unconditionally exit the program now. */ - /* Values that can be returned by execute_command (). */ #define EXECUTION_FAILURE 1 #define EXECUTION_SUCCESS 0 /* Usage messages by builtins result in a return status of 2. */ -#define EX_USAGE 2 +#define EX_BADUSAGE 2 + +/* Special exit statuses used by the shell, internally and externally. */ +#define EX_BINARY_FILE 126 +#define EX_NOEXEC 126 +#define EX_NOINPUT 126 +#define EX_NOTFOUND 127 -/* Special exit status used when the shell is asked to execute a - binary file as a shell script. */ -#define EX_BINARY_FILE 126 -#define EX_NOEXEC 126 -#define EX_NOTFOUND 127 +#define EX_SHERRBASE 256 /* all special error values are > this. */ + +#define EX_BADSYNTAX 257 /* shell syntax error */ +#define EX_USAGE 258 /* syntax error in usage */ +#define EX_REDIRFAIL 259 /* redirection failed */ +#define EX_BADASSIGN 260 /* variable assignment error */ +#define EX_EXPFAIL 261 /* word expansion failed */ /* The list of characters that are quoted in double-quotes with a backslash. Other characters following a backslash cause nothing special to happen. */ -#define slashify_in_quotes "\\`$\"" +#define slashify_in_quotes "\\`$\"\n" #define slashify_in_here_document "\\`$" /* Constants which specify how to handle backslashes and quoting in @@ -76,7 +80,22 @@ extern jmp_buf top_level, catch; #define Q_DOUBLE_QUOTES 0x1 #define Q_HERE_DOCUMENT 0x2 #define Q_KEEP_BACKSLASH 0x4 +#define Q_NOQUOTE 0x8 +#define Q_QUOTED 0x10 +#define Q_ADDEDQUOTES 0x20 +#define Q_QUOTEDNULL 0x40 + +/* Flag values that control parameter pattern substitution. */ +#define MATCH_ANY 0x0 +#define MATCH_BEG 0x1 +#define MATCH_END 0x2 + +#define MATCH_TYPEMASK 0x3 + +#define MATCH_GLOBREP 0x10 +#define MATCH_QUOTED 0x20 +/* Some needed external declarations. */ extern char **shell_environment; extern WORD_LIST *rest_of_args; diff --git a/sig.c b/sig.c new file mode 100644 index 0000000..d0243f7 --- /dev/null +++ b/sig.c @@ -0,0 +1,482 @@ +/* sig.c - interface for shell signal handlers and signal initialization. */ + +/* Copyright (C) 1994 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, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "config.h" + +#include "bashtypes.h" + +#if defined (HAVE_UNISTD_H) +# include +#endif + +#include +#include + +#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 return_catch_flag; +extern int loop_level, continuing, breaking; +extern int parse_and_execute_level, shell_initialized; +extern int interactive, interactive_shell, login_shell, startup_state; + +/* Non-zero after SIGINT. */ +int interrupt_state; + +/* 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; + +static void initialize_terminating_signals (); + +void +initialize_signals () +{ + initialize_terminating_signals (); + initialize_job_signals (); +#if !defined (HAVE_SYS_SIGLIST) && !defined (HAVE_STRSIGNAL) + initialize_siglist (); +#endif +} + +void +reinitialize_signals () +{ + initialize_terminating_signals (); + initialize_job_signals (); +} + +/* 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; +}; + +#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, +#endif + +#ifdef SIGINT + SIGINT, NULL_HANDLER, +#endif + +#ifdef SIGILL + SIGILL, NULL_HANDLER, +#endif + +#ifdef SIGTRAP + SIGTRAP, NULL_HANDLER, +#endif + +#ifdef SIGIOT + SIGIOT, NULL_HANDLER, +#endif + +#ifdef SIGDANGER + SIGDANGER, NULL_HANDLER, +#endif + +#ifdef SIGEMT + SIGEMT, NULL_HANDLER, +#endif + +#ifdef SIGFPE + SIGFPE, NULL_HANDLER, +#endif + +#ifdef SIGBUS + SIGBUS, NULL_HANDLER, +#endif + +#ifdef SIGSEGV + SIGSEGV, NULL_HANDLER, +#endif + +#ifdef SIGSYS + SIGSYS, NULL_HANDLER, +#endif + +#ifdef SIGPIPE + SIGPIPE, NULL_HANDLER, +#endif + +#ifdef SIGALRM + SIGALRM, NULL_HANDLER, +#endif + +#ifdef SIGTERM + SIGTERM, NULL_HANDLER, +#endif + +#ifdef SIGXCPU + SIGXCPU, NULL_HANDLER, +#endif + +#ifdef SIGXFSZ + SIGXFSZ, NULL_HANDLER, +#endif + +#ifdef SIGVTALRM + SIGVTALRM, NULL_HANDLER, +#endif + +#ifdef SIGPROF + SIGPROF, NULL_HANDLER, +#endif + +#ifdef SIGLOST + SIGLOST, NULL_HANDLER, +#endif + +#ifdef SIGUSR1 + SIGUSR1, NULL_HANDLER, +#endif + +#ifdef SIGUSR2 + SIGUSR2, NULL_HANDLER, +#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) + +/* Initialize signals that will terminate the shell to do some + unwind protection. */ +static void +initialize_terminating_signals () +{ + register int i; + + /* 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) + struct sigaction act, oact; + + 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++) + { + sigaction (XSIG (i), &act, &oact); + terminating_signals[i].orig_handler = oact.sa_handler; + /* Don't do anything with signals that are ignored at shell entry + if the shell is not interactive. */ + if (!interactive_shell && oact.sa_handler == SIG_IGN) + { + sigaction (XSIG (i), &oact, &act); + set_signal_ignored (XSIG (i)); + } + } + +#else /* !HAVE_POSIX_SIGNALS */ + + for (i = 0; i < TERMSIGS_LENGTH; i++) + { + terminating_signals[i].orig_handler = + signal (XSIG (i), termination_unwind_protect); + /* Don't do anything with signals that are ignored at shell entry + if the shell is not interactive. */ + if (!interactive_shell && terminating_signals[i].orig_handler == SIG_IGN) + { + signal (XSIG (i), SIG_IGN); + set_signal_ignored (XSIG (i)); + } + } + +#endif /* !HAVE_POSIX_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); + sigdelset (&top_level_mask, SIGCHLD); +#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); + } +} + +void +reset_terminating_signals () +{ + register int i; + +#if defined (HAVE_POSIX_SIGNALS) + struct sigaction act; + + 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); + 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_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); +#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; +{ + if (sig == SIGINT && signal_is_trapped (SIGINT)) + run_interrupt_trap (); + +#if defined (HISTORY) + 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); +} + +/* 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 ("Bad code in sig.c: sigprocmask"); + } + + 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; + + 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/sig.h b/sig.h new file mode 100644 index 0000000..3819533 --- /dev/null +++ b/sig.h @@ -0,0 +1,121 @@ +/* sig.h -- header file for signal handler definitions. */ + +/* Copyright (C) 1994 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, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* Make sure that this is included *after* config.h! */ + +#if !defined (_SIG_H_) +# define _SIG_H_ + +#include "stdc.h" + +#if !defined (SIGABRT) && defined (SIGIOT) +# define SIGABRT SIGIOT +#endif + +#define sighandler RETSIGTYPE +typedef RETSIGTYPE SigHandler (); + +#if defined (VOID_SIGHANDLER) +# define SIGRETURN(n) return +#else +# define SIGRETURN(n) return(n) +#endif /* !VOID_SIGHANDLER */ + +/* Here is a definition for set_signal_handler () which simply expands to + a call to signal () for non-Posix systems. The code for set_signal_handler + in the Posix case resides in general.c. */ +#if !defined (HAVE_POSIX_SIGNALS) +# define set_signal_handler(sig, handler) (SigHandler *)signal (sig, handler) +#else +extern SigHandler *set_signal_handler (); /* in sig.c */ +#endif /* _POSIX_VERSION */ + +/* Definitions used by the job control code. */ +#if defined (JOB_CONTROL) + +#if !defined (SIGCHLD) && defined (SIGCLD) +# define SIGCHLD SIGCLD +#endif + +#if !defined (HAVE_POSIX_SIGNALS) && !defined (sigmask) +# define sigmask(x) (1 << ((x)-1)) +#endif /* !HAVE_POSIX_SIGNALS && !sigmask */ + +#if !defined (HAVE_POSIX_SIGNALS) +# if !defined (SIG_BLOCK) +# define SIG_BLOCK 2 +# define SIG_SETMASK 3 +# endif /* SIG_BLOCK */ + +/* sigset_t defined in config.h */ + +/* Make sure there is nothing inside the signal set. */ +# define sigemptyset(set) (*(set) = 0) + +/* Initialize the signal set to hold all signals. */ +# define sigfillset(set) (*set) = sigmask (NSIG) - 1 + +/* Add SIG to the contents of SET. */ +# define sigaddset(set, sig) *(set) |= sigmask (sig) + +/* Delete SIG from signal set SET. */ +# define sigdelset(set, sig) *(set) &= ~sigmask (sig) + +/* Is SIG a member of the signal set SET? */ +# define sigismember(set, sig) ((*(set) & sigmask (sig)) != 0) + +/* Suspend the process until the reception of one of the signals + not present in SET. */ +# define sigsuspend(set) sigpause (*(set)) +#endif /* !HAVE_POSIX_SIGNALS */ + +/* These definitions are used both in POSIX and non-POSIX implementations. */ + +#define BLOCK_SIGNAL(sig, nvar, ovar) \ + sigemptyset (&nvar); \ + sigaddset (&nvar, sig); \ + sigemptyset (&ovar); \ + sigprocmask (SIG_BLOCK, &nvar, &ovar) + +#if defined (HAVE_POSIX_SIGNALS) +# define BLOCK_CHILD(nvar, ovar) \ + BLOCK_SIGNAL (SIGCHLD, nvar, ovar) +# define UNBLOCK_CHILD(ovar) \ + sigprocmask (SIG_SETMASK, &ovar, (sigset_t *) NULL) +#else /* !HAVE_POSIX_SIGNALS */ +# define BLOCK_CHILD(nvar, ovar) ovar = sigblock (sigmask (SIGCHLD)) +# define UNBLOCK_CHILD(ovar) sigsetmask (ovar) +#endif /* !HAVE_POSIX_SIGNALS */ + +#endif /* JOB_CONTROL */ + +/* Functions from sig.c. */ +extern sighandler termination_unwind_protect __P((int)); +extern sighandler sigint_sighandler __P((int)); +extern void initialize_signals __P((void)); +extern void reinitialize_signals __P((void)); +extern void reset_terminating_signals __P((void)); +extern void throw_to_top_level __P((void)); +extern void jump_to_top_level __P((int)); + +/* Functions defined in trap.c. */ +extern SigHandler *set_sigint_handler __P((void)); + +#endif /* _SIG_H_ */ diff --git a/siglist.c b/siglist.c index 7571cf0..cb45205 100644 --- a/siglist.c +++ b/siglist.c @@ -18,6 +18,10 @@ 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, 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include "config.h" + +#if !defined (HAVE_SYS_SIGLIST) && !defined (HAVE_STRSIGNAL) + #include #include #include @@ -176,35 +180,35 @@ initialize_siglist () #if defined (SIGMSG) sys_siglist[SIGMSG] = "HFT input data pending"; -#endif +#endif #if defined (SIGPWR) sys_siglist[SIGPWR] = "power failure imminent"; -#endif +#endif #if defined (SIGDANGER) sys_siglist[SIGDANGER] = "system crash imminent"; -#endif +#endif #if defined (SIGMIGRATE) sys_siglist[SIGMIGRATE] = "migrate process to another CPU"; -#endif +#endif #if defined (SIGPRE) sys_siglist[SIGPRE] = "programming error"; -#endif +#endif #if defined (SIGGRANT) sys_siglist[SIGGRANT] = "HFT monitor mode granted"; -#endif +#endif #if defined (SIGRETRACT) sys_siglist[SIGRETRACT] = "HFT monitor mode retracted"; -#endif +#endif #if defined (SIGSOUND) sys_siglist[SIGSOUND] = "HFT sound sequence has completed"; -#endif +#endif for (i = 0; i < NSIG; i++) { @@ -217,3 +221,4 @@ initialize_siglist () } } } +#endif /* !HAVE_SYS_SIGLIST && !HAVE_STRSIGNAL */ diff --git a/siglist.h b/siglist.h index b52d7ad..6fad8da 100644 --- a/siglist.h +++ b/siglist.h @@ -21,20 +21,20 @@ #if !defined (_SIGLIST_H_) #define _SIGLIST_H_ -#if defined (Solaris) || defined (USGr4_2) || defined (drs6000) || defined (amiga) || defined (Minix) -# if !defined (sys_siglist) -# define sys_siglist _sys_siglist -# endif /* !sys_siglist */ -#endif /* Solaris || USGr4_2 || drs6000 || amiga || Minix */ - -#if !defined (Solaris) && !defined (Linux) && !defined (__BSD_4_4__) && \ - !defined (Minix) && !defined (NetBSD) && !defined (FreeBSD) && \ - !defined (BSD_OS) +#if !defined (SYS_SIGLIST_DECLARED) && !defined (HAVE_STRSIGNAL) + +#if defined (HAVE_UNDER_SYS_SIGLIST) && !defined (HAVE_SYS_SIGLIST) && !defined (sys_siglist) +# define sys_siglist _sys_siglist +#endif /* HAVE_UNDER_SYS_SIGLIST && !HAVE_SYS_SIGLIST && !sys_siglist */ + +#if !defined (sys_siglist) extern char *sys_siglist[]; -#endif /* !Solaris && !Linux && !__BSD_4_4__ && !Minix && !NetBSD && !FreeBSD && !BSD_OS */ +#endif /* !sys_siglist */ + +#endif /* !SYS_SIGLIST_DECLARED && !HAVE_STRSIGNAL */ -#if !defined (strsignal) && !defined (Solaris) && !defined (NetBSD) +#if !defined (strsignal) && !defined (HAVE_STRSIGNAL) # define strsignal(sig) (char *)sys_siglist[sig] -#endif /* !strsignal && !Solaris && !NetBSD */ +#endif /* !strsignal && !HAVE_STRSIGNAL */ #endif /* _SIGLIST_H */ diff --git a/stdc.h b/stdc.h index 5dcc32b..f1590c6 100644 --- a/stdc.h +++ b/stdc.h @@ -19,14 +19,15 @@ along with Bash; see the file COPYING. If not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ -#if !defined (__STDC_H__) -#define __STDC_H__ +#if !defined (_STDC_H_) +#define _STDC_H_ /* Adapted from BSD /usr/include/sys/cdefs.h. */ /* A function can be defined using prototypes and compile on both ANSI C and traditional C compilers with something like this: extern char *func __P((char *, char *, int)); */ + #if defined (__STDC__) # if !defined (__P) @@ -75,4 +76,4 @@ #endif /* !__STDC__ */ -#endif /* !__STDC_H__ */ +#endif /* !_STDC_H_ */ diff --git a/stringlib.c b/stringlib.c new file mode 100644 index 0000000..7bc8b49 --- /dev/null +++ b/stringlib.c @@ -0,0 +1,373 @@ +/* stringlib.c - Miscellaneous string functions. */ + +/* Copyright (C) 1996 + 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, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "config.h" + +#include "bashtypes.h" + +#if defined (HAVE_UNISTD_H) +# include +#endif + +#include "bashansi.h" +#include +#include + +#include "shell.h" + +#ifndef to_upper +# define to_upper(c) (islower(c) ? toupper(c) : (c)) +# define to_lower(c) (isupper(c) ? tolower(c) : (c)) +#endif + +/* Convert STRING by expanding the escape sequences specified by the + ANSI C standard. If SAWC is non-null, recognize `\c' and use that + as a string terminator. If we see \c, set *SAWC to 1 before + returning. LEN is the length of STRING. */ +char * +ansicstr (string, len, sawc) + char *string; + int len, *sawc; +{ + int c; + char *ret, *r, *s; + + if (string == 0 || *string == '\0') + return ((char *)NULL); + + ret = xmalloc (len + 1); + for (r = ret, s = string; s && *s; ) + { + c = *s++; + if (c != '\\' || *s == '\0') + *r++ = c; + else + { + switch (c = *s++) + { +#if defined (__STDC__) + case 'a': c = '\a'; break; + case 'v': c = '\v'; break; +#else + case 'a': c = '\007'; break; + case 'v': c = (int) 0x0B; break; +#endif + case 'b': c = '\b'; break; + case 'e': c = '\033'; break; /* ESC -- non-ANSI */ + case 'E': c = '\033'; break; /* ESC -- non-ANSI */ + case 'f': c = '\f'; break; + case 'n': c = '\n'; break; + case 'r': c = '\r'; break; + case 't': c = '\t'; break; + case '0': case '1': case '2': case '3': + case '4': case '5': case '6': case '7': + c -= '0'; + if (*s >= '0' && *s <= '7') + c = c * 8 + (*s++ - '0'); + if (*s >= '0' && *s <= '7') + c = c * 8 + (*s++ - '0'); + break; + case '\\': + case '\'': + break; + case 'c': + if (sawc) + { + *sawc = 1; + *r = '\0'; + return ret; + } + default: *r++ = '\\'; break; + } + *r++ = c; + } + } + *r = '\0'; + return ret; +} + +/* **************************************************************** */ +/* */ +/* Functions to manage arrays of strings */ +/* */ +/* **************************************************************** */ + +/* Find NAME in ARRAY. Return the index of NAME, or -1 if not present. + ARRAY should be NULL terminated. */ +int +find_name_in_array (name, array) + char *name, **array; +{ + int i; + + for (i = 0; array[i]; i++) + if (STREQ (name, array[i])) + return (i); + + return (-1); +} + +/* Return the length of ARRAY, a NULL terminated array of char *. */ +int +array_len (array) + char **array; +{ + register int i; + + for (i = 0; array[i]; i++); + return (i); +} + +/* Free the contents of ARRAY, a NULL terminated array of char *. */ +void +free_array_members (array) + char **array; +{ + register int i; + + if (array == 0) + return; + + for (i = 0; array[i]; i++) + free (array[i]); +} + +void +free_array (array) + char **array; +{ + if (array == 0) + return; + + free_array_members (array); + free (array); +} + +/* Allocate and return a new copy of ARRAY and its contents. */ +char ** +copy_array (array) + char **array; +{ + register int i; + int len; + char **new_array; + + len = array_len (array); + + new_array = (char **)xmalloc ((len + 1) * sizeof (char *)); + for (i = 0; array[i]; i++) + new_array[i] = savestring (array[i]); + new_array[i] = (char *)NULL; + + return (new_array); +} + +/* Comparison routine for use with qsort() on arrays of strings. Uses + strcoll(3) if available, otherwise it uses strcmp(3). */ +int +qsort_string_compare (s1, s2) + register char **s1, **s2; +{ +#if defined (HAVE_STRCOLL) + return (strcoll (*s1, *s2)); +#else /* !HAVE_STRCOLL */ + int result; + + if ((result = **s1 - **s2) == 0) + result = strcmp (*s1, *s2); + + return (result); +#endif /* !HAVE_STRCOLL */ +} + +/* Sort ARRAY, a null terminated array of pointers to strings. */ +void +sort_char_array (array) + char **array; +{ + qsort (array, array_len (array), sizeof (char *), + (Function *)qsort_string_compare); +} + +/* Cons up a new array of words. The words are taken from LIST, + which is a WORD_LIST *. If COPY is true, everything is malloc'ed, + so you should free everything in this array when you are done. + The array is NULL terminated. If IP is non-null, it gets the + number of words in the returned array. STARTING_INDEX says where + to start filling in the returned array; it can be used to reserve + space at the beginning of the array. */ +char ** +word_list_to_argv (list, copy, starting_index, ip) + WORD_LIST *list; + int copy, starting_index, *ip; +{ + int count; + char **array; + + count = list_length (list); + array = (char **)xmalloc ((1 + count + starting_index) * sizeof (char *)); + + for (count = 0; count < starting_index; count++) + array[count] = (char *)NULL; + for (count = starting_index; list; count++, list = list->next) + array[count] = copy ? savestring (list->word->word) : list->word->word; + array[count] = (char *)NULL; + + if (ip) + *ip = count; + return (array); +} + +/* Convert an array of strings into the form used internally by the shell. + COPY means to copy the values in ARRAY into the returned list rather + than allocate new storage. STARTING_INDEX says where in ARRAY to begin. */ +WORD_LIST * +argv_to_word_list (array, copy, starting_index) + char **array; + int copy, starting_index; +{ + WORD_LIST *list; + WORD_DESC *w; + int i, count; + + if (array == 0 || array[0] == 0) + return (WORD_LIST *)NULL; + + for (count = 0; array[count]; count++) + ; + + for (i = starting_index, list = (WORD_LIST *)NULL; i < count; i++) + { + w = make_bare_word (copy ? "" : array[i]); + if (copy) + { + free (w->word); + w->word = array[i]; + } + list = make_word_list (w, list); + } + return (REVERSE_LIST(list, WORD_LIST *)); +} + +/* **************************************************************** */ +/* */ +/* String Management Functions */ +/* */ +/* **************************************************************** */ + +/* Replace occurrences of PAT with REP in STRING. If GLOBAL is non-zero, + replace all occurrences, otherwise replace only the first. + This returns a new string; the caller should free it. */ +char * +strsub (string, pat, rep, global) + char *string, *pat, *rep; + int global; +{ + int patlen, templen, tempsize, repl, i; + char *temp, *r; + + patlen = strlen (pat); + for (temp = (char *)NULL, i = templen = tempsize = 0, repl = 1; string[i]; ) + { + if (repl && STREQN (string + i, pat, patlen)) + { + RESIZE_MALLOCED_BUFFER (temp, templen, patlen, tempsize, (patlen * 2)); + + for (r = rep; *r; ) + temp[templen++] = *r++; + + i += patlen; + repl = global != 0; + } + else + { + RESIZE_MALLOCED_BUFFER (temp, templen, 1, tempsize, 16); + temp[templen++] = string[i++]; + } + } + temp[templen] = 0; + return (temp); +} + +/* Remove all leading whitespace from STRING. This includes + newlines. STRING should be terminated with a zero. */ +void +strip_leading (string) + char *string; +{ + char *start = string; + + while (*string && (whitespace (*string) || *string == '\n')) + string++; + + if (string != start) + { + int len = strlen (string); + FASTCOPY (string, start, len); + start[len] = '\0'; + } +} + +/* Remove all trailing whitespace from STRING. This includes + newlines. If NEWLINES_ONLY is non-zero, only trailing newlines + are removed. STRING should be terminated with a zero. */ +void +strip_trailing (string, newlines_only) + char *string; + int newlines_only; +{ + int len = strlen (string) - 1; + + while (len >= 0) + { + if ((newlines_only && string[len] == '\n') || + (!newlines_only && whitespace (string[len]))) + len--; + else + break; + } + string[len + 1] = '\0'; +} + +/* Determine if s2 occurs in s1. If so, return a pointer to the + match in s1. The compare is case insensitive. This is a + case-insensitive strstr(3). */ +char * +strindex (s1, s2) + char *s1, *s2; +{ + register int i, l, len, c; + + c = to_upper (s2[0]); + for (i = 0, len = strlen (s1), l = strlen (s2); (len - i) >= l; i++) + if ((to_upper (s1[i]) == c) && (strncasecmp (s1 + i, s2, l) == 0)) + return (s1 + i); + return ((char *)NULL); +} + +/* A wrapper for bcopy that can be prototyped in general.h */ +void +xbcopy (s, d, n) + char *s, *d; + int n; +{ + FASTCOPY (s, d, n); +} diff --git a/subst.c b/subst.c index 9dd00a8..054258e 100644 --- a/subst.c +++ b/subst.c @@ -19,15 +19,17 @@ with Bash; see the file COPYING. If not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include "config.h" + #include "bashtypes.h" #include #include #include #include -/* Not all systems declare ERRNO in errno.h... and some systems #define it! */ -#if !defined (errno) -extern int errno; -#endif /* !errno */ + +#if defined (HAVE_UNISTD_H) +# include +#endif #include "bashansi.h" #include "posixstat.h" @@ -37,8 +39,15 @@ extern int errno; #include "jobs.h" #include "execute_cmd.h" #include "filecntl.h" +#include "trap.h" +#include "pathexp.h" +#include "mailcheck.h" + +#include "builtins/getopt.h" +#include "builtins/common.h" #if defined (READLINE) +# include "bashline.h" # include #else # include @@ -50,50 +59,68 @@ extern int errno; #endif #include -#include "builtins/getopt.h" + +#if !defined (errno) +extern int errno; +#endif /* !errno */ /* The size that strings change by. */ -#define DEFAULT_ARRAY_SIZE 512 +#define DEFAULT_ARRAY_SIZE 128 + +/* Variable types. */ +#define VT_VARIABLE 0 +#define VT_POSPARMS 1 +#define VT_ARRAYVAR 2 -/* How to quote and determine the quoted state of the character C. */ +/* Flags for quoted_strchr */ +#define ST_BACKSL 0x01 +#define ST_CTLESC 0x02 + +/* How to quote character C. */ static char *make_quoted_char (); -#define QUOTED_CHAR(c) ((c) == CTLESC) /* Process ID of the last command executed within command substitution. */ pid_t last_command_subst_pid = NO_PID; /* Extern functions and variables from different files. */ extern int last_command_exit_value, interactive, interactive_shell; -extern int subshell_environment; -extern int dollar_dollar_pid, no_brace_expansion; +extern int subshell_environment, startup_state; +extern int dollar_dollar_pid; extern int posixly_correct; extern int eof_encountered, eof_encountered_limit, ignoreeof; extern char *this_command_name; -extern jmp_buf top_level; +extern struct fd_bitmap *current_fds_to_close; #if defined (READLINE) extern int no_line_editing; extern int hostname_list_initialized; #endif -#if !defined (USE_POSIX_GLOB_LIBRARY) -extern int glob_dot_filenames, noglob_dot_filenames; -extern char *glob_error_return; -#endif +extern void getopts_reset (); + +/* Non-zero means to allow unmatched globbed filenames to expand to + a null file. */ +int allow_null_glob_expansion; + +/* Variables to keep track of which words in an expanded word list (the + output of expand_word_list_internal) are the result of globbing + expansions. GLOB_ARGV_FLAGS is used by execute_cmd.c. */ +char *glob_argv_flags; +static int glob_argv_flags_size; static WORD_LIST expand_word_error, expand_word_fatal; static char expand_param_error, expand_param_fatal; static WORD_LIST *expand_string_internal (); -static WORD_LIST *expand_word_internal (), *expand_words_internal (); +static WORD_LIST *expand_word_internal (), *expand_word_list_internal (); static WORD_LIST *expand_string_leave_quoted (); +static WORD_LIST *expand_string_for_rhs (); static WORD_LIST *word_list_split (); -static char *quote_string (); +static WORD_LIST *quote_list (), *dequote_list (); static int unquoted_substring (), unquoted_member (); -static int unquoted_glob_pattern_p (); -static void quote_list (), dequote_list (); static int do_assignment_internal (); static char *string_extract_verbatim (), *string_extract (); static char *string_extract_double_quoted (), *string_extract_single_quoted (); +static int skip_single_quoted (), skip_double_quoted (); static char *extract_delimited_string (); static char *extract_dollar_brace_string (); @@ -110,14 +137,83 @@ substring (string, start, end) char *string; int start, end; { - register int len = end - start; - register char *result = xmalloc (len + 1); + register int len; + register char *result; + len = end - start; + result = xmalloc (len + 1); strncpy (result, string + start, len); result[len] = '\0'; return (result); } +static char * +quoted_substring (string, start, end) + char *string; + int start, end; +{ + register int len, l; + register char *result, *s, *r; + + len = end - start; + + /* Move to string[start], skipping quoted characters. */ + for (s = string, l = 0; *s && l < start; ) + { + if (*s == CTLESC) + { + s++; + continue; + } + l++; + if (*s == 0) + break; + } + + r = result = xmalloc (2*len + 1); /* save room for quotes */ + + /* Copy LEN characters, including quote characters. */ + s = string + l; + for (l = 0; l < len; s++) + { + if (*s == CTLESC) + *r++ = *s++; + *r++ = *s; + l++; + if (*s == 0) + break; + } + *r = '\0'; + return result; +} + +/* Find the first occurrence of character C in string S, obeying shell + quoting rules. If (FLAGS & ST_BACKSL) is non-zero, backslash-escaped + characters are skipped. If (FLAGS & ST_CTLESC) is non-zero, characters + escaped with CTLESC are skipped. */ +static inline char * +quoted_strchr (s, c, flags) + char *s; + int c, flags; +{ + register char *p; + + for (p = s; *p; p++) + { + if (((flags & ST_BACKSL) && *p == '\\') + || ((flags & ST_CTLESC) && *p == CTLESC)) + { + p++; + if (*p == '\0') + return ((char *)NULL); + continue; + } + else if (*p == c) + return p; + } + return ((char *)NULL); +} + /* Conventions: A string with s[0] == CTLNUL && s[1] == 0 is a quoted null string. @@ -134,12 +230,26 @@ remove_quoted_escapes (string) char *string; { register char *s; + int docopy; + char *t, *t1; + + if (string == NULL) + return (string); - for (s = string; s && *s; s++) + t1 = t = xmalloc (strlen (string) + 1); + for (docopy = 0, s = string; *s; s++, t1++) { if (*s == CTLESC && (s[1] == CTLESC || s[1] == CTLNUL)) - strcpy (s, s + 1); /* XXX - should be memmove */ + { + s++; + docopy = 1; + } + *t1 = *s; } + *t1 = '\0'; + if (docopy) + strcpy (string, t); + free (t); return (string); } @@ -154,7 +264,7 @@ quote_escapes (string) char *result; result = xmalloc ((strlen (string) * 2) + 1); - for (s = string, t = result; s && *s; ) + for (s = string, t = result; *s; ) { if (*s == CTLESC || *s == CTLNUL) *t++ = CTLESC; @@ -162,545 +272,681 @@ quote_escapes (string) } *t = '\0'; return (result); -} +} -/* Just like string_extract, but doesn't hack backslashes or any of - that other stuff. Obeys quoting. Used to do splitting on $IFS. */ static char * -string_extract_verbatim (string, sindex, charlist) - char *string, *charlist; - int *sindex; +dequote_escapes (string) + char *string; { - register int i = *sindex; - int c; - char *temp; - - if (charlist[0] == '\'' && !charlist[1]) - { - temp = string_extract_single_quoted (string, sindex); - i = *sindex - 1; - *sindex = i; - return (temp); - } + register char *s, *t; + char *result; - for (i = *sindex; (c = string[i]); i++) + result = xmalloc (strlen (string) + 1); + for (s = string, t = result; *s; ) { - if (c == CTLESC) + if (*s == CTLESC && (s[1] == CTLESC || s[1] == CTLNUL)) { - i++; - continue; + s++; + if (*s == '\0') + break; } - - if (MEMBER (c, charlist)) - break; + *t++ = *s++; } - - temp = xmalloc (1 + (i - *sindex)); - strncpy (temp, string + (*sindex), i - (*sindex)); - temp[i - (*sindex)] = '\0'; - *sindex = i; - - return (temp); + *t = '\0'; + return result; } /* Extract a substring from STRING, starting at SINDEX and ending with one of the characters in CHARLIST. Don't make the ending character part of the string. Leave SINDEX pointing at the ending character. - Understand about backslashes in the string. */ + Understand about backslashes in the string. If VARNAME is non-zero, + and array variables have been compiled into the shell, everything + between a `[' and a corresponding `]' is skipped over. */ static char * -string_extract (string, sindex, charlist) +string_extract (string, sindex, charlist, varname) char *string, *charlist; - int *sindex; + int *sindex, varname; { - register int c, i = *sindex; + register int c, i; char *temp; - while (c = string[i]) + for (i = *sindex; c = string[i]; i++) { if (c == '\\') if (string[i + 1]) i++; else break; - else - if (MEMBER (c, charlist)) +#if defined (ARRAY_VARS) + else if (varname && c == '[') + { + int ni; + /* If this is an array subscript, skip over it and continue. */ + ni = skipsubscript (string, i); + if (string[ni] == ']') + i = ni; + } +#endif + else if (MEMBER (c, charlist)) break; - i++; } - temp = xmalloc (1 + (i - *sindex)); - strncpy (temp, string + (*sindex), i - (*sindex)); - temp[i - (*sindex)] = '\0'; + c = i - *sindex; + temp = xmalloc (1 + c); + strncpy (temp, string + *sindex, c); + temp[c] = '\0'; *sindex = i; return (temp); } -/* Remove backslashes which are quoting backquotes from STRING. Modifies - STRING, and returns a pointer to it. */ -char * -de_backslash (string) - char *string; -{ - register int i, l = strlen (string); - - for (i = 0; i < l; i++) - if (string[i] == '\\' && (string[i + 1] == '`' || string[i + 1] == '\\' || - string[i + 1] == '$')) - strcpy (string + i, string + i + 1); /* XXX - should be memmove */ - return (string); -} - -#if 0 -/* Replace instances of \! in a string with !. */ -void -unquote_bang (string) +/* Extract the contents of STRING as if it is enclosed in double quotes. + SINDEX, when passed in, is the offset of the character immediately + following the opening double quote; on exit, SINDEX is left pointing after + the closing double quote. If STRIPDQ is non-zero, unquoted double + quotes are stripped and the string is terminated by a null byte. + Backslashes between the embedded double quotes are processed. If STRIPDQ + is zero, an unquoted `"' terminates the string. */ +static inline char * +string_extract_double_quoted (string, sindex, stripdq) char *string; + int *sindex, stripdq; { - register int i, j; - register char *temp; + int c, j, i, t; + char *temp, *ret; /* The new string we return. */ + int pass_next, backquote, si; /* State variables for the machine. */ + int dquote; - temp = xmalloc (1 + strlen (string)); + pass_next = backquote = dquote = 0; + temp = xmalloc (1 + strlen (string) - *sindex); - for (i = 0, j = 0; (temp[j] = string[i]); i++, j++) + for (j = 0, i = *sindex; c = string[i]; i++) { - if (string[i] == '\\' && string[i + 1] == '!') + /* Process a character that was quoted by a backslash. */ + if (pass_next) { - temp[j] = '!'; - i++; - } - } - strcpy (string, temp); - free (temp); -} -#endif - -/* Extract the $( construct in STRING, and return a new string. - Start extracting at (SINDEX) as if we had just seen "$(". - Make (SINDEX) get the position just after the matching ")". */ -char * -extract_command_subst (string, sindex) - char *string; - int *sindex; -{ - return (extract_delimited_string (string, sindex, "$(", "(", ")")); -} - -/* Extract the $[ construct in STRING, and return a new string. - Start extracting at (SINDEX) as if we had just seen "$[". - Make (SINDEX) get the position just after the matching "]". */ -char * -extract_arithmetic_subst (string, sindex) - char *string; - int *sindex; -{ - return (extract_delimited_string (string, sindex, "$[", "[", "]")); -} - -#if defined (PROCESS_SUBSTITUTION) -/* Extract the <( or >( construct in STRING, and return a new string. - Start extracting at (SINDEX) as if we had just seen "<(". - Make (SINDEX) get the position just after the matching ")". */ -char * -extract_process_subst (string, starter, sindex) - char *string; - char *starter; - int *sindex; -{ - return (extract_delimited_string (string, sindex, starter, "(", ")")); -} -#endif /* PROCESS_SUBSTITUTION */ - -/* Extract and create a new string from the contents of STRING, a - character string delimited with OPENER and CLOSER. SINDEX is - the address of an int describing the current offset in STRING; - it should point to just after the first OPENER found. On exit, - SINDEX gets the position just after the matching CLOSER. If - OPENER is more than a single character, ALT_OPENER, if non-null, - contains a character string that can also match CLOSER and thus - needs to be skipped. */ -static char * -extract_delimited_string (string, sindex, opener, alt_opener, closer) - char *string; - int *sindex; - char *opener, *alt_opener, *closer; -{ - register int i, c, l; - int pass_character, nesting_level; - int delimiter, delimited_nesting_level; - int len_closer, len_opener, len_alt_opener; - char *result; - - len_opener = STRLEN (opener); - len_alt_opener = STRLEN (alt_opener); - len_closer = STRLEN (closer); + /* Posix.2 sez: - pass_character = delimiter = delimited_nesting_level = 0; + ``The backslash shall retain its special meaning as an escape + character only when followed by one of the characters: + $ ` " \ ''. - nesting_level = 1; + If STRIPDQ is zero, we handle the double quotes here and let + expand_word_internal handle the rest. If STRIPDQ is non-zero, + we have already been through one round of backslash stripping, + and want to strip these backslashes only if DQUOTE is non-zero, + indicating that we are inside an embedded double-quoted string. */ + + /* If we are in an embedded quoted string, then don't strip + backslashes before characters for which the backslash + retains its special meaning, but remove backslashes in + front of other characters. If we are not in an + embedded quoted string, don't strip backslashes at all. + This mess is necessary because the string was already + surrounded by double quotes (and sh has some really weird + quoting rules). + The returned string will be run through expansion as if + it were double-quoted. */ + if ((stripdq == 0 && c != '"') || + (stripdq && ((dquote && strchr (slashify_in_quotes, c)) || dquote == 0))) + temp[j++] = '\\'; + temp[j++] = c; + pass_next = 0; + continue; + } - for (i = *sindex; c = string[i]; i++) - { - if (pass_character) + /* A backslash protects the next character. The code just above + handles preserving the backslash in front of any character but + a double quote. */ + if (c == '\\') { - pass_character = 0; + pass_next++; continue; } - if (c == CTLESC) + /* Inside backquotes, ``the portion of the quoted string from the + initial backquote and the characters up to the next backquote + that is not preceded by a backslash, having escape characters + removed, defines that command''. */ + if (backquote) { - pass_character++; + if (c == '`') + backquote = 0; + temp[j++] = c; continue; } - if (c == '\\') + if (c == '`') { - if ((delimiter == '"') && - (member (string[i + 1], slashify_in_quotes))) - { - pass_character++; - continue; - } + temp[j++] = c; + backquote++; + continue; } - if (!delimiter || delimiter == '"') + /* Pass everything between `$(' and the matching `)' or a quoted + ${ ... } pair through according to the Posix.2 specification. */ + if (c == '$' && ((string[i + 1] == '(') || (string[i + 1] == '{'))) { - if (STREQN (string + i, opener, len_opener)) - { - if (!delimiter) - nesting_level++; - else - delimited_nesting_level++; - - i += len_opener - 1; - continue; - } - - if (len_alt_opener && STREQN (string + i, alt_opener, len_alt_opener)) - { - if (!delimiter) - nesting_level++; - else - delimited_nesting_level++; - - i += len_alt_opener - 1; - continue; - } + si = i + 2; + if (string[i + 1] == '(') + ret = extract_delimited_string (string, &si, "$(", "(", ")"); + else + ret = extract_dollar_brace_string (string, &si, 1); - if (STREQN (string + i, closer, len_closer)) - { - i += len_closer - 1; + temp[j++] = '$'; + temp[j++] = string[i + 1]; - if (delimiter && delimited_nesting_level) - delimited_nesting_level--; + for (t = 0; ret[t]; t++, j++) + temp[j] = ret[t]; + temp[j++] = string[si]; - if (!delimiter) - { - nesting_level--; - if (nesting_level == 0) - break; - } - } + i = si; + free (ret); + continue; } - if (delimiter) + /* Add any character but a double quote to the quoted string we're + accumulating. */ + if (c != '"') { - if (c == delimiter || delimiter == '\\') - delimiter = 0; + temp[j++] = c; continue; } - else + + /* c == '"' */ + if (stripdq) { - if (c == '"' || c == '\'' || c == '\\') - delimiter = c; + dquote ^= 1; + continue; } + + break; } + temp[j] = '\0'; - l = i - *sindex; - result = xmalloc (1 + l); - strncpy (result, string + *sindex, l); - result[l] = '\0'; + /* Point to after the closing quote. */ + if (c) + i++; *sindex = i; - if (!c && (delimiter || nesting_level)) + return (temp); +} + +/* This should really be another option to string_extract_double_quoted. */ +static inline int +skip_double_quoted (string, sind) + char *string; + int sind; +{ + int c, j, i; + char *ret; + int pass_next, backquote, si; + + pass_next = backquote = 0; + + for (j = 0, i = sind; c = string[i]; i++) { - report_error ("bad substitution: no `%s' in %s", closer, string); - free (result); - longjmp (top_level, DISCARD); + if (pass_next) + { + pass_next = 0; + continue; + } + else if (c == '\\') + { + pass_next++; + continue; + } + else if (backquote) + { + if (c == '`') + backquote = 0; + continue; + } + else if (c == '`') + { + backquote++; + continue; + } + else if (c == '$' && ((string[i + 1] == '(') || (string[i + 1] == '{'))) + { + si = i + 2; + if (string[i + 1] == '(') + ret = extract_delimited_string (string, &si, "$(", "(", ")"); + else + ret = extract_dollar_brace_string (string, &si, 0); + + i = si; + free (ret); + continue; + } + else if (c != '"') + continue; + else + break; } - return (result); + + if (c) + i++; + + return (i); } -/* Extract a parameter expansion expression within ${ and } from STRING. - Obey the Posix.2 rules for finding the ending `}': count braces while - skipping over enclosed quoted strings and command substitutions. - SINDEX is the address of an int describing the current offset in STRING; - it should point to just after the first `{' found. On exit, SINDEX - gets the position just after the matching `}'. */ -/* XXX -- this is very similar to extract_delimited_string -- XXX */ +/* Extract the contents of STRING as if it is enclosed in single quotes. + SINDEX, when passed in, is the offset of the character immediately + following the opening single quote; on exit, SINDEX is left pointing after + the closing single quote. */ +static inline char * +string_extract_single_quoted (string, sindex) + char *string; + int *sindex; +{ + register int i, j; + char *t; + + for (i = *sindex; string[i] && string[i] != '\''; i++) + ; + + j = i - *sindex; + t = xmalloc (1 + j); + strncpy (t, string + *sindex, j); + t[j] = '\0'; + + if (string[i]) + i++; + *sindex = i; + + return (t); +} + +static inline int +skip_single_quoted (string, sind) + char *string; + int sind; +{ + register int i; + + for (i = sind; string[i] && string[i] != '\''; i++) + ; + if (string[i]) + i++; + return i; +} + +/* Just like string_extract, but doesn't hack backslashes or any of + that other stuff. Obeys quoting. Used to do splitting on $IFS. */ static char * -extract_dollar_brace_string (string, sindex) +string_extract_verbatim (string, sindex, charlist) + char *string, *charlist; + int *sindex; +{ + register int i = *sindex; + int c; + char *temp; + + if (charlist[0] == '\'' && charlist[1] == '\0') + { + temp = string_extract_single_quoted (string, sindex); + --*sindex; /* leave *sindex at separator character */ + return temp; + } + + for (i = *sindex; c = string[i]; i++) + { + if (c == CTLESC) + { + i++; + continue; + } + + if (MEMBER (c, charlist)) + break; + } + + c = i - *sindex; + temp = xmalloc (1 + c); + strncpy (temp, string + *sindex, c); + temp[c] = '\0'; + *sindex = i; + + return (temp); +} + +/* Extract the $( construct in STRING, and return a new string. + Start extracting at (SINDEX) as if we had just seen "$(". + Make (SINDEX) get the position of the matching ")". */ +char * +extract_command_subst (string, sindex) char *string; int *sindex; { - register int i, c, l; + return (extract_delimited_string (string, sindex, "$(", "(", ")")); +} + +/* Extract the $[ construct in STRING, and return a new string. + Start extracting at (SINDEX) as if we had just seen "$[". + Make (SINDEX) get the position of the matching "]". */ +char * +extract_arithmetic_subst (string, sindex) + char *string; + int *sindex; +{ + return (extract_delimited_string (string, sindex, "$[", "[", "]")); +} + +#if defined (PROCESS_SUBSTITUTION) +/* Extract the <( or >( construct in STRING, and return a new string. + Start extracting at (SINDEX) as if we had just seen "<(". + Make (SINDEX) get the position of the matching ")". */ +char * +extract_process_subst (string, starter, sindex) + char *string; + char *starter; + int *sindex; +{ + return (extract_delimited_string (string, sindex, starter, "(", ")")); +} +#endif /* PROCESS_SUBSTITUTION */ + +#if defined (ARRAY_VARS) +char * +extract_array_assignment_list (string, sindex) + char *string; + int *sindex; +{ + return (extract_delimited_string (string, sindex, "(", (char *)NULL, ")")); +} +#endif + +/* Extract and create a new string from the contents of STRING, a + character string delimited with OPENER and CLOSER. SINDEX is + the address of an int describing the current offset in STRING; + it should point to just after the first OPENER found. On exit, + SINDEX gets the position of the last character of the matching CLOSER. + If OPENER is more than a single character, ALT_OPENER, if non-null, + contains a character string that can also match CLOSER and thus + needs to be skipped. */ +static char * +extract_delimited_string (string, sindex, opener, alt_opener, closer) + char *string; + int *sindex; + char *opener, *alt_opener, *closer; +{ + int i, c, si; + char *t, *result; int pass_character, nesting_level; - int delimiter, delimited_nesting_level; - char *result; + int len_closer, len_opener, len_alt_opener; + + len_opener = STRLEN (opener); + len_alt_opener = STRLEN (alt_opener); + len_closer = STRLEN (closer); - pass_character = delimiter = delimited_nesting_level = 0; + pass_character = 0; nesting_level = 1; + i = *sindex; - for (i = *sindex; c = string[i]; i++) + while (nesting_level) { - if (pass_character) + c = string[i]; + + if (c == 0) + break; + + if (pass_character) /* previous char was backslash */ { pass_character = 0; + i++; continue; } if (c == CTLESC) { pass_character++; + i++; continue; } - /* Backslashes quote the next character. */ +#if 0 + if (c == '\\' && delimiter == '"' && + (member (string[i], slashify_in_quotes))) +#else if (c == '\\') +#endif { - if ((delimiter == '"') && - (member (string[i + 1], slashify_in_quotes))) - { - pass_character++; - continue; - } + pass_character++; + i++; + continue; } - if (!delimiter || delimiter == '"') + /* Process a nested OPENER. */ + if (STREQN (string + i, opener, len_opener)) { - if (string[i] == '$' && string[i+1] == '{') - { - if (!delimiter) - nesting_level++; - else - delimited_nesting_level++; - - i++; - continue; - } - - /* Pass the contents of old-style command substitutions through - verbatim. */ - if (string[i] == '`') - { - int si; - char *t; - - si = i + 1; - t = string_extract (string, &si, "`"); - i = si; - free (t); - continue; - } - - /* Pass the contents of new-style command substitutions through - verbatim. */ - if (string[i] == '$' && string[i+1] == '(') - { - int si; - char *t; - - si = i + 2; - t = extract_delimited_string (string, &si, "$(", "(", ")"); - i = si; - free (t); - continue; - } - - if (string[i] == '{') - { - if (!delimiter) - nesting_level++; - else - delimited_nesting_level++; - - continue; - } - - if (string[i] == '}') - { - if (delimiter && delimited_nesting_level) - delimited_nesting_level--; - - if (!delimiter) - { - nesting_level--; - if (nesting_level == 0) - break; - } - } + si = i + len_opener; + t = extract_delimited_string (string, &si, opener, alt_opener, closer); + i = si + 1; + FREE (t); + continue; } - if (delimiter) + /* Process a nested ALT_OPENER */ + if (len_alt_opener && STREQN (string + i, alt_opener, len_alt_opener)) { - if (c == delimiter || delimiter == '\\') - delimiter = 0; + si = i + len_alt_opener; + t = extract_delimited_string (string, &si, alt_opener, alt_opener, closer); + i = si + 1; + FREE (t); continue; } - else + + /* If the current substring terminates the delimited string, decrement + the nesting level. */ + if (STREQN (string + i, closer, len_closer)) { - if (c == '"' || c == '\'' || c == '\\') - delimiter = c; + i += len_closer - 1; /* move to last char of the closer */ + nesting_level--; + if (nesting_level == 0) + break; } + + /* Pass old-style command substitution through verbatim. */ + if (c == '`') + { + si = i + 1; + t = string_extract (string, &si, "`", 0); + i = si + 1; + FREE (t); + continue; + } + + /* Pass single-quoted strings through verbatim. */ + if (c == '\'') + { + si = i + 1; + i = skip_single_quoted (string, si); + continue; + } + + /* Pass embedded double-quoted strings through verbatim as well. */ + if (c == '"') + { + si = i + 1; + i = skip_double_quoted (string, si); + continue; + } + + i++; /* move past this character, which was not special. */ } - l = i - *sindex; - result = xmalloc (1 + l); - strncpy (result, string + *sindex, l); - result[l] = '\0'; + si = i - *sindex - len_closer + 1; + result = xmalloc (1 + si); + strncpy (result, string + *sindex, si); + result[si] = '\0'; *sindex = i; - if (!c && (delimiter || nesting_level)) + if (c == 0 && nesting_level) { - report_error ("bad substitution: no ending `}' in %s", string); + report_error ("bad substitution: no `%s' in %s", closer, string); free (result); - longjmp (top_level, DISCARD); + jump_to_top_level (DISCARD); } + return (result); } -/* Extract the contents of STRING as if it is enclosed in double quotes. - SINDEX, when passed in, is the offset of the character immediately - following the opening double quote; on exit, SINDEX is left pointing after - the closing double quote. */ +/* Extract a parameter expansion expression within ${ and } from STRING. + Obey the Posix.2 rules for finding the ending `}': count braces while + skipping over enclosed quoted strings and command substitutions. + SINDEX is the address of an int describing the current offset in STRING; + it should point to just after the first `{' found. On exit, SINDEX + gets the position of the matching `}'. QUOTED is non-zero if this + occurs inside double quotes. */ +/* XXX -- this is very similar to extract_delimited_string -- XXX */ static char * -string_extract_double_quoted (string, sindex) +extract_dollar_brace_string (string, sindex, quoted) char *string; - int *sindex; + int *sindex, quoted; { - register int c, j, i; - char *temp; /* The new string we return. */ - int pass_next, backquote; /* State variables for the machine. */ + register int i, c, l; + int pass_character, nesting_level, si; + char *result, *t; - pass_next = backquote = 0; - temp = xmalloc (1 + strlen (string) - *sindex); + pass_character = 0; - for (j = 0, i = *sindex; c = string[i]; i++) + nesting_level = 1; + + for (i = *sindex; (c = string[i]); i++) { - /* Process a character that was quoted by a backslash. */ - if (pass_next) + if (pass_character) { - /* Posix.2 sez: - - ``The backslash shall retain its special meaning as an escape - character only when followed by one of the characters: - $ ` " \ ''. + pass_character = 0; + continue; + } - We handle the double quotes here. expand_word_internal handles - the rest. */ - if (c != '"') - temp[j++] = '\\'; - temp[j++] = c; - pass_next = 0; + if (c == CTLESC) + { + pass_character++; continue; } - /* A backslash protects the next character. The code just above - handles preserving the backslash in front of any character but - a double quote. */ + /* Backslashes quote the next character. */ if (c == '\\') { - pass_next++; + pass_character++; continue; } - /* Inside backquotes, ``the portion of the quoted string from the - initial backquote and the characters up to the next backquote - that is not preceded by a backslash, having escape characters - removed, defines that command''. */ - if (backquote) + if (string[i] == '$' && string[i+1] == '{') { - if (c == '`') - backquote = 0; - temp[j++] = c; + nesting_level++; + i++; continue; } - if (c == '`') + if (c == '}') { - temp[j++] = c; - backquote++; + nesting_level--; + if (nesting_level == 0) + break; continue; } - /* Pass everything between `$(' and the matching `)' or a quoted - ${ ... } pair through according to the Posix.2 specification. */ - if (c == '$' && ((string[i + 1] == '(') || (string[i + 1] == '{'))) + /* Pass the contents of old-style command substitutions through + verbatim. */ + if (c == '`') { - register int t; - int si; - char *ret; + si = i + 1; + t = string_extract (string, &si, "`", 0); + i = si; + free (t); + continue; + } + /* Pass the contents of new-style command substitutions through + verbatim. */ + if (string[i] == '$' && string[i+1] == '(') + { si = i + 2; - if (string[i + 1] == '(') - ret = extract_delimited_string (string, &si, "$(", "(", ")"); - else - ret = extract_dollar_brace_string (string, &si); - - temp[j++] = '$'; - temp[j++] = string[i + 1]; - - for (t = 0; ret[t]; t++) - temp[j++] = ret[t]; - + t = extract_delimited_string (string, &si, "$(", "(", ")"); i = si; - temp[j++] = string[i]; - free (ret); + free (t); continue; } - /* An unescaped double quote serves to terminate the string. */ - if (c == '"') - break; + /* Pass the contents of single-quoted strings through verbatim. */ + if (c == '\'') + { + si = i + 1; + i = skip_single_quoted (string, si); + /* skip_single_quoted leaves index one past close quote */ + i--; + continue; + } - /* Add the character to the quoted string we're accumulating. */ - temp[j++] = c; + /* Pass embedded double-quoted strings through verbatim as well. */ + if (c == '"') + { + si = i + 1; + /* skip_double_quoted leaves index one past close quote */ + i = skip_double_quoted (string, si); + i--; + continue; + } } - temp[j] = '\0'; - /* Point to after the closing quote. */ - if (c) - i++; + l = i - *sindex; + result = xmalloc (1 + l); + strncpy (result, string + *sindex, l); + result[l] = '\0'; *sindex = i; - return (temp); + if (c == 0 && nesting_level) + { + report_error ("bad substitution: no ending `}' in %s", string); + free (result); + jump_to_top_level (DISCARD); + } + + return (result); } -/* Extract the contents of STRING as if it is enclosed in single quotes. - SINDEX, when passed in, is the offset of the character immediately - following the opening single quote; on exit, SINDEX is left pointing after - the closing single quote. */ -static char * -string_extract_single_quoted (string, sindex) +/* Remove backslashes which are quoting backquotes from STRING. Modifies + STRING, and returns a pointer to it. */ +char * +de_backslash (string) char *string; - int *sindex; -{ - register int i = *sindex; - char *temp; +{ + register int i, l; - while (string[i] && string[i] != '\'') - i++; + for (i = 0, l = strlen (string); i < l; i++) + if (string[i] == '\\' && (string[i + 1] == '`' || string[i + 1] == '\\' || + string[i + 1] == '$')) + strcpy (string + i, string + i + 1); /* XXX - should be memmove */ + return (string); +} - temp = xmalloc (1 + i - *sindex); - strncpy (temp, string + *sindex, i - *sindex); - temp[i - *sindex] = '\0'; +#if 0 +/* Replace instances of \! in a string with !. */ +void +unquote_bang (string) + char *string; +{ + register int i, j; + register char *temp; - if (string[i]) - i++; - *sindex = i; + temp = xmalloc (1 + strlen (string)); - return (temp); + for (i = 0, j = 0; (temp[j] = string[i]); i++, j++) + { + if (string[i] == '\\' && string[i + 1] == '!') + { + temp[j] = '!'; + i++; + } + } + strcpy (string, temp); + free (temp); } +#endif +#if defined (READLINE) /* Return 1 if the portion of STRING ending at EINDEX is quoted (there is an unclosed quoted string), or if the character at EINDEX is quoted by a backslash. */ @@ -710,7 +956,6 @@ char_is_quoted (string, eindex) int eindex; { int i, pass_next, quoted; - char *temp; for (i = pass_next = quoted = 0; i <= eindex; i++) { @@ -721,42 +966,30 @@ char_is_quoted (string, eindex) return 1; continue; } - else if (string[i] == '\'') - { - i++; - temp = string_extract_single_quoted (string, &i); - free (temp); - if (i > eindex) - return 1; - i--; - } - else if (string[i] == '"') - { - i++; - temp = string_extract_double_quoted (string, &i); - free (temp); - if (i > eindex) - return 1; - i--; - } + else if (string[i] == '\'' || string[i] == '"') + { + i = (string[i] == '\'') ? skip_single_quoted (string, ++i) + : skip_double_quoted (string, ++i); + if (i > eindex) + return 1; + i--; /* the skip functions increment past the closing quote. */ + } else if (string[i] == '\\') - { - pass_next = 1; - continue; - } + { + pass_next = 1; + continue; + } } return (0); } -#if defined (READLINE) int unclosed_pair (string, eindex, openstr) char *string; int eindex; char *openstr; { - int i, pass_next, openc, c, olen; - char *temp, *s; + int i, pass_next, openc, olen; olen = strlen (openstr); for (i = pass_next = openc = 0; i <= eindex; i++) @@ -773,19 +1006,10 @@ unclosed_pair (string, eindex, openstr) openc = 1 - openc; i += olen - 1; } - else if (string[i] == '\'') - { - i++; - temp = string_extract_single_quoted (string, &i); - free (temp); - if (i > eindex) - return 0; - } - else if (string[i] == '"') + else if (string[i] == '\'' || string[i] == '"') { - i++; - temp = string_extract_double_quoted (string, &i); - free (temp); + i = (string[i] == '\'') ? skip_single_quoted (string, i) + : skip_double_quoted (string, i); if (i > eindex) return 0; } @@ -799,21 +1023,25 @@ unclosed_pair (string, eindex, openstr) } #endif /* READLINE */ +#if 0 +/* UNUSED */ /* Extract the name of the variable to bind to from the assignment string. */ char * assignment_name (string) char *string; { - int offset = assignment (string); + int offset; char *temp; - if (!offset) + offset = assignment (string); + if (offset == 0) return (char *)NULL; temp = xmalloc (offset + 1); strncpy (temp, string, offset); temp[offset] = '\0'; return (temp); } +#endif /* Return a single string of all the words in LIST. SEP is the separator to put between individual elements of LIST in the output string. */ @@ -826,7 +1054,7 @@ string_list_internal (list, sep) char *result, *r; int word_len, sep_len, result_size; - if (!list) + if (list == 0) return ((char *)NULL); /* This is nearly always called with either sep[0] == 0 or sep[1] == 0. */ @@ -846,8 +1074,13 @@ string_list_internal (list, sep) { if (t != list && sep_len) { - FASTCOPY (sep, r, sep_len); - r += sep_len; + if (sep_len > 1) + { + FASTCOPY (sep, r, sep_len); + r += sep_len; + } + else + *r++ = sep[0]; } word_len = strlen (t->word->word); @@ -855,7 +1088,7 @@ string_list_internal (list, sep) r += word_len; } - *r = '\0'; + *r = '\0'; return (result); } @@ -877,12 +1110,12 @@ char * string_list_dollar_star (list) WORD_LIST *list; { - char *ifs = get_string_value ("IFS"); - char sep[2]; + char *ifs, sep[2]; - if (!ifs) + ifs = get_string_value ("IFS"); + if (ifs == 0) sep[0] = ' '; - else if (!*ifs) + else if (*ifs == '\0') sep[0] = '\0'; else sep[0] = *ifs; @@ -917,13 +1150,11 @@ string_list_dollar_star (list) /* BEWARE! list_string strips null arguments. Don't call it twice and expect to have "" preserved! */ -/* Is the first character of STRING a quoted NULL character? */ -#define QUOTED_NULL(string) ((string)[0] == CTLNUL && (string)[1] == '\0') - /* Perform quoted null character removal on STRING. We don't allow any quoted null characters in the middle or at the ends of strings because - of how expand_word_internal works. remove_quoted_nulls () simply - turns STRING into an empty string iff it only consists of a quoted null. */ + of how expand_word_internal works. remove_quoted_nulls () turns + STRING into an empty string iff it only consists of a quoted null, + and removes all unquoted CTLNUL characters. */ /* #define remove_quoted_nulls(string) \ do { if (QUOTED_NULL (string)) string[0] ='\0'; } while (0) @@ -940,14 +1171,14 @@ remove_quoted_nulls (string) { if (*s == CTLESC) { - *p++ = *s++; /* CTLESC */ + *p++ = *s++; /* CTLESC */ if (*s == 0) break; - *p++ = *s; /* quoted char */ + *p++ = *s; /* quoted char */ continue; } if (*s == CTLNUL) - continue; + continue; *p++ = *s; } *p = '\0'; @@ -963,18 +1194,12 @@ word_list_remove_quoted_nulls (list) { register WORD_LIST *t; - t = list; - - while (t) - { - remove_quoted_nulls (t->word->word); - t = t->next; - } + for (t = list; t; t = t->next) + remove_quoted_nulls (t->word->word); } /* This performs word splitting and quoted null character removal on STRING. */ - #define issep(c) (member ((c), separators)) WORD_LIST * @@ -982,10 +1207,10 @@ list_string (string, separators, quoted) register char *string, *separators; int quoted; { - WORD_LIST *result = (WORD_LIST *)NULL; - char *current_word = (char *)NULL, *s; - int sindex = 0; - int sh_style_split; + WORD_LIST *result; + WORD_DESC *t; + char *current_word, *s; + int sindex, sh_style_split; if (!string || !*string) return ((WORD_LIST *)NULL); @@ -1011,11 +1236,10 @@ list_string (string, separators, quoted) extract a word, stopping at a separator skip sequences of spc, tab, or nl as long as they are separators This obeys the field splitting rules in Posix.2. */ - - while (string[sindex]) + for (result = (WORD_LIST *)NULL, sindex = 0; string[sindex]; ) { current_word = string_extract_verbatim (string, &sindex, separators); - if (!current_word) + if (current_word == 0) break; /* If we have a quoted empty string, add a quoted null argument. We @@ -1024,29 +1248,31 @@ list_string (string, separators, quoted) below. */ if (QUOTED_NULL (current_word)) { - WORD_DESC *t = make_word (" "); - t->quoted++; + t = make_bare_word (""); + t->flags |= W_QUOTED; free (t->word); t->word = make_quoted_char ('\0'); result = make_word_list (t, result); } - else if (strlen (current_word)) + else if (current_word[0] != '\0') { /* If we have something, then add it regardless. However, perform quoted null character removal on the current word. */ remove_quoted_nulls (current_word); result = make_word_list (make_word (current_word), result); - if (quoted) - result->word->quoted = 1; + if (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) + result->word->flags |= W_QUOTED; } /* If we're not doing sequences of separators in the traditional Bourne shell style, then add a quoted null argument. */ - else if (!sh_style_split && !spctabnl (string[sindex])) { - result = make_word_list (make_word (""), result); - result->word->quoted = 1; + t = make_bare_word (""); + t->flags |= W_QUOTED; + free (t->word); + t->word = make_quoted_char ('\0'); + result = make_word_list (t, result); } free (current_word); @@ -1059,7 +1285,6 @@ list_string (string, separators, quoted) in the list of separators. */ while (string[sindex] && spctabnl (string[sindex]) && issep (string[sindex])) sindex++; - } return (REVERSE_LIST (result, WORD_LIST *)); } @@ -1079,7 +1304,7 @@ get_word_from_string (stringp, separators, endptr) if (!stringp || !*stringp || !**stringp) return ((char *)NULL); - + s = *stringp; sh_style_split = @@ -1105,7 +1330,7 @@ get_word_from_string (stringp, separators, endptr) Now extract a word, stopping at a separator, save a pointer to the first character after the word, then skip sequences of spc, tab, or nl as long as they are separators. - + This obeys the field splitting rules in Posix.2. */ sindex = 0; current_word = string_extract_verbatim (s, &sindex, separators); @@ -1139,7 +1364,7 @@ strip_trailing_ifs_whitespace (string, separators, saw_escape) int saw_escape; { char *s; - + s = string + STRLEN (string) - 1; while (s > string && ((spctabnl (*s) && issep (*s)) || (saw_escape && *s == CTLESC && spctabnl (s[1])))) @@ -1148,6 +1373,61 @@ strip_trailing_ifs_whitespace (string, separators, saw_escape) return string; } +#if 0 +#if defined (ARRAY_VARS) +WORD_LIST * +list_string_with_quotes (string) + char *string; +{ + WORD_LIST *list; + char *token, *s; + int c, i, tokstart, len; + + for (s = string; s && *s && spctabnl (*s); s++) + ; + if (s == 0 || *s == 0) + return ((WORD_LIST *)NULL); + + tokstart = i = 0; + list = (WORD_LIST *)NULL; + while (1) + { + c = s[i]; + if (c == '\\') + { + i++; + if (s[i]) + i++; + } + else if (c == '\'') + i = skip_single_quoted (s, ++i); + else if (c == '"') + i = skip_double_quoted (s, ++i); + else if (c == 0 || spctabnl (c)) + { + /* We have found the end of a token. Make a word out of it and + add it to the word list. */ + len = i - tokstart; + token = xmalloc (len + 1); + strncpy (token, s + tokstart, len); + token[len] = '\0'; + list = make_word_list (make_word (token), list); + free (token); + while (spctabnl (s[i])) + i++; + if (s[i]) + tokstart = i; + else + break; + } + else + i++; /* normal character */ + } + return (REVERSE_LIST (list, WORD_LIST *)); +} +#endif /* ARRAY_VARS */ +#endif /* 0 */ + #if defined (PROCESS_SUBSTITUTION) #define EXP_CHAR(s) (s == '$' || s == '`' || s == '<' || s == '>' || s == CTLESC) #else @@ -1166,7 +1446,7 @@ maybe_expand_string (string, quoted, func) WORD_LIST *list; int i, saw_quote; char *ret; - + for (i = saw_quote = 0; string[i]; i++) { if (EXP_CHAR (string[i])) @@ -1176,7 +1456,7 @@ maybe_expand_string (string, quoted, func) } if (string[i]) - { + { list = (*func) (string, quoted); if (list) { @@ -1186,13 +1466,46 @@ maybe_expand_string (string, quoted, func) else ret = (char *)NULL; } - else if (saw_quote && !quoted) + else if (saw_quote && ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) == 0)) ret = string_quote_removal (string, quoted); else ret = savestring (string); return ret; } +#if defined (ARRAY_VARS) +SHELL_VAR * +do_array_element_assignment (name, value) + char *name, *value; +{ + char *t; + int ind, ni; + SHELL_VAR *entry; + + t = strchr (name, '['); + if (t == 0) + return ((SHELL_VAR *)NULL); + ind = t - name; + ni = skipsubscript (name, ind); + if ((ALL_ELEMENT_SUB (t[1]) && t[2] == ']') || (ni <= ind + 1)) + { + report_error ("%s: bad array subscript", name); + return ((SHELL_VAR *)NULL); + } + *t++ = '\0'; + ind = array_expand_index (t, ni - ind); + if (ind < 0) + { + t[-1] = '['; /* restore original name */ + report_error ("%s: bad array subscript", name); + return ((SHELL_VAR *)NULL); + } + entry = bind_array_variable (name, ind, value); + t[-1] = '['; /* restore original name */ + return (entry); +} +#endif /* ARRAY_VARS */ + /* Given STRING, an assignment string, get the value of the right side of the `=', and bind it to the left side. If EXPAND is true, then perform parameter expansion, command substitution, and arithmetic @@ -1203,10 +1516,17 @@ do_assignment_internal (string, expand) char *string; int expand; { - int offset = assignment (string); - char *name = savestring (string); - char *value = (char *)NULL; - SHELL_VAR *entry = (SHELL_VAR *)NULL; + int offset; + char *name, *value; + SHELL_VAR *entry; +#if defined (ARRAY_VARS) + char *t; + int ni, assign_list = 0; +#endif + + offset = assignment (string); + name = savestring (string); + value = (char *)NULL; if (name[offset] == '=') { @@ -1215,12 +1535,21 @@ do_assignment_internal (string, expand) name[offset] = 0; temp = name + offset + 1; - if (expand && temp[0]) +#if defined (ARRAY_VARS) + if (expand && temp[0] == '(' && strchr (temp, ')')) { - if (strchr (temp, '~') && unquoted_member ('~', temp)) - temp = tilde_expand (temp); - else - temp = savestring (temp); + assign_list = ni = 1; + value = extract_delimited_string (temp, &ni, "(", (char *)NULL, ")"); + } + else +#endif + + /* Perform tilde expansion. */ + if (expand && temp[0]) + { + temp = (strchr (temp, '~') && unquoted_member ('~', temp)) + ? bash_tilde_expand (temp) + : savestring (temp); value = maybe_expand_string (temp, 0, expand_string_unsplit); free (temp); @@ -1232,25 +1561,46 @@ do_assignment_internal (string, expand) if (value == 0) value = savestring (""); - entry = bind_variable (name, value); - if (echo_command_at_execute) +#if defined (ARRAY_VARS) + if (assign_list) + fprintf (stderr, "%s%s=(%s)\n", indirection_level_string (), name, value); + else +#endif fprintf (stderr, "%s%s=%s\n", indirection_level_string (), name, value); +#define ASSIGN_RETURN(r) FREE (value); free (name); return (r); + +#if defined (ARRAY_VARS) + if (t = strchr (name, '[')) + { + if (assign_list) + { + report_error ("%s: cannot assign list to array member", name); + ASSIGN_RETURN (0); + } + entry = do_array_element_assignment (name, value); + if (entry == 0) + ASSIGN_RETURN (0); + } + else if (assign_list) + entry = assign_array_from_string (name, value); + else +#endif /* ARRAY_VARS */ + entry = bind_variable (name, value); + stupidly_hack_special_variables (name); if (entry) entry->attributes &= ~att_invisible; - FREE (value); - free (name); - /* Return 1 if the assignment seems to have been performed correctly. */ - return (entry ? ((entry->attributes & att_readonly) == 0) : 0); + ASSIGN_RETURN (entry ? ((entry->attributes & att_readonly) == 0) : 0); } /* Perform the assignment statement in STRING, and expand the right side by doing command and parameter expansion. */ +int do_assignment (string) char *string; { @@ -1260,6 +1610,7 @@ do_assignment (string) /* Given STRING, an assignment string, get the value of the right side of the `=', and bind it to the left side. Do not do command and parameter substitution on the right hand side. */ +int do_assignment_no_expand (string) char *string; { @@ -1276,7 +1627,7 @@ do_assignment_no_expand (string) /* Append SOURCE to TARGET at INDEX. SIZE is the current amount of space allocated to TARGET. SOURCE can be NULL, in which - case nothing happens. Gets rid of SOURCE by free ()ing it. + case nothing happens. Gets rid of SOURCE by freeing it. Returns TARGET in case the location has changed. */ inline char * sub_append_string (source, target, indx, size) @@ -1287,7 +1638,7 @@ sub_append_string (source, target, indx, size) { int srclen, n; - srclen = strlen (source); + srclen = STRLEN (source); if (srclen >= (int)(*size - *indx)) { n = srclen + *indx; @@ -1304,6 +1655,8 @@ sub_append_string (source, target, indx, size) return (target); } +#if 0 +/* UNUSED */ /* Append the textual representation of NUMBER to TARGET. INDX and SIZE are as in SUB_APPEND_STRING. */ char * @@ -1316,27 +1669,38 @@ sub_append_number (number, target, indx, size) temp = itos (number); return (sub_append_string (temp, target, indx, size)); } +#endif /* Return the word list that corresponds to `$*'. */ WORD_LIST * list_rest_of_args () { - register WORD_LIST *list = (WORD_LIST *)NULL; - register WORD_LIST *args = rest_of_args; + register WORD_LIST *list, *args; int i; /* Break out of the loop as soon as one of the dollar variables is null. */ - for (i = 1; i < 10 && dollar_vars[i]; i++) - list = make_word_list (make_word (dollar_vars[i]), list); + for (i = 1, list = (WORD_LIST *)NULL; i < 10 && dollar_vars[i]; i++) + list = make_word_list (make_bare_word (dollar_vars[i]), list); + + for (args = rest_of_args; args; args = args->next) + list = make_word_list (make_bare_word (args->word->word), list); - while (args) - { - list = make_word_list (make_word (args->word->word), list); - args = args->next; - } return (REVERSE_LIST (list, WORD_LIST *)); } +int +number_of_args () +{ + register WORD_LIST *list; + int n; + + for (n = 0; n < 9 && dollar_vars[n+1]; n++) + ; + for (list = rest_of_args; list; list = list->next) + n++; + return n; +} + /* Make a single large string out of the dollar digit variables, and the rest_of_args. If DOLLAR_STAR is 1, then obey the special case of "$*" with respect to IFS. */ @@ -1344,9 +1708,10 @@ char * string_rest_of_args (dollar_star) int dollar_star; { - register WORD_LIST *list = list_rest_of_args (); + register WORD_LIST *list; char *string; + list = list_rest_of_args (); string = dollar_star ? string_list_dollar_star (list) : string_list (list); dispose_words (list); return (string); @@ -1369,9 +1734,9 @@ call_expand_word_internal (w, q, c, e) result = expand_word_internal (w, q, c, e); if (result == &expand_word_error) - longjmp (top_level, DISCARD); + jump_to_top_level (DISCARD); else if (result == &expand_word_fatal) - longjmp (top_level, FORCE_EOF); + jump_to_top_level (FORCE_EOF); else return (result); } @@ -1386,7 +1751,7 @@ expand_string_internal (string, quoted) WORD_DESC td; WORD_LIST *tresult; - if (!string || !*string) + if (string == 0 || *string == 0) return ((WORD_LIST *)NULL); bzero (&td, sizeof (td)); @@ -1420,25 +1785,6 @@ expand_string_unsplit (string, quoted) return (value); } -/* This does not perform word splitting or dequote the WORD_LIST - it returns. */ -static WORD_LIST * -expand_string_for_rhs (string, quoted, dollar_at_p, has_dollar_at) - char *string; - int quoted, *dollar_at_p, *has_dollar_at; -{ - WORD_DESC td; - WORD_LIST *tresult; - - if (string == 0 || *string == '\0') - return (WORD_LIST *)NULL; - - bzero (&td, sizeof (td)); - td.word = string; - tresult = call_expand_word_internal (&td, quoted, dollar_at_p, has_dollar_at); - return (tresult); -} - /* Expand STRING just as if you were expanding a word, but do not dequote the resultant WORD_LIST. This is called only from within this file, and is used to correctly preserve quoted characters when expanding @@ -1452,7 +1798,7 @@ expand_string_leave_quoted (string, quoted) WORD_LIST *tlist; WORD_LIST *tresult; - if (!string || !*string) + if (string == 0 || *string == '\0') return ((WORD_LIST *)NULL); tlist = expand_string_internal (string, quoted); @@ -1466,6 +1812,25 @@ expand_string_leave_quoted (string, quoted) return ((WORD_LIST *)NULL); } +/* This does not perform word splitting or dequote the WORD_LIST + it returns. */ +static WORD_LIST * +expand_string_for_rhs (string, quoted, dollar_at_p, has_dollar_at) + char *string; + int quoted, *dollar_at_p, *has_dollar_at; +{ + WORD_DESC td; + WORD_LIST *tresult; + + if (string == 0 || *string == '\0') + return (WORD_LIST *)NULL; + + bzero (&td, sizeof (td)); + td.word = string; + tresult = call_expand_word_internal (&td, quoted, dollar_at_p, has_dollar_at); + return (tresult); +} + /* Expand STRING just as if you were expanding a word. This also returns a list of words. Note that filename globbing is *NOT* done for word or string expansion, just when the shell is expanding a command. This @@ -1482,10 +1847,7 @@ expand_string (string, quoted) return ((WORD_LIST *)NULL); result = expand_string_leave_quoted (string, quoted); - - if (result) - dequote_list (result); - return (result); + return (result ? dequote_list (result) : result); } /*************************************************** @@ -1494,21 +1856,20 @@ expand_string (string, quoted) * * ***************************************************/ -/* I'm going to have to rewrite expansion because filename globbing is - beginning to make the entire arrangement ugly. I'll do this soon. */ -static void +static WORD_LIST * dequote_list (list) - register WORD_LIST *list; + WORD_LIST *list; { register char *s; + register WORD_LIST *tlist; - while (list) + for (tlist = list; tlist; tlist = tlist->next) { - s = dequote_string (list->word->word); - free (list->word->word); - list->word->word = s; - list = list->next; + s = dequote_string (tlist->word->word); + free (tlist->word->word); + tlist->word->word = s; } + return list; } static char * @@ -1533,13 +1894,14 @@ make_quoted_char (c) } /* Quote STRING. Return a new string. */ -static char * +char * quote_string (string) char *string; { + register char *t; char *result; - if (!*string) + if (*string == 0) { result = xmalloc (2); result[0] = CTLNUL; @@ -1547,11 +1909,9 @@ quote_string (string) } else { - register char *t; - result = xmalloc ((strlen (string) * 2) + 1); - for (t = result; string && *string; ) + for (t = result; *string; ) { *t++ = CTLESC; *t++ = *string++; @@ -1585,7 +1945,7 @@ dequote_string (string) return (result); /* XXX */ } - for (t = result; string && *string; string++) + for (t = result; *string; string++, t++) { if (*string == CTLESC) { @@ -1595,7 +1955,7 @@ dequote_string (string) break; } - *t++ = *string; + *t = *string; } *t = '\0'; @@ -1603,19 +1963,21 @@ dequote_string (string) } /* Quote the entire WORD_LIST list. */ -static void +static WORD_LIST * quote_list (list) WORD_LIST *list; { register WORD_LIST *w; + char *t; for (w = list; w; w = w->next) { - char *t = w->word->word; + t = w->word->word; w->word->word = quote_string (t); free (t); - w->word->quoted = 1; + w->word->flags |= W_QUOTED; } + return list; } /* **************************************************************** */ @@ -1642,15 +2004,17 @@ remove_pattern (param, pattern, op) char *param, *pattern; int op; { - register int len = param ? strlen (param) : 0; - register char *end = param + len; + register int len; + register char *end; register char *p, *ret, c; + if (param == NULL || *param == '\0') + return (param); if (pattern == NULL || *pattern == '\0') /* minor optimization */ return (savestring (param)); - if (param == NULL || *param == '\0') - return (param); + len = STRLEN (param); + end = param + len; switch (op) { @@ -1680,35 +2044,151 @@ remove_pattern (param, pattern, op) } break; - case RP_LONG_RIGHT: /* remove longest match at end */ - for (p = param; p <= end; p++) - { - if (fnmatch (pattern, p, 0) != FNM_NOMATCH) - { - c = *p; - *p = '\0'; - ret = savestring (param); - *p = c; - return (ret); - } - } - break; + case RP_LONG_RIGHT: /* remove longest match at end */ + for (p = param; p <= end; p++) + { + if (fnmatch (pattern, p, 0) != FNM_NOMATCH) + { + c = *p; *p = '\0'; + ret = savestring (param); + *p = c; + return (ret); + } + } + break; + + case RP_SHORT_RIGHT: /* remove shortest match at end */ + for (p = end; p >= param; p--) + { + if (fnmatch (pattern, p, 0) != FNM_NOMATCH) + { + c = *p; *p = '\0'; + ret = savestring (param); + *p = c; + return (ret); + } + } + break; + } + return (savestring (param)); /* no match, return original string */ +} + +/* Return 1 of the first character of STRING could match the first + character of pattern PAT. Used to avoid n2 calls to fnmatch(). */ +static int +match_pattern_char (pat, string) + char *pat, *string; +{ + register char *np; + int neg; + char c, c1; + + if (*string == 0) + return (0); + + switch (c = *pat++) + { + default: + return (*string == c); + case '\\': + return (*string == *pat); + case '?': + case '*': + return (1); + case '[': + for (np = pat; *np != ']'; np++); + if (*np == 0) + return (*string == '['); + if (neg = (*pat == '!' || *pat == '^')) + pat++; + for ( ; (c1 = *pat++) != ']'; ) + { + if (c1 == '\\') + c1 = *pat++; + if (c1 == 0) + return (0); + if (*pat != '-' || pat[1] == '\0' || pat[1] == ']') + return (neg ? *string != c1 : *string == c1); + if (c1 <= *string && *string <= pat[1]) + return (1); + pat += 2; + } + } +} + +/* Match PAT anywhere in STRING and return the match boundaries. + This returns 1 in case of a successful match, 0 otherwise. SP + and EP are pointers into the string where the match begins and + ends, respectively. MTYPE controls what kind of match is attempted. + MATCH_BEG and MATCH_END anchor the match at the beginning and end + of the string, respectively. The longest match is returned. */ +static int +match_pattern (string, pat, mtype, sp, ep) + char *string, *pat; + int mtype; + char **sp, **ep; +{ + int c; + register char *p, *p1; + char *end; + + if (string == 0 || *string == 0 || pat == 0 || *pat == 0) + return (0); + + end = string + STRLEN (string); + + switch (mtype) + { + case MATCH_ANY: + for (p = string; p <= end; p++) + { + if (match_pattern_char (pat, p)) + { + for (p1 = end; p1 >= p; p1--) + { + c = *p1; *p1 = '\0'; + if (fnmatch (pat, p, 0) == 0) + { + *p1 = c; + *sp = p; + *ep = p1; + return 1; + } + *p1 = c; + } + } + } + return (0); + + case MATCH_BEG: + if (match_pattern_char (pat, string) == 0) + return (0); + for (p = end; p >= string; p--) + { + c = *p; *p = '\0'; + if (fnmatch (pat, string, 0) == 0) + { + *p = c; + *sp = string; + *ep = p; + return 1; + } + *p = c; + } + return (0); - case RP_SHORT_RIGHT: /* remove shortest match at end */ - for (p = end; p >= param; p--) + case MATCH_END: + for (p = string; p <= end; p++) + if (fnmatch (pat, p, 0) == 0) { - if (fnmatch (pattern, p, 0) != FNM_NOMATCH) - { - c = *p; - *p = '\0'; - ret = savestring (param); - *p = c; - return (ret); - } + *sp = p; + *ep = end; + return 1; } - break; + return (0); } - return (savestring (param)); /* no match, return original string */ + + return (0); } /******************************************* @@ -1731,9 +2211,7 @@ expand_word (word, quoted) tresult = call_expand_word_internal (word, quoted, (int *)NULL, (int *)NULL); result = word_list_split (tresult); dispose_words (tresult); - if (result) - dequote_list (result); - return (result); + return (result ? dequote_list (result) : result); } /* Expand WORD, but do not perform word splitting on the result. This @@ -1747,9 +2225,7 @@ expand_word_no_split (word, quoted) WORD_LIST *result; result = call_expand_word_internal (word, quoted, (int *)NULL, (int *)NULL); - if (result) - dequote_list (result); - return (result); + return (result ? dequote_list (result) : result); } /* Perform shell expansions on WORD, but do not perform word splitting or @@ -1759,10 +2235,7 @@ expand_word_leave_quoted (word, quoted) WORD_DESC *word; int quoted; { - WORD_LIST *result; - - result = call_expand_word_internal (word, quoted, (int *)NULL, (int *)NULL); - return (result); + return (call_expand_word_internal (word, quoted, (int *)NULL, (int *)NULL)); } /* Return the value of a positional parameter. This handles values > 10. */ @@ -1771,25 +2244,16 @@ get_dollar_var_value (ind) int ind; { char *temp; + WORD_LIST *p; if (ind < 10) - { - if (dollar_vars[ind]) - temp = savestring (dollar_vars[ind]); - else - temp = (char *)NULL; - } + temp = dollar_vars[ind] ? savestring (dollar_vars[ind]) : (char *)NULL; else /* We want something like ${11} */ { - WORD_LIST *p = rest_of_args; - ind -= 10; - while (p && ind--) - p = p->next; - if (p) - temp = savestring (p->word->word); - else - temp = (char *)NULL; + for (p = rest_of_args; p && ind--; p = p->next) + ; + temp = p ? savestring (p->word->word) : (char *)NULL; } return (temp); } @@ -1802,19 +2266,17 @@ get_dollar_var_value (ind) /* */ /* **************************************************************** */ -extern struct fd_bitmap *current_fds_to_close; -extern char *mktemp (); - #if !defined (HAVE_DEV_FD) /* Named pipes must be removed explicitly with `unlink'. This keeps a list of FIFOs the shell has open. unlink_fifo_list will walk the list and unlink all of them. add_fifo_list adds the name of an open FIFO to the list. NFIFO is a count of the number of FIFOs in the list. */ #define FIFO_INCR 20 +extern char *mktemp (); static char **fifo_list = (char **)NULL; -static int nfifo = 0; -static int fifo_list_size = 0; +static int nfifo; +static int fifo_list_size; static void add_fifo_list (pathname) @@ -1833,7 +2295,7 @@ add_fifo_list (pathname) void unlink_fifo_list () { - if (!nfifo) + if (nfifo == 0) return; while (nfifo--) @@ -1861,20 +2323,6 @@ make_named_pipe () return (tname); } -#if !defined (_POSIX_VERSION) -int -mkfifo (path, mode) - char *path; - int mode; -{ -#if defined (S_IFIFO) - return (mknod (path, (mode | S_IFIFO), 0)); -#else /* !S_IFIFO */ - return (-1); -#endif /* !S_IFIFO */ -} -#endif /* !_POSIX_VERSION */ - #else /* HAVE_DEV_FD */ /* DEV_FD_LIST is a bitmap of file descriptors attached to pipes the shell @@ -1882,7 +2330,7 @@ mkfifo (path, mode) set in DEV_FD_LIST. TOTFDS is a count of the highest possible number of open files. */ static char *dev_fd_list = (char *)NULL; -static int nfds = 0; +static int nfds; static int totfds; /* The highest possible number of open files. */ static void @@ -1913,7 +2361,7 @@ unlink_fifo_list () { register int i; - if (!nfds) + if (nfds == 0) return; for (i = 0; nfds && i < totfds; i++) @@ -1950,8 +2398,8 @@ make_dev_fd_filename (fd) { char *ret; - ret = xmalloc (16 * sizeof (char)); - sprintf (ret, "/dev/fd/%d", fd); + ret = xmalloc (16); + sprintf (ret, "%s%d", DEV_FD_PREFIX, fd); add_fifo_list (fd); return (ret); } @@ -1984,7 +2432,7 @@ process_substitute (string, open_for_read_in_child) #endif /* HAVE_DEV_FD */ #if defined (JOB_CONTROL) pid_t old_pipeline_pgrp; -#endif +#endif if (!string || !*string) return ((char *)NULL); @@ -1994,8 +2442,7 @@ process_substitute (string, open_for_read_in_child) #else /* HAVE_DEV_FD */ if (pipe (fildes) < 0) { - internal_error ("can't make pipes for process substitution: %s", - strerror (errno)); + sys_error ("cannot make pipe for process substitution"); return ((char *)NULL); } /* If OPEN_FOR_READ_IN_CHILD == 1, we want to use the write end of @@ -2007,8 +2454,7 @@ process_substitute (string, open_for_read_in_child) if (!pathname) { - internal_error ("cannot make pipe for process subsitution: %s", - strerror (errno)); + sys_error ("cannot make pipe for process substitution"); return ((char *)NULL); } @@ -2017,33 +2463,32 @@ process_substitute (string, open_for_read_in_child) #if defined (JOB_CONTROL) old_pipeline_pgrp = pipeline_pgrp; pipeline_pgrp = shell_pgrp; +#if 0 cleanup_the_pipeline (); +#else + save_pipeline (1); +#endif +#endif /* JOB_CONTROL */ + pid = make_child ((char *)NULL, 1); if (pid == 0) { + reset_terminating_signals (); /* XXX */ /* Cancel traps, in trap.c. */ restore_original_signals (); setup_async_signals (); - subshell_environment++; + subshell_environment = SUBSHELL_COMSUB; } + +#if defined (JOB_CONTROL) set_sigchld_handler (); stop_making_children (); pipeline_pgrp = old_pipeline_pgrp; -#else /* !JOB_CONTROL */ - pid = make_child ((char *)NULL, 1); - if (pid == 0) - { - /* Cancel traps, in trap.c. */ - restore_original_signals (); - setup_async_signals (); - subshell_environment++; - } -#endif /* !JOB_CONTROL */ +#endif /* JOB_CONTROL */ if (pid < 0) { - internal_error ("cannot make a child for process substitution: %s", - strerror (errno)); + sys_error ("cannot make child for process substitution"); free (pathname); #if defined (HAVE_DEV_FD) close (parent_pipe_fd); @@ -2054,6 +2499,10 @@ process_substitute (string, open_for_read_in_child) if (pid > 0) { +#if defined (JOB_CONTROL) + restore_pipeline (1); +#endif + last_made_pid = old_pid; #if defined (JOB_CONTROL) && defined (PGRP_PIPE) @@ -2075,11 +2524,11 @@ process_substitute (string, open_for_read_in_child) #if !defined (HAVE_DEV_FD) /* Open the named pipe in the child. */ - fd = open (pathname, open_for_read_in_child ? O_RDONLY : O_WRONLY); + fd = open (pathname, open_for_read_in_child ? O_RDONLY|O_NONBLOCK : O_WRONLY); if (fd < 0) { - internal_error ("cannot open named pipe %s for %s: %s", pathname, - open_for_read_in_child ? "reading" : "writing", strerror (errno)); + sys_error ("cannot open named pipe %s for %s", pathname, + open_for_read_in_child ? "reading" : "writing"); exit (127); } #else /* HAVE_DEV_FD */ @@ -2088,8 +2537,8 @@ process_substitute (string, open_for_read_in_child) if (dup2 (fd, open_for_read_in_child ? 0 : 1) < 0) { - internal_error ("cannot duplicate named pipe %s as fd %d: %s", - pathname, open_for_read_in_child ? 0 : 1, strerror (errno)); + sys_error ("cannot duplicate named pipe %s as fd %d", pathname, + open_for_read_in_child ? 0 : 1); exit (127); } @@ -2130,13 +2579,13 @@ command_substitute (string, quoted) char *string; int quoted; { - pid_t pid, old_pid; - int fildes[2]; - char *istring = (char *)NULL; - int istring_index, istring_size, c = 1; - int result; + pid_t pid, old_pid, old_pipeline_pgrp; + char *istring; + int istring_index, istring_size, c, result, fildes[2]; + FILE *istream; istring_index = istring_size = 0; + istring = (char *)NULL; /* Don't fork () if there is no need to. In the case of no command to run, just return NULL. */ @@ -2146,39 +2595,32 @@ command_substitute (string, quoted) /* Pipe the output of executing STRING into the current shell. */ if (pipe (fildes) < 0) { - internal_error ("Can't make pipes for command substitution!"); + sys_error ("cannot make pipes for command substitution"); goto error_exit; } old_pid = last_made_pid; #if defined (JOB_CONTROL) - { - pid_t old_pipeline_pgrp = pipeline_pgrp; - - pipeline_pgrp = shell_pgrp; - cleanup_the_pipeline (); - pid = make_child ((char *)NULL, 0); - if (pid == 0) - /* Reset the signal handlers in the child, but don't free the - trap strings. */ - reset_signal_handlers (); - set_sigchld_handler (); - stop_making_children (); - pipeline_pgrp = old_pipeline_pgrp; - } -#else /* !JOB_CONTROL */ - pid = make_child ((char *)NULL, 0); + old_pipeline_pgrp = pipeline_pgrp; + pipeline_pgrp = shell_pgrp; + cleanup_the_pipeline (); +#endif + pid = make_child ((char *)NULL, 0); if (pid == 0) /* Reset the signal handlers in the child, but don't free the trap strings. */ reset_signal_handlers (); -#endif /* !JOB_CONTROL */ + +#if defined (JOB_CONTROL) + set_sigchld_handler (); + stop_making_children (); + pipeline_pgrp = old_pipeline_pgrp; +#endif /* JOB_CONTROL */ if (pid < 0) { - internal_error ("Can't make a child for command substitution: %s", - strerror (errno)); + sys_error ("cannot make child for command substitution"); error_exit: FREE (istring); @@ -2195,9 +2637,7 @@ command_substitute (string, quoted) #endif if (dup2 (fildes[1], 1) < 0) { - internal_error - ("command_substitute: cannot duplicate pipe as fd 1: %s", - strerror (errno)); + sys_error ("command_substitute: cannot duplicate pipe as fd 1"); exit (EXECUTION_FAILURE); } @@ -2220,11 +2660,15 @@ command_substitute (string, quoted) /* The currently executing shell is not interactive. */ interactive = 0; + /* This is a subshell environment. */ + subshell_environment = SUBSHELL_COMSUB; + /* Command substitution does not inherit the -e flag. */ exit_immediately_on_error = 0; remove_quoted_escapes (string); + startup_state = 2; /* see if we can avoid a fork */ /* Give command substitution a place to jump back to on failure, so we don't go back up to main (). */ result = setjmp (top_level); @@ -2238,8 +2682,6 @@ command_substitute (string, quoted) } else { - FILE *istream; - istream = fdopen (fildes[0], "r"); #if defined (JOB_CONTROL) && defined (PGRP_PIPE) @@ -2248,40 +2690,36 @@ command_substitute (string, quoted) close (fildes[1]); - if (!istream) + if (istream == 0) { - internal_error ("Can't reopen pipe to command substitution (fd %d): %s", - fildes[0], strerror (errno)); + sys_error ("cannot reopen pipe to command substitution (fd %d)", fildes[0]); goto error_exit; } /* Read the output of the command through the pipe. */ while (1) { -#if defined (NO_READ_RESTART_ON_SIGNAL) +#if !defined (HAVE_RESTARTABLE_SYSCALLS) c = getc_with_restart (istream); #else c = getc (istream); -#endif /* !NO_READ_RESTART_ON_SIGNAL */ +#endif /* HAVE_RESTARTABLE_SYSCALLS */ if (c == EOF) break; - /* Add the character to ISTRING. */ - if (istring_index + 2 >= istring_size) - { - while (istring_index + 2 >= istring_size) - istring_size += DEFAULT_ARRAY_SIZE; - istring = xrealloc (istring, istring_size); - } + /* Add the character to ISTRING, possibly after resizing it. */ + RESIZE_MALLOCED_BUFFER (istring, istring_index, 2, istring_size, DEFAULT_ARRAY_SIZE); - if (quoted || c == CTLESC || c == CTLNUL) + if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || c == CTLESC || c == CTLNUL) istring[istring_index++] = CTLESC; istring[istring_index++] = c; - istring[istring_index] = '\0'; } + if (istring) + istring[istring_index] = '\0'; + fclose (istream); close (fildes[0]); @@ -2308,7 +2746,7 @@ command_substitute (string, quoted) goto error_exit; /* Strip trailing newlines from the output of the command. */ - if (quoted) + if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) { while (istring_index > 0) { @@ -2338,66 +2776,387 @@ command_substitute (string, quoted) * * ********************************************************/ +static int +getpatspec (c, value) + int c; + char *value; +{ + if (c == '#') + return ((*value == '#') ? RP_LONG_LEFT : RP_SHORT_LEFT); + else /* c == '%' */ + return ((*value == '%') ? RP_LONG_RIGHT : RP_SHORT_RIGHT); +} + +/* Posix.2 says that the WORD should be run through tilde expansion, + parameter expansion, command substitution and arithmetic expansion. + This leaves the result quoted, so quote_string_for_globbing () has + to be called to fix it up for fnmatch (). If QUOTED is non-zero, + it means that the entire expression was enclosed in double quotes. + This means that quoting characters in the pattern do not make any + special pattern characters quoted. For example, the `*' in the + following retains its special meaning: "${foo#'*'}". */ +static char * +getpattern (value, quoted, expandpat) + char *value; + int quoted, expandpat; +{ + char *pat, *tword; + WORD_LIST *l; + int i; + + tword = strchr (value, '~') ? bash_tilde_expand (value) : savestring (value); + + /* expand_string_internal () leaves WORD quoted and does not perform + word splitting. */ + if (expandpat && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && *tword) + { + i = 0; + pat = string_extract_double_quoted (tword, &i, 1); + free (tword); + tword = pat; + } + + /* There is a problem here: how to handle single or double quotes in the + pattern string when the whole expression is between double quotes? */ +#if 0 + l = *tword ? expand_string_for_rhs (tword, quoted, (int *)NULL, (int *)NULL) +#else + l = *tword ? expand_string_for_rhs (tword, + (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) ? Q_NOQUOTE : quoted, + (int *)NULL, (int *)NULL) +#endif + : (WORD_LIST *)0; + free (tword); + pat = string_list (l); + dispose_words (l); + if (pat) + { + tword = quote_string_for_globbing (pat, 1); + free (pat); + pat = tword; + } + return (pat); +} + /* Handle removing a pattern from a string as a result of ${name%[%]value} or ${name#[#]value}. */ static char * -parameter_brace_remove_pattern (value, temp, c) +parameter_brace_remove_pattern (value, temp, c, quoted) char *value, *temp; - int c; + int c, quoted; +{ + int patspec; + char *pattern, *tword; + + patspec = getpatspec (c, value); + if (patspec == RP_LONG_LEFT || patspec == RP_LONG_RIGHT) + value++; + + pattern = getpattern (value, quoted, 1); + + tword = remove_pattern (temp, pattern, patspec); + + FREE (pattern); + return (tword); +} + +static char * +list_remove_pattern (list, pattern, patspec, type, quoted) + WORD_LIST *list; + char *pattern; + int patspec, type, quoted; +{ + WORD_LIST *new, *l; + WORD_DESC *w; + char *tword; + + for (new = (WORD_LIST *)NULL, l = list; l; l = l->next) + { + tword = remove_pattern (l->word->word, pattern, patspec); + w = make_bare_word (tword); + new = make_word_list (w, new); + } + + l = REVERSE_LIST (new, WORD_LIST *); + if (type == '*') + tword = (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) ? string_list_dollar_star (l) : string_list (l); + else + tword = string_list ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) ? quote_list (l) : l); + + dispose_words (l); + return (tword); +} + +static char * +parameter_list_remove_pattern (value, type, c, quoted) + char *value; + int type, c, quoted; +{ + int patspec; + char *pattern; + + patspec = getpatspec (c, value); + if (patspec == RP_LONG_LEFT || patspec == RP_LONG_RIGHT) + value++; + + pattern = getpattern (value, quoted, 1); + + return (list_remove_pattern (list_rest_of_args (), pattern, patspec, type, quoted)); +} + +#if defined (ARRAY_VARS) +static char * +array_remove_pattern (value, aspec, aval, c, quoted) + char *value, *aspec, *aval; /* AVAL == evaluated ASPEC */ + int c, quoted; { - int pattern_specifier; + SHELL_VAR *var; + int len, patspec; +#if 0 + int ind; +#endif + char *ret, *t, *pattern; WORD_LIST *l; - char *pattern, *t, *tword; - if (c == '#') + var = array_variable_part (aspec, &t, &len); + if (var == 0) + return ((char *)NULL); + + patspec = getpatspec (c, value); + if (patspec == RP_LONG_LEFT || patspec == RP_LONG_RIGHT) + value++; + + pattern = getpattern (value, quoted, 1); + + if (ALL_ELEMENT_SUB (t[0]) && t[1] == ']') + { + if (array_p (var) == 0) + { + report_error ("%s: bad array subscript", aspec); + return ((char *)NULL); + } + l = array_to_word_list (array_cell (var)); + if (l == 0) + return ((char *)NULL); + ret = list_remove_pattern (l, pattern, patspec, t[0], quoted); + dispose_words (l); + } + else { - if (*value == '#') +#if 0 + ind = array_expand_index (t, len); + if (ind < 0) { - value++; - pattern_specifier = RP_LONG_LEFT; + report_error ("%s: bad array subscript", aspec); + return ((char *)NULL); } - else - pattern_specifier = RP_SHORT_LEFT; + if (array_p (var) == 0 && ind != 0) + return ((char *)NULL); + + t = array_p (var) ? array_reference (array_cell (var), ind) : value_cell (var); + ret = remove_pattern (t, pattern, patspec); +#else + ret = remove_pattern (aval, pattern, patspec); +#endif + if (ret) + quote_escapes (ret); } - else /* c == '%' */ + return ret; +} + +int +valid_array_reference (name) + char *name; +{ + char *t; + int r, len; + + t = strchr (name, '['); + if (t) + { + *t = '\0'; + r = legal_identifier (name); + *t = '['; + if (r == 0) + return 0; + /* Check for a properly-terminated non-blank subscript. */ + len = skipsubscript (t, 0); + if (t[len] != ']' || len == 1) + return 0; + for (r = 1; r < len; r++) + if (whitespace (t[r]) == 0) + return 1; + return 0; + } + return 0; +} + +/* Expand the array index beginning at S and extending LEN characters. */ +int +array_expand_index (s, len) + char *s; + int len; +{ + char *exp, *t; + int val; + + exp = xmalloc (len); + strncpy (exp, s, len - 1); + exp[len - 1] = '\0'; + t = maybe_expand_string (exp, 0, expand_string); + this_command_name = (char *)NULL; + val = evalexp (t); + free (t); + free (exp); + return val; +} + +/* Return the variable specified by S without any subscript. If non-null, + return the index of the start of the subscript in *SUBP. If non-null, + the length of the subscript is returned in *LENP. */ +SHELL_VAR * +array_variable_part (s, subp, lenp) + char *s, **subp; + int *lenp; +{ + char *t; + int ind, ni; + SHELL_VAR *var; + + t = strchr (s, '['); + ind = t - s; + ni = skipsubscript (s, ind); + if (ni <= ind + 1 || s[ni] != ']') { - if (*value == '%') + report_error ("%s: bad array subscript", s); + return ((SHELL_VAR *)NULL); + } + + *t = '\0'; + var = find_variable (s); + *t++ = '['; + + if (subp) + *subp = t; + if (lenp) + *lenp = ni - ind; + return var; +} + +static char * +array_value_internal (s, quoted, allow_all) + char *s; + int quoted, allow_all; +{ + int len, ind; + char *retval, *t; + WORD_LIST *l; + SHELL_VAR *var; + + var = array_variable_part (s, &t, &len); + + if (var == 0) + return (char *)NULL; + + if (ALL_ELEMENT_SUB (t[0]) && t[1] == ']') + { + if (array_p (var) == 0 || allow_all == 0) + { + report_error ("%s: bad array subscript", s); + return ((char *)NULL); + } + l = array_to_word_list (array_cell (var)); + if (l == (WORD_LIST *)NULL) + return ((char *) NULL); + + if (t[0] == '*') /* ${name[*]} */ + retval = (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) ? string_list_dollar_star (l) : string_list (l); + else /* ${name[@]} */ + retval = string_list ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) ? quote_list (l) : l); + + dispose_words (l); + } + else + { + ind = array_expand_index (t, len); + if (ind < 0) { - value++; - pattern_specifier = RP_LONG_RIGHT; + report_error ("%s: bad array subscript", var->name); + return ((char *)NULL); } - else - pattern_specifier = RP_SHORT_RIGHT; + if (array_p (var) == 0) + return (ind == 0 ? value_cell (var) : (char *)NULL); + retval = array_reference (array_cell (var), ind); + if (retval) + retval = quote_escapes (retval); } - /* Posix.2 says that the WORD should be run through tilde expansion, - parameter expansion, command substitution and arithmetic expansion. - This leaves the result quoted, so quote_string_for_globbing () has - to be called to fix it up for fnmatch (). */ - if (strchr (value, '~')) - tword = tilde_expand (value); - else - tword = savestring (value); + return retval; +} - /* expand_string_internal () leaves WORD quoted and does not perform - word splitting. */ - l = expand_string_internal (tword, 0); - free (tword); - pattern = string_list (l); - dispose_words (l); +static char * +array_value (s, quoted) + char *s; + int quoted; +{ + return (array_value_internal (s, quoted, 1)); +} + +/* Return the value of the array indexing expression S as a single string. + If ALLOW_ALL is 0, do not allow `@' and `*' subscripts. This is used + by other parts of the shell such as the arithmetic expression evaluator + in expr.c. */ +char * +get_array_value (s, allow_all) + char *s; + int allow_all; +{ + return (array_value_internal (s, 0, allow_all)); +} + +static int +array_length_reference (s) + char *s; +{ + int ind, len; + char *t; + ARRAY *array; + SHELL_VAR *var; + + var = array_variable_part (s, &t, &len); - if (pattern) + /* If unbound variables should generate an error, report one and return + failure. */ + if ((var == 0 || array_p (var) == 0) && unbound_vars_is_error) { - tword = quote_string_for_globbing (pattern, 1); - free (pattern); - pattern = tword; + ind = *--t; + *t = '\0'; + report_error ("%s: unbound variable", s); + *t++ = (char)ind; + return (-1); } + else if (var == 0) + return 0; + else if (array_p (var) == 0) + return 1; - t = remove_pattern (temp, pattern, pattern_specifier); + array = array_cell (var); - FREE (pattern); - return (t); + if (ALL_ELEMENT_SUB (t[0]) && t[1] == ']') + return (array_num_elements (array)); + + ind = array_expand_index (t, len); + if (ind < 0) + { + report_error ("%s: bad array subscript", t); + return (-1); + } + t = array_reference (array, ind); + len = STRLEN (t); + + return (len); } +#endif /* ARRAY_VARS */ static int valid_brace_expansion_word (name, var_is_special) @@ -2408,11 +3167,16 @@ valid_brace_expansion_word (name, var_is_special) return 1; else if (var_is_special) return 1; +#if defined (ARRAY_VARS) + else if (valid_array_reference (name)) + return 1; +#endif /* ARRAY_VARS */ else if (legal_identifier (name)) return 1; else return 0; } + /* Parameter expand NAME, and return a new string which is the expansion, or NULL if there was no expansion. VAR_IS_SPECIAL is non-zero if NAME is one of the special variables in @@ -2423,84 +3187,124 @@ parameter_brace_expand_word (name, var_is_special, quoted) char *name; int var_is_special, quoted; { - char *temp = (char *)NULL; + char *temp, *tt; + int arg_index; + SHELL_VAR *var; + WORD_LIST *l; /* Handle multiple digit arguments, as in ${11}. */ if (digit (*name)) { - int arg_index = atoi (name); - + arg_index = atoi (name); temp = get_dollar_var_value (arg_index); } else if (var_is_special) /* ${@} */ { - char *tt; - WORD_LIST *l; - tt = xmalloc (2 + strlen (name)); - tt[0] = '$'; tt[1] = '\0'; + tt[0] = '$'; strcpy (tt + 1, name); l = expand_string_leave_quoted (tt, quoted); free (tt); temp = string_list (l); dispose_words (l); } +#if defined (ARRAY_VARS) + else if (valid_array_reference (name)) + { + temp = array_value (name, quoted); + } +#endif + else if (var = find_variable (name)) + { + if (var && invisible_p (var) == 0) + { +#if defined (ARRAY_VARS) + temp = array_p (var) ? array_reference (array_cell (var), 0) : value_cell (var); +#else + temp = value_cell (var); +#endif + + if (temp) + temp = quote_escapes (temp); + } + else + temp = (char *)NULL; + } else - { - SHELL_VAR *var = find_variable (name); + temp = (char *)NULL; - if (var && !invisible_p (var) && (temp = value_cell (var))) - temp = quoted && temp && *temp ? quote_string (temp) - : quote_escapes (temp); - } return (temp); } +/* Expand an indirect reference to a variable: ${!NAME} expands to the + value of the variable whose name is the value of NAME. */ +static char * +parameter_brace_expand_indir (name, var_is_special, quoted) + char *name; + int var_is_special, quoted; +{ + char *temp, *t; + + t = parameter_brace_expand_word (name, var_is_special, quoted); + if (t == 0) + return (t); + temp = parameter_brace_expand_word (t, t[0] == '@' && t[1] == '\0', quoted); + free (t); + return temp; +} + /* Expand the right side of a parameter expansion of the form ${NAMEcVALUE}, depending on the value of C, the separating character. C can be one of - "-", "+", or "=". */ + "-", "+", or "=". QUOTED is true if the entire brace expression occurs + between double quotes. */ static char * -parameter_brace_expand_rhs (name, value, c, quoted) +parameter_brace_expand_rhs (name, value, c, quoted, qdollaratp, hasdollarat) char *name, *value; - int c, quoted; + int c, quoted, *qdollaratp, *hasdollarat; { WORD_LIST *l; char *t, *t1, *temp; - int i, lquote, hasdol; + int hasdol; - if (value[0] == '~' || - (strchr (value, '~') && unquoted_substring ("=~", value))) - temp = tilde_expand (value); - else - temp = savestring (value); + temp = (*value == '~' || (strchr (value, '~') && unquoted_substring ("=~", value))) + ? bash_tilde_expand (value) + : savestring (value); - /* This is a hack. A better fix is coming later. */ - lquote = 0; - if (*temp == '"' && temp[strlen (temp) - 1] == '"') + /* If the entire expression is between double quotes, we want to treat + the value as a double-quoted string, with the exception that we strip + embedded unescaped double quotes. */ + if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && *temp) { - i = 1; - t = string_extract_double_quoted (temp, &i); /* XXX */ + hasdol = 0; + t = string_extract_double_quoted (temp, &hasdol, 1); free (temp); temp = t; - lquote = 1; /* XXX */ } + hasdol = 0; - /* XXX was quoted not lquote */ - l = *temp ? expand_string_for_rhs (temp, quoted||lquote, &hasdol, (int *)NULL) - : (WORD_LIST *)NULL; + /* XXX was 0 not quoted */ + l = *temp ? expand_string_for_rhs (temp, quoted, &hasdol, (int *)NULL) + : (WORD_LIST *)0; + if (hasdollarat) + *hasdollarat = hasdol || (l && l->next); free (temp); - /* expand_string_for_rhs does not dequote the word list it returns, but - there are a few cases in which we need to add quotes. */ - if (lquote && quoted == 0 && hasdol == 0 && l && l->word->quoted == 0) - quote_list (l); - if (l) { + /* The expansion of TEMP returned something. We need to treat things + slightly differently if HASDOL is non-zero. */ temp = string_list (l); + /* If l->next is not null, we know that TEMP contained "$@", since that + is the only expansion that creates more than one word. */ + if ((hasdol && quoted) || l->next) + *qdollaratp = 1; dispose_words (l); } - else if (lquote) + else if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && hasdol) { + /* The brace expansion occurred between double quotes and there was + a $@ in TEMP. It does not matter if the $@ is quoted, as long as + it does not expand to anything. In this case, we want to return + a quoted empty string. */ temp = xmalloc (2); temp[0] = CTLNUL; temp[1] = '\0'; @@ -2512,10 +3316,7 @@ parameter_brace_expand_rhs (name, value, c, quoted) return (temp); /* c == '=' */ - if (temp) - t = savestring (temp); - else - t = savestring (""); + t = temp ? savestring (temp) : savestring (""); t1 = dequote_string (t); free (t); bind_variable (name, t1); @@ -2531,12 +3332,15 @@ static void parameter_brace_expand_error (name, value) char *name, *value; { + WORD_LIST *l; + char *temp; + if (value && *value) { - WORD_LIST *l = expand_string (value, 0); - char *temp1 = string_list (l); - report_error ("%s: %s", name, temp1 ? temp1 : value); - FREE (temp1); + l = expand_string (value, 0); + temp = string_list (l); + report_error ("%s: %s", name, temp ? temp : ""); /* XXX was value not "" */ + FREE (temp); dispose_words (l); } else @@ -2557,6 +3361,9 @@ valid_length_expression (name) return (!name[1] || /* ${#} */ ((name[1] == '@' || name[1] == '*') && !name[2]) || /* ${#@}, ${#*} */ (digit (name[1]) && all_digits (name + 1)) || /* ${#11} */ +#if defined (ARRAY_VARS) + valid_array_reference (name + 1) || /* ${#a[7]} */ +#endif legal_identifier (name + 1)); /* ${#PS1} */ } @@ -2566,60 +3373,717 @@ static int parameter_brace_expand_length (name) char *name; { - char *t; - int number = 0; + char *t, *newname; + int number; + WORD_LIST *list; +#if defined (ARRAY_VARS) + SHELL_VAR *var; +#endif + + if (name[1] == '\0') /* ${#} */ + number = number_of_args (); +#if defined (ARRAY_VARS) + else if (valid_array_reference (name + 1)) + number = array_length_reference (name + 1); +#endif /* ARRAY_VARS */ + else if (name[1] != '*' && name[1] != '@') + { + number = 0; + + if (digit (name[1])) /* ${#1} */ + { + t = get_dollar_var_value (atoi (name + 1)); + number = STRLEN (t); + FREE (t); + } +#if defined (ARRAY_VARS) + else if ((var = find_variable (name + 1)) && array_p (var)) + { + t = array_reference (array_cell (var), 0); + number = STRLEN (t); + } +#endif + else /* ${#PS1} */ + { + newname = savestring (name); + newname[0] = '$'; + list = expand_string (newname, Q_DOUBLE_QUOTES); + t = list ? string_list (list) : (char *)NULL; + free (newname); + if (list) + dispose_words (list); + + number = STRLEN (t); + FREE (t); + } + } + else /* ${#@} and ${#*} */ + number = number_of_args (); + + return (number); +} + +/* Verify and limit the start and end of the desired substring. If + VTYPE == 0, a regular shell variable is being used; if it is 1, + then the positional paramters are being used; if it is 2, then + VALUE is really a pointer to an array variable that should be used. */ +static int +verify_substring_values (value, substr, vtype, e1p, e2p) + char *value, *substr; + int vtype, *e1p, *e2p; +{ + char *t, *temp1; + int len; +#if defined (ARRAY_VARS) + ARRAY *a; +#endif + + t = strchr (substr, ':'); + if (t) + *t = '\0'; + temp1 = maybe_expand_string (substr, 1, expand_string); + *e1p = evalexp (temp1); + free (temp1); + + switch (vtype) + { + case VT_VARIABLE: + len = strlen (value); + break; + case VT_POSPARMS: + len = number_of_args () + 1; + break; +#if defined (ARRAY_VARS) + case VT_ARRAYVAR: + a = (ARRAY *)value; + len = array_num_elements (a) + 1; + break; +#endif + } + + if (*e1p < 0) /* negative offsets count from end */ + *e1p += len; + + if (t) + { + t++; + temp1 = maybe_expand_string (t, 1, expand_string); + t[-1] = ':'; + *e2p = evalexp (temp1); + free (temp1); + if (*e2p < 0) + { + internal_error ("%s: substring expression < 0", t); + return (0); + } + *e2p += *e1p; /* want E2 chars starting at E1 */ + if (*e2p > len) + *e2p = len; + } + else + *e2p = len; + + return (1); +} + +/* Return a string containing the positional parameters from START to + END, inclusive. If STRING[0] == '*', we obey the rules for $*, + which only makes a difference if QUOTED is non-zero. */ +static char * +pos_params (string, start, end, quoted) + char *string; + int start, end, quoted; +{ + WORD_LIST *save, *params, *h, *t; + char *ret; + int i; + + save = params = list_rest_of_args (); + if (save == 0) + return ((char *)NULL); + + for (i = 1; params && i < start; i++) + params = params->next; + if (params == 0) + return ((char *)NULL); + for (h = t = params; params && i < end; i++) + { + t = params; + params = params->next; + } + + t->next = (WORD_LIST *)NULL; + if (string[0] == '*') + ret = (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) ? string_list_dollar_star (h) : string_list (h); + else + ret = string_list ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) ? quote_list (h) : h); + t->next = params; + + dispose_words (save); + return (ret); +} + +/* Return the type of variable specified by VARNAME (simple variable, + positional param, or array variable. Also return the value specified + by VARNAME (value of a variable or a reference to an array element). */ +static int +get_var_and_type (varname, value, varp, valp) + char *varname, *value; + SHELL_VAR **varp; + char **valp; +{ + int vtype; + char *temp; +#if defined (ARRAY_VARS) + SHELL_VAR *v; +#endif + + vtype = (varname[0] == '@' || varname[0] == '*') && varname[1] == '\0'; /* VT_POSPARMS */ + *varp = (SHELL_VAR *)NULL; + +#if defined (ARRAY_VARS) + if (valid_array_reference (varname)) + { + v = array_variable_part (varname, &temp, (int *)0); + if (v && array_p (v)) + { + if (temp[0] == '@' && temp[1] == ']') + { + vtype = VT_ARRAYVAR; + *valp = (char *)array_cell (v); + } + else + { + vtype = VT_VARIABLE; + *valp = array_value (varname, 1); + } + *varp = v; + } + else + return -1; + } + else if ((v = find_variable (varname)) && array_p (v)) + { + vtype = VT_VARIABLE; + *varp = v; + *valp = array_reference (array_cell (v), 0); + } + else +#endif + *valp = value; + + return vtype; +} + +/* Process a variable substring expansion: ${name:e1[:e2]}. If VARNAME + is `@', use the positional parameters; otherwise, use the value of + VARNAME. If VARNAME is an array variable, use the array elements. */ + +static char * +parameter_brace_substring (varname, value, substr, quoted) + char *varname, *value, *substr; + int quoted; +{ + int e1, e2, vtype; + char *temp, *val; + SHELL_VAR *v; + + if (value == 0) + return ((char *)NULL); + + this_command_name = varname; + + vtype = get_var_and_type (varname, value, &v, &val); + if (vtype == -1) + return ((char *)NULL); + + if (verify_substring_values (val, substr, vtype, &e1, &e2) == 0) + return (&expand_param_error); + + switch (vtype) + { + case VT_VARIABLE: + temp = quoted ? quoted_substring (value, e1, e2) : substring (value, e1, e2); + break; + case VT_POSPARMS: + temp = pos_params (varname, e1, e2, quoted); + break; +#if defined (ARRAY_VARS) + case VT_ARRAYVAR: + temp = array_subrange (array_cell (v), e1, e2, quoted); + break; +#endif + } + + return temp; +} + +char * +pat_subst (string, pat, rep, mflags) + char *string, *pat, *rep; + int mflags; +{ + char *ret, *s, *e, *str; + int rsize, rptr, l, replen, mtype; + + ret = xmalloc (rsize = 64); + ret[0] = '\0'; + + mtype = mflags & MATCH_TYPEMASK; + + for (replen = STRLEN (rep), rptr = 0, str = string;;) + { + if (match_pattern (str, pat, mtype, &s, &e) == 0) + break; + l = s - str; + RESIZE_MALLOCED_BUFFER (ret, rptr, (l + replen), rsize, 64); + + /* OK, now copy the leading unmatched portion of the string (from + str to s) to ret starting at rptr (the current offset). Then copy + the replacement string at ret + rptr + (s - str). Increment + rptr (if necessary) and str and go on. */ + if (l) + { + strncpy (ret + rptr, str, l); + rptr += l; + } + if (replen) + { + strncpy (ret + rptr, rep, replen); + rptr += replen; + } + str = e; /* e == end of match */ + if (((mflags & MATCH_GLOBREP) == 0) || mtype != MATCH_ANY) + break; + } + + /* Now copy the unmatched portion of the input string */ + if (*str) + strcpy (ret + rptr, str); + else + ret[rptr] = '\0'; + + return ret; +} + +/* Do pattern match and replacement on the positional parameters. */ +static char * +pos_params_pat_subst (string, pat, rep, mflags) + char *string, *pat, *rep; + int mflags; +{ + WORD_LIST *save, *params; + WORD_DESC *w; + char *ret; + + save = params = list_rest_of_args (); + if (save == 0) + return ((char *)NULL); + + for ( ; params; params = params->next) + { + ret = pat_subst (params->word->word, pat, rep, mflags); + w = make_bare_word (ret); + dispose_word (params->word); + params->word = w; + FREE (ret); + } + + ret = string_list ((mflags & MATCH_QUOTED) ? quote_list (save) : save); + dispose_words (save); + + return (ret); +} + +static char * +parameter_brace_patsub (varname, value, patsub, quoted) + char *varname, *value, *patsub; + int quoted; +{ + int vtype, mflags; + char *val, *temp, *pat, *rep, *p; + SHELL_VAR *v; + + if (value == 0) + return ((char *)NULL); + + this_command_name = varname; + + vtype = get_var_and_type (varname, value, &v, &val); + if (vtype == -1) + return ((char *)NULL); + + mflags = 0; + if (*patsub == '/') + { + mflags |= MATCH_GLOBREP; + patsub++; + } + + if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) + mflags |= MATCH_QUOTED; + + if (rep = quoted_strchr (patsub, '/', ST_BACKSL)) + *rep++ = '\0'; + else + rep = (char *)NULL; + + if (rep && *rep == '\0') + rep = (char *)NULL; + + /* Expand PAT and REP for command, variable and parameter, arithmetic, + and process substitution. Also perform quote removal. Do not + perform word splitting or filename generation. */ + pat = maybe_expand_string (patsub, quoted, expand_string_unsplit); + if (rep) + rep = maybe_expand_string (rep, quoted, expand_string_unsplit); + + p = pat; + if (pat[0] == '#') + { + mflags |= MATCH_BEG; + p++; + } + else if (pat[0] == '%') + { + mflags |= MATCH_END; + p++; + } + else + mflags |= MATCH_ANY; + + /* OK, we now want to substitute REP for PAT in VAL. If GLOBAL is 1, + the substitution is done everywhere, otherwise only the first + occurrence of PAT is replaced. */ + switch (vtype) + { + case VT_VARIABLE: + temp = pat_subst (val, p, rep, mflags); + break; + case VT_POSPARMS: + temp = pos_params_pat_subst (val, p, rep, mflags); + break; +#if defined (ARRAY_VARS) + case VT_ARRAYVAR: + temp = array_pat_subst (array_cell (v), p, rep, mflags); + break; +#endif + } + + FREE (pat); + FREE (rep); + + return temp; +} + +/* ${[#][!]name[[:]#[#]%[%]-=?+[word][:e1[:e2]]]} */ +static char * +parameter_brace_expand (string, indexp, quoted, quoted_dollar_atp, contains_dollar_at) + char *string; + int *indexp, quoted, *quoted_dollar_atp, *contains_dollar_at; +{ + int check_nullness, var_is_set, var_is_null, var_is_special; + int want_substring, want_indir, want_patsub; + char *name, *value, *temp, *temp1; + int t_index, sindex, c, number; + + sindex = *indexp; + t_index = ++sindex; + name = string_extract (string, &t_index, "#%:-=?+/}", 1); + value = (char *)NULL; + var_is_set = var_is_null = var_is_special = check_nullness = 0; + want_substring = want_indir = want_patsub = 0; + + /* If the name really consists of a special variable, then + make sure that we have the entire name. Handle indirect + references to special variables here, too. */ + if ((sindex == t_index || + ((sindex == t_index - 1) && string[sindex] == '!')) && + (string[t_index] == '-' || + string[t_index] == '?' || + string[t_index] == '#')) + { + t_index++; + free (name); + temp1 = string_extract (string, &t_index, "#%:-=?+/}", 0); + name = xmalloc (3 + (strlen (temp1))); + *name = string[sindex]; + if (string[sindex] == '!') + { + /* indirect ref. of special variable */ + name[1] = string[sindex + 1]; + strcpy (name + 2, temp1); + } + else + strcpy (name + 1, temp1); + free (temp1); + } + sindex = t_index; + + /* Find out what character ended the variable name. Then + do the appropriate thing. */ + if (c = string[sindex]) + sindex++; + + /* If c is followed by one of the valid parameter expansion + characters, move past it as normal. If not, assume that + a substring specification is being given, and do not move + past it. */ + if (c == ':' && member (string[sindex], "-=?+")) + { + check_nullness++; + if (c = string[sindex]) + sindex++; + } + else if (c == ':') + want_substring = 1; + else if (c == '/') + want_patsub = 1; + + want_indir = *name == '!'; + + /* Determine the value of this variable. */ + + /* Check for special variables, directly and indirectly + referenced. */ + if ((digit (*name) && all_digits (name)) || + (name[1] == '\0' && member (*name, "#-?$!@*")) || + (want_indir && name[2] == '\0' && member (name[1], "#-?$!@*"))) + var_is_special++; + + /* Check for special expansion things. */ + if (*name == '#') /* length of a parameter */ + { + /* Take the lengths of some of the shell's special + parameters. */ + if (string[sindex] == '}' && name[1] == '\0' && + check_nullness == 0 && member (c, "-?$!#")) + { + free (name); + switch (c) + { + case '-': + temp1 = which_set_flags (); + break; + case '?': + temp1 = itos (last_command_exit_value); + break; + case '$': + temp1 = itos (dollar_dollar_pid); + break; + case '!': + if (last_asynchronous_pid == NO_PID) + temp1 = (char *)NULL; + else + temp1 = itos ((int)last_asynchronous_pid); + break; + case '#': + temp1 = itos (number_of_args ()); + break; + } + number = STRLEN (temp1); + FREE (temp1); + *indexp = ++sindex; /* { string[sindex] == '}' */ + return (itos (number)); + } + + /* Don't allow things like ${#:-foo} to go by; they are + errors. If we are not pointing at the character just + after the closing brace, then we haven't gotten all of + the name. Since it begins with a special character, + this is a bad substitution. Explicitly check for ${#:}, + which the rules do not catch. Also check NAME for + validity before trying to go on. */ + if (string[sindex - 1] != '}' || + member (c, "?-=+") || + (name[1] == '\0' && c == '}' && check_nullness) || + (valid_length_expression (name) == 0)) + { + temp = (char *)NULL; + goto bad_substitution; + } + + number = parameter_brace_expand_length (name); + free (name); + + *indexp = sindex; + return ((number < 0) ? &expand_param_error : itos (number)); + } + + /* ${@} is identical to $@. */ + if (name[0] == '@' && name[1] == '\0') + { + if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp) + *quoted_dollar_atp = 1; + + if (contains_dollar_at) + *contains_dollar_at = 1; + } + + /* Make sure that NAME is valid before trying to go on. */ + if (valid_brace_expansion_word (want_indir ? name + 1 : name, + var_is_special) == 0) + { + temp = (char *)NULL; + goto bad_substitution; + } + + if (want_indir) + temp = parameter_brace_expand_indir (name + 1, var_is_special, quoted); + else + temp = parameter_brace_expand_word (name, var_is_special, quoted); + +#if defined (ARRAY_VARS) + if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && valid_array_reference (name)) + { + temp1 = strchr (name, '['); + if (temp1 && temp1[1] == '@' && temp1[2] == ']') + { + if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp) + *quoted_dollar_atp = 1; + if (contains_dollar_at) + *contains_dollar_at = 1; + } + } +#endif + + var_is_set = temp != (char *)0; + var_is_null = check_nullness && (var_is_set == 0 || *temp == 0); + + /* Get the rest of the stuff inside the braces. */ + if (c && c != '}') + { + /* Extract the contents of the ${ ... } expansion + according to the Posix.2 rules. */ + value = extract_dollar_brace_string (string, &sindex, quoted); + /*{*/ + if (string[sindex] == '}') + sindex++; + else + goto bad_substitution; + } + else + value = (char *)NULL; - if (name[1] == '\0') /* ${#} */ + *indexp = sindex; + + /* If this is a substring spec, process it and add the result. */ + if (want_substring) { - WORD_LIST *l = list_rest_of_args (); - number = list_length (l); - dispose_words (l); + temp1 = parameter_brace_substring (name, temp, value, quoted); + FREE (name); + FREE (value); + FREE (temp); + return (temp1); } - else if (name[1] != '*' && name[1] != '@') + else if (want_patsub) { - number = 0; + temp1 = parameter_brace_patsub (name, temp, value, quoted); + FREE (name); + FREE (value); + FREE (temp); + return (temp1); + } - if (digit (name[1])) /* ${#1} */ - { - if (t = get_dollar_var_value (atoi (name + 1))) - { - number = strlen (t); - free (t); - } + /* Do the right thing based on which character ended the variable name. */ + switch (c) + { + default: + case '\0': + bad_substitution: + report_error ("%s: bad substitution", string ? string : "??"); + FREE (value); + FREE (temp); + free (name); + return &expand_param_error; + + /*{*/ + case '}': + if (var_is_set == 0 && unbound_vars_is_error) + { + report_error ("%s: unbound variable", name); + FREE (value); + FREE (temp); + free (name); + last_command_exit_value = EXECUTION_FAILURE; + return &expand_param_error; } - else /* ${#PS1} */ - { - WORD_LIST *list; - char *newname; - - newname = savestring (name); - newname[0] = '$'; - list = expand_string (newname, 0); - t = string_list (list); - free (newname); - dispose_words (list); - - if (t) - number = strlen (t); + break; - FREE (t); + case '#': /* ${param#[#]pattern} */ + case '%': /* ${param%[%]pattern} */ + if (value == 0 || *value == '\0' || temp == 0 || *temp == '\0') + { + FREE (value); + break; + } + if ((name[0] == '@' || name[0] == '*') && name[1] == '\0') + temp1 = parameter_list_remove_pattern (value, name[0], c, quoted); +#if defined (ARRAY_VARS) + else if (valid_array_reference (name)) + temp1 = array_remove_pattern (value, name, temp, c, quoted); +#endif + else + temp1 = parameter_brace_remove_pattern (value, temp, c, quoted); + free (temp); + free (value); + temp = temp1; + break; + + case '-': + case '=': + case '?': + case '+': + if (var_is_set && var_is_null == 0) + { + /* We don't want the value of the named variable for + anything, just the value of the right hand side. */ + if (c == '+') + { + FREE (temp); + if (value) + { + temp = parameter_brace_expand_rhs (name, value, c, + quoted, + quoted_dollar_atp, + contains_dollar_at); + free (value); + } + else + temp = (char *)NULL; + } + else + { + FREE (value); + } + /* Otherwise do nothing; just use the value in TEMP. */ } - } - else /* ${#@} and ${#*} */ - { -#if !defined (KSH_INCOMPATIBLE) - WORD_LIST *l = list_rest_of_args (); - number = l ? list_length (l) : 0; - dispose_words (l); -#else - if (t = string_rest_of_args (1)) - { - number = strlen (t); - free (t); + else /* VAR not set or VAR is NULL. */ + { + FREE (temp); + temp = (char *)NULL; + if (c == '=' && var_is_special) + { + report_error ("$%s: cannot assign in this way", name); + free (name); + free (value); + return &expand_param_error; + } + else if (c == '?') + { + parameter_brace_expand_error (name, value); + return (interactive ? &expand_param_error : &expand_param_fatal); + } + else if (c != '+') + temp = parameter_brace_expand_rhs (name, value, c, quoted, + quoted_dollar_atp, + contains_dollar_at); + free (value); } -#endif /* KSH_INCOMPATIBLE */ + break; } - return (number); + free (name); + return (temp); } /* Make a word list which is the parameter and variable expansion, @@ -2628,8 +4092,8 @@ parameter_brace_expand_length (name) result of the expansion. If WORD contains a null word, the word list returned is also null. - QUOTED, when non-zero specifies that the text of WORD is treated - as if it were surrounded by double quotes. + QUOTED contains flag values defined in shell.h. + CONTAINS_DOLLAR_AT and EXPANDED_SOMETHING are return values; when non-null they point to an integer value which receives information about expansion. CONTAINS_DOLLAR_AT gets non-zero if WORD contained "$@", else zero. @@ -2651,50 +4115,58 @@ expand_word_internal (word, quoted, contains_dollar_at, expanded_something) int *contains_dollar_at; int *expanded_something; { - /* The thing that we finally output. */ - WORD_LIST *result = (WORD_LIST *)NULL; + WORD_LIST *list; + WORD_DESC *tword; + SHELL_VAR *var; /* The intermediate string that we build while expanding. */ - char *istring = xmalloc (DEFAULT_ARRAY_SIZE); + char *istring; /* The current size of the above object. */ - int istring_size = DEFAULT_ARRAY_SIZE; + int istring_size; /* Index into ISTRING. */ - int istring_index = 0; + int istring_index; /* Temporary string storage. */ - char *temp = (char *)NULL; + char *temp, *temp1; /* The text of WORD. */ - register char *string = word->word; + register char *string; /* The index into STRING. */ - int sindex = 0; + int sindex; /* This gets 1 if we see a $@ while quoted. */ - int quoted_dollar_at = 0; + int quoted_dollar_at; /* One of UNQUOTED, PARTIALLY_QUOTED, or WHOLLY_QUOTED, depending on whether WORD contains no quoting characters, a partially quoted string (e.g., "xx"ab), or is fully quoted (e.g., "xxab"). */ - int quoted_state = UNQUOTED; + int quoted_state; + + int had_quoted_null; register int c; /* Current character. */ int number; /* Temporary number value. */ int t_index; /* For calls to string_extract_xxx. */ - char *command_subst_result; /* For calls to command_substitute (). */ - istring[0] = '\0'; + istring = xmalloc (istring_size = DEFAULT_ARRAY_SIZE); + istring[istring_index = 0] = '\0'; - if (!string) goto final_exit; + quoted_dollar_at = had_quoted_null = 0; + quoted_state = UNQUOTED; + + string = word->word; + if (string == 0) + goto finished_with_string; if (contains_dollar_at) *contains_dollar_at = 0; /* Begin the expansion. */ - for (;;) + for (sindex = 0; ;) { c = string[sindex]; @@ -2720,26 +4192,22 @@ expand_word_internal (word, quoted, contains_dollar_at, expanded_something) case '<': case '>': { - char *temp1; - int old_index; - - if (string[++sindex] != '(' || quoted || posixly_correct) + if (string[++sindex] != '(' || (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || posixly_correct) { sindex--; goto add_character; } else - old_index = ++sindex; /* skip past both '<' and '(' */ + t_index = sindex + 1; /* skip past both '<' and '(' */ - temp1 = extract_process_subst - (string, (c == '<') ? "<(" : ">(", &old_index); - sindex = old_index; + temp1 = extract_process_subst (string, (c == '<') ? "<(" : ">(", &t_index); + sindex = t_index; /* If the process substitution specification is `<()', we want to open the pipe for writing in the child and produce output; if it is `>()', we want to open the pipe for reading in the child and consume input. */ - temp = process_substitute (temp1, (c == '>')); + temp = temp1 ? process_substitute (temp1, (c == '>')) : (char *)0; FREE (temp1); @@ -2776,17 +4244,16 @@ expand_word_internal (word, quoted, contains_dollar_at, expanded_something) case '7': case '8': case '9': - temp = dollar_vars[digit_value (c)]; - if (unbound_vars_is_error && temp == (char *)NULL) + temp1 = dollar_vars[digit_value (c)]; + if (unbound_vars_is_error && temp1 == (char *)NULL) { report_error ("$%c: unbound variable", c); free (string); free (istring); - last_command_exit_value = 1; + last_command_exit_value = EXECUTION_FAILURE; return (&expand_word_error); } - if (temp) - temp = savestring (temp); + temp = temp1 ? savestring (temp1) : (char *)NULL; goto dollar_add_string; /* $$ -- pid of the invoking shell. */ @@ -2800,19 +4267,19 @@ expand_word_internal (word, quoted, contains_dollar_at, expanded_something) /* Add TEMP to ISTRING. */ add_string: - istring = sub_append_string - (temp, istring, &istring_index, &istring_size); - temp = (char *)NULL; + if (temp) + { + istring = sub_append_string + (temp, istring, &istring_index, &istring_size); + temp = (char *)0; + } + break; /* $# -- number of positional parameters. */ case '#': - { - WORD_LIST *list = list_rest_of_args (); - number = list_length (list); - dispose_words (list); - goto add_number; - } + number = number_of_args (); + goto add_number; /* $? -- return value of the last synchronous command. */ case '?': @@ -2829,7 +4296,8 @@ expand_word_internal (word, quoted, contains_dollar_at, expanded_something) case '!': number = (int)last_asynchronous_pid; - /* If no asynchronous pids have been created, echo nothing. */ + /* If no asynchronous pids have been created, expand + to nothing. */ if (number == (int)NO_PID) { if (string[sindex]) @@ -2845,19 +4313,23 @@ expand_word_internal (word, quoted, contains_dollar_at, expanded_something) case '*': /* `$*' */ temp = string_rest_of_args (quoted); - if (quoted && temp && *temp == '\0' /* && istring_index > 0 */) + /* If there are no command-line arguments, this should just + disappear if there are other characters in the expansion, + even if it's quoted. */ + if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && temp && *temp == '\0') { free (temp); temp = (char *)NULL; } - /* In the case of a quoted string, quote the entire arg-list. - "$1 $2 $3". */ - if (quoted && temp) + "$1 $2 $3". Otherwise quote the special escape characters. */ + if (temp) { - char *james_brown = temp; - temp = quote_string (temp); - free (james_brown); + temp1 = temp; + temp = (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) + ? quote_string (temp) + : quote_escapes (temp); + free (temp1); } goto dollar_add_string; @@ -2866,432 +4338,173 @@ expand_word_internal (word, quoted, contains_dollar_at, expanded_something) the individually quoted arguments so that the final split on the first character of $IFS is still done. */ case '@': /* `$@' */ - { - WORD_LIST *tlist = list_rest_of_args (); - if (quoted && tlist) - quote_list (tlist); - - /* We want to flag the fact that we saw this. We can't turn - off quoting entirely, because other characters in the - string might need it (consider "\"$@\""), but we need some - way to signal that the final split on the first character - of $IFS should be done, even though QUOTED is 1. */ - if (quoted) - quoted_dollar_at = 1; - if (contains_dollar_at) - *contains_dollar_at = 1; - temp = string_list (tlist); - dispose_words (tlist); - goto dollar_add_string; - } + list = list_rest_of_args (); + + /* We want to flag the fact that we saw this. We can't turn + off quoting entirely, because other characters in the + string might need it (consider "\"$@\""), but we need some + way to signal that the final split on the first character + of $IFS should be done, even though QUOTED is 1. */ + if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) + quoted_dollar_at = 1; + if (contains_dollar_at) + *contains_dollar_at = 1; + temp = string_list (((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && list) ? quote_list (list) : list); + /* If the expansion is not quoted, protect any special escape + characters in the expansion by quoting them. */ + if (temp && quoted == 0) + { + temp1 = temp; + temp = quote_escapes (temp); + free (temp1); + } + dispose_words (list); + goto dollar_add_string; - /* ${[#]name[[:]#[#]%[%]-=?+[word]]} */ - case '{': - { - int check_nullness = 0; - int var_is_set = 0; - int var_is_null = 0; - int var_is_special = 0; - char *name, *value; - - t_index = ++sindex; - name = string_extract (string, &t_index, "#%:-=?+}"); - value = (char *)NULL; - - /* If the name really consists of a special variable, then - make sure that we have the entire name. */ - if (sindex == t_index && - (string[sindex] == '-' || - string[sindex] == '?' || - string[sindex] == '#')) - { - char *tt; - t_index++; - free (name); - tt = string_extract (string, &t_index, "#%:-=?+}"); - name = xmalloc (2 + (strlen (tt))); - *name = string[sindex]; - strcpy (name + 1, tt); - free (tt); - } - sindex = t_index; - - /* Find out what character ended the variable name. Then - do the appropriate thing. */ - if (c = string[sindex]) - sindex++; - - if (c == ':') - { - check_nullness++; - if (c = string[sindex]) - sindex++; - } - - /* Determine the value of this variable. */ - if ((digit (*name) && all_digits (name)) || - (strlen (name) == 1 && member (*name, "#-?$!@*"))) - var_is_special++; - - /* Check for special expansion things. */ - if (*name == '#') - { - /* Handle ${#-} and ${#?}. They return the lengths of - $- and $?, respectively. */ - if (string[sindex] == '}' && - !name[1] && - !check_nullness && - (c == '-' || c == '?')) - { - char *s; - - free (name); - - if (c == '-') - s = which_set_flags (); - else - s = itos (last_command_exit_value); - - number = STRLEN (s); - FREE (s); - goto add_number; - } - - /* Don't allow things like ${#:-foo} to go by; they are - errors. If we are not pointing at the character just - after the closing brace, then we haven't gotten all of - the name. Since it begins with a special character, - this is a bad substitution. Explicitly check for ${#:}, - which the rules do not catch. */ - if (string[sindex - 1] != '}' || member (c, "?-=+") || - (string[sindex - 1] == '}' && !name[1] && c == '}' && - check_nullness)) - { - free (name); - name = string; - goto bad_substitution; - } - - /* Check NAME for validity before trying to go on. */ - if (!valid_length_expression (name)) - { - free (name); - name = string; - goto bad_substitution; - } - - number = parameter_brace_expand_length (name); - free (name); - /* We are pointing one character after the brace which - closes this expression. Since the code at add_number - increments SINDEX, we back up a single character. */ - sindex--; - goto add_number; - } - - /* ${@} is identical to $@. */ - if (name[0] == '@' && name[1] == '\0') - { - if (quoted) - quoted_dollar_at = 1; - - if (contains_dollar_at) - *contains_dollar_at = 1; - } - - /* Make sure that NAME is valid before trying to go on. */ - if (!valid_brace_expansion_word (name, var_is_special)) - { - free (name); - name = string; - goto bad_substitution; - } - - temp = - parameter_brace_expand_word (name, var_is_special, quoted); - - if (temp) - var_is_set++; - - if (!var_is_set || !temp || !*temp) - var_is_null++; - - if (!check_nullness) - var_is_null = 0; - - /* Get the rest of the stuff inside the braces. */ - if (c && c != '}') - { - /* Extract the contents of the ${ ... } expansion - according to the Posix.2 rules. It's much less of - a hack that the former extract_delimited_string () - scheme. */ - value = extract_dollar_brace_string (string, &sindex); - - if (string[sindex] == '}') - sindex++; - else - { - free (name); - name = string; - goto bad_substitution; - } - } - else - value = (char *)NULL; - - /* Do the right thing based on which character ended the - variable name. */ - switch (c) - { - default: - free (name); - name = string; - /* FALL THROUGH */ - - case '\0': - bad_substitution: - report_error ("%s: bad substitution", name ? name : "??"); - FREE (value); - free (temp); - free (name); - free (istring); - return &expand_word_error; - - case '}': - if (!var_is_set && unbound_vars_is_error) - { - report_error ("%s: unbound variable", name); - FREE (value); - free (temp); - free (name); - free (string); - last_command_exit_value = 1; - free (istring); - return &expand_word_error; - } - break; - - case '#': /* ${param#[#]pattern} */ - case '%': /* ${param%[%]pattern} */ - { - char *t; - if (!value || !*value || !temp || !*temp) - break; - if (quoted) - { - t = dequote_string (temp); - free (temp); - temp = t; - } - t = parameter_brace_remove_pattern (value, temp, c); - free (temp); - free (value); - temp = t; - } - break; - - case '-': - case '=': - case '?': - case '+': - if (var_is_set && !var_is_null) - { - /* We don't want the value of the named variable for - anything, just the value of the right hand side. */ - if (c == '+') - { - FREE (temp); - if (value) - { - temp = parameter_brace_expand_rhs - (name, value, c, quoted); - /* XXX - this is a hack. A better fix is - coming later. */ - if ((value[0] == '$' && value[1] == '@') || - (value[0] == '"' && value[1] == '$' && value[2] == '@')) - { - if (quoted) - quoted_dollar_at++; - if (contains_dollar_at) - *contains_dollar_at = 1; - } - free (value); - } - else - temp = (char *)NULL; - } - else - { - FREE (value); - } - /* Otherwise do nothing; just use the value in TEMP. */ - } - else /* VAR not set or VAR is NULL. */ - { - FREE (temp); - temp = (char *)NULL; - if (c == '=' && var_is_special) - { - report_error - ("$%s: cannot assign in this way", name); - free (name); - free (value); - free (string); - free (istring); - return &expand_word_error; - } - else if (c == '?') - { - free (string); - free (istring); - parameter_brace_expand_error (name, value); - if (!interactive) - return &expand_word_fatal; - else - return &expand_word_error; - } - else if (c != '+') - temp = parameter_brace_expand_rhs - (name, value, c, quoted); - free (value); - } - break; - } /* end case on closing character. */ - free (name); - goto add_string; - } /* end case '{' */ + case '{': /*}*/ + temp = parameter_brace_expand (string, &sindex, quoted, + "ed_dollar_at, + contains_dollar_at); + if (temp == &expand_param_error || temp == &expand_param_fatal) + { + free (string); + free (istring); + return (temp == &expand_param_error) ? &expand_word_error + : &expand_word_fatal; + } + /* XXX */ + /* quoted nulls should be removed if there is anything else + in the string. */ + /* Note that we saw the quoted null so we can add one back at + the end of this function if there are no other characters + in the string, discard TEMP, and go on. */ + if (temp && QUOTED_NULL (temp)) + { + had_quoted_null = 1; + free (temp); + break; + } + + goto add_string; /* break; */ /* Do command or arithmetic substitution. */ - case '(': + case '(': /*)*/ /* We have to extract the contents of this paren substitution. */ - { - int old_index = ++sindex; - - temp = extract_command_subst (string, &old_index); - sindex = old_index; - - /* For Posix.2-style `$(( ))' arithmetic substitution, - extract the expression and pass it to the evaluator. */ - if (temp && *temp == '(') - { - char *t = temp + 1; - int last = strlen (t) - 1; - - if (t[last] != ')') - { - report_error ("%s: bad arithmetic substitution", temp); - free (temp); - free (string); - free (istring); - return &expand_word_error; - } - - /* Cut off ending `)' */ - t[last] = '\0'; - - /* Expand variables found inside the expression. */ - { - WORD_LIST *l; + t_index = sindex + 1; + temp = extract_command_subst (string, &t_index); + sindex = t_index; - l = expand_string (t, 1); - t = string_list (l); - dispose_words (l); + /* For Posix.2-style `$(( ))' arithmetic substitution, + extract the expression and pass it to the evaluator. */ + if (temp && *temp == '(') + { + temp1 = temp + 1; + t_index = strlen (temp1) - 1; + + if (temp1[t_index] != ')') + { + report_error ("%s: bad arithmetic substitution", temp); + free (temp); + free (string); + free (istring); + return &expand_word_error; } - /* No error messages. */ - this_command_name = (char *)NULL; + /* Cut off ending `)' */ + temp1[t_index] = '\0'; - number = evalexp (t); - free (temp); - free (t); + /* Expand variables found inside the expression. */ + temp1 = maybe_expand_string (temp1, 1, expand_string); - goto add_number; - } + /* No error messages. */ + this_command_name = (char *)NULL; + number = evalexp (temp1); + free (temp); + free (temp1); - goto handle_command_substitution; - } + goto add_number; + } + + temp1 = command_substitute (temp, quoted); + FREE (temp); + temp = temp1; + goto dollar_add_string; /* Do straight arithmetic substitution. */ case '[': /* We have to extract the contents of this arithmetic substitution. */ - { - char *t; - int old_index = ++sindex; - WORD_LIST *l; + t_index = sindex + 1; + temp = extract_arithmetic_subst (string, &t_index); + sindex = t_index; - temp = extract_arithmetic_subst (string, &old_index); - sindex = old_index; + /* Do initial variable expansion. */ + temp1 = maybe_expand_string (temp, 1, expand_string); - /* Do initial variable expansion. */ - l = expand_string (temp, 1); - t = string_list (l); - dispose_words (l); + /* No error messages. */ + this_command_name = (char *)NULL; + number = evalexp (temp1); + free (temp1); + free (temp); - /* No error messages. */ - this_command_name = (char *)NULL; - number = evalexp (t); - free (t); - free (temp); - - goto add_number; - } + goto add_number; default: - { - /* Find the variable in VARIABLE_LIST. */ - int old_index; - char *name; - SHELL_VAR *var; - - temp = (char *)NULL; - - for (old_index = sindex; - (c = string[sindex]) && - (isletter (c) || digit (c) || c == '_'); - sindex++); - name = substring (string, old_index, sindex); - - /* If this isn't a variable name, then just output the `$'. */ - if (!name || !*name) - { - FREE (name); - temp = savestring ("$"); - if (expanded_something) - *expanded_something = 0; - goto add_string; - } - - /* If the variable exists, return its value cell. */ - var = find_variable (name); - - if (var && !invisible_p (var) && value_cell (var)) - { - temp = value_cell (var); - temp = quoted && temp && *temp ? quote_string (temp) - : quote_escapes (temp); - free (name); - goto add_string; - } - else - temp = (char *)NULL; + /* Find the variable in VARIABLE_LIST. */ + temp = (char *)NULL; - if (unbound_vars_is_error) - report_error ("%s: unbound variable", name); - else - { - free (name); - goto add_string; - } - - free (name); - free (string); - last_command_exit_value = 1; - free (istring); - return &expand_word_error; - } + for (t_index = sindex; + (c = string[sindex]) && legal_variable_char (c); + sindex++); + temp1 = substring (string, t_index, sindex); + + /* If this isn't a variable name, then just output the `$'. */ + if (temp1 == 0 || *temp1 == '\0') + { + FREE (temp1); + temp = xmalloc (2); + temp[0] = '$'; + temp[1] = '\0'; + if (expanded_something) + *expanded_something = 0; + goto add_string; + } + + /* If the variable exists, return its value cell. */ + var = find_variable (temp1); + + if (var && invisible_p (var) == 0 && value_cell (var)) + { +#if defined (ARRAY_VARS) + if (array_p (var)) + { + temp = array_reference (array_cell (var), 0); + if (temp) + temp = quote_escapes (temp); + } + else +#endif + temp = quote_escapes (value_cell (var)); + free (temp1); + goto add_string; + } + + temp = (char *)NULL; + + if (unbound_vars_is_error) + report_error ("%s: unbound variable", temp1); + else + { + free (temp1); + goto add_string; + } + + free (temp1); + free (string); + last_command_exit_value = EXECUTION_FAILURE; + free (istring); + return &expand_word_error; } break; /* End case '$': */ @@ -3302,20 +4515,12 @@ expand_word_internal (word, quoted, contains_dollar_at, expanded_something) if (expanded_something) *expanded_something = 1; - temp = string_extract (string, &sindex, "`"); + temp = string_extract (string, &sindex, "`", 0); de_backslash (temp); - - handle_command_substitution: - command_subst_result = command_substitute (temp, quoted); - + temp1 = command_substitute (temp, quoted); FREE (temp); - - temp = command_subst_result; - - if (string[sindex]) - sindex++; - - goto add_string; + temp = temp1; + goto dollar_add_string; } case '\\': @@ -3324,215 +4529,193 @@ expand_word_internal (word, quoted, contains_dollar_at, expanded_something) sindex += 2; continue; } + + c = string[++sindex]; + + if (quoted & Q_HERE_DOCUMENT) + temp1 = slashify_in_here_document; + else if (quoted & Q_DOUBLE_QUOTES) + temp1 = slashify_in_quotes; + else + temp1 = ""; + + if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && member (c, temp1) == 0) + { + temp = xmalloc (3); + temp[0] = '\\'; temp[1] = c; temp[2] = '\0'; + } else + /* This character is quoted, so add it in quoted mode. */ + temp = make_quoted_char (c); + + if (c) + sindex++; + goto add_string; + + case '"': + if (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT|Q_NOQUOTE)) + goto add_character; + + t_index = ++sindex; + temp = string_extract_double_quoted (string, &sindex, 0); + + /* If the quotes surrounded the entire string, then the + whole word was quoted. */ + quoted_state = (t_index == 1 && string[sindex] == '\0') + ? WHOLLY_QUOTED + : PARTIALLY_QUOTED; + + if (temp && *temp) { - char *slashify_chars = ""; + int dollar_at_flag; + + tword = make_word (temp); /* XXX */ + free (temp); + temp = (char *)NULL; + + list = expand_word_internal (tword, Q_DOUBLE_QUOTES, &dollar_at_flag, (int *)NULL); - c = string[++sindex]; + if (list == &expand_word_error || list == &expand_word_fatal) + { + free (istring); + free (string); + /* expand_word_internal has already freed temp_word->word + for us because of the way it prints error messages. */ + tword->word = (char *)NULL; + dispose_word (tword); + return list; + } - if (quoted == Q_HERE_DOCUMENT) - slashify_chars = slashify_in_here_document; - else if (quoted == Q_DOUBLE_QUOTES) - slashify_chars = slashify_in_quotes; + dispose_word (tword); - if (quoted && !member (c, slashify_chars)) + /* "$@" (a double-quoted dollar-at) expands into nothing, + not even a NULL word, when there are no positional + parameters. */ + if (list == 0 && dollar_at_flag) { - temp = xmalloc (3); - temp[0] = '\\'; temp[1] = c; temp[2] = '\0'; - if (c) - sindex++; + quoted_dollar_at++; + break; + } + + /* If we get "$@", we know we have expanded something, so we + need to remember it for the final split on $IFS. This is + a special case; it's the only case where a quoted string + can expand into more than one word. It's going to come back + from the above call to expand_word_internal as a list with + a single word, in which all characters are quoted and + separated by blanks. What we want to do is to turn it back + into a list for the next piece of code. */ + if (list) + dequote_list (list); + + if (dollar_at_flag) + { + quoted_dollar_at++; + if (contains_dollar_at) + *contains_dollar_at = 1; + if (expanded_something) + *expanded_something = 1; + } + } + else + { + /* What we have is "". This is a minor optimization. */ + free (temp); + list = (WORD_LIST *)NULL; + } + + /* The code above *might* return a list (consider the case of "$@", + where it returns "$1", "$2", etc.). We can't throw away the + rest of the list, and we have to make sure each word gets added + as quoted. We test on tresult->next: if it is non-NULL, we + quote the whole list, save it to a string with string_list, and + add that string. We don't need to quote the results of this + (and it would be wrong, since that would quote the separators + as well), so we go directly to add_string. */ + if (list) + { + if (list->next) + { + temp = string_list (quote_list (list)); + dispose_words (list); goto add_string; } else { - /* This character is quoted, so add it in quoted mode. */ - temp = make_quoted_char (c); - if (c) - sindex++; - goto add_string; + temp = savestring (list->word->word); + dispose_words (list); } } + else + temp = (char *)NULL; - case '"': - if (quoted) - goto add_character; - sindex++; - { - WORD_LIST *tresult = (WORD_LIST *)NULL; - - t_index = sindex; - temp = string_extract_double_quoted (string, &sindex); + /* We do not want to add quoted nulls to strings that are only + partially quoted; we can throw them away. */ + if (temp == 0 && quoted_state == PARTIALLY_QUOTED) + { + FREE (temp); + continue; + } - /* If the quotes surrounded the entire string, then the - whole word was quoted. */ - if (t_index == 1 && !string[sindex]) - quoted_state = WHOLLY_QUOTED; - else - quoted_state = PARTIALLY_QUOTED; + add_quoted_string: - if (temp && *temp) - { - int dollar_at_flag; - int quoting_flags = Q_DOUBLE_QUOTES; - WORD_DESC *temp_word = make_word (temp); - - free (temp); - - tresult = expand_word_internal - (temp_word, quoting_flags, &dollar_at_flag, (int *)NULL); - - if (tresult == &expand_word_error || tresult == &expand_word_fatal) - { - free (istring); - free (string); - /* expand_word_internal has already freed temp_word->word - for us because of the way it prints error messages. */ - temp_word->word = (char *)NULL; - dispose_word (temp_word); - return tresult; - } - - dispose_word (temp_word); - - /* "$@" (a double-quoted dollar-at) expands into nothing, - not even a NULL word, when there are no positional - parameters. */ - if (!tresult && dollar_at_flag) - { - quoted_dollar_at++; - break; - } - - /* If we get "$@", we know we have expanded something, so we - need to remember it for the final split on $IFS. This is - a special case; it's the only case where a quoted string - can expand into more than one word. It's going to come back - from the above call to expand_word_internal as a list with - a single word, in which all characters are quoted and - separated by blanks. What we want to do is to turn it back - into a list for the next piece of code. */ - dequote_list (tresult); - - if (dollar_at_flag) - { - quoted_dollar_at++; - if (expanded_something) - *expanded_something = 1; - } - } - else - { - /* What we have is "". This is a minor optimization. */ - free (temp); - tresult = (WORD_LIST *)NULL; - } + if (temp) + { + temp1 = temp; + temp = quote_string (temp); + free (temp1); + } + else + { + /* Add NULL arg. */ + temp = xmalloc (2); + temp[0] = CTLNUL; + temp[1] = '\0'; + } + goto add_string; + /* break; */ - /* The code above *might* return a list (consider the case of "$@", - where it returns "$1", "$2", etc.). We can't throw away the - rest of the list, and we have to make sure each word gets added - as quoted. We test on tresult->next: if it is non-NULL, we - quote the whole list, save it to a string with string_list, and - add that string. We don't need to quote the results of this - (and it would be wrong, since that would quote the separators - as well), so we go directly to add_string. */ - if (tresult) - { - if (tresult->next) - { - quote_list (tresult); - temp = string_list (tresult); - dispose_words (tresult); - goto add_string; - } - else - { - temp = savestring (tresult->word->word); - dispose_words (tresult); - } - } - else - temp = (char *)NULL; + case '\'': + if (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT|Q_NOQUOTE)) + goto add_character; - /* We do not want to add quoted nulls to strings that are only - partially quoted; we can throw them away. */ - if (!temp && (quoted_state == PARTIALLY_QUOTED)) - continue; + t_index = ++sindex; + temp = string_extract_single_quoted (string, &sindex); - add_quoted_string: + /* If the entire STRING was surrounded by single quotes, + then the string is wholly quoted. */ + quoted_state = (t_index == 1 && string[sindex] == '\0') + ? WHOLLY_QUOTED + : PARTIALLY_QUOTED; - if (temp) - { - char *t = temp; - temp = quote_string (temp); - free (t); - } - else - { - /* Add NULL arg. */ - temp = xmalloc (2); - temp[0] = CTLNUL; - temp[1] = '\0'; - } - goto add_string; - } - /* break; */ + /* If all we had was '', it is a null expansion. */ + if (*temp == '\0') + { + free (temp); + temp = (char *)NULL; + } + else + remove_quoted_escapes (temp); - case '\'': - { - if (!quoted) - { - sindex++; - - t_index = sindex; - temp = string_extract_single_quoted (string, &sindex); - - /* If the entire STRING was surrounded by single quotes, - then the string is wholly quoted. */ - if (t_index == 1 && !string[sindex]) - quoted_state = WHOLLY_QUOTED; - else - quoted_state = PARTIALLY_QUOTED; - - /* If all we had was '', it is a null expansion. */ - if (!*temp) - { - free (temp); - temp = (char *)NULL; - } - else - remove_quoted_escapes (temp); - - /* We do not want to add quoted nulls to strings that are only - partially quoted; such nulls are discarded. */ - if (!temp && (quoted_state == PARTIALLY_QUOTED)) - continue; - - goto add_quoted_string; - } - else - goto add_character; + /* We do not want to add quoted nulls to strings that are only + partially quoted; such nulls are discarded. */ + if (temp == 0 && (quoted_state == PARTIALLY_QUOTED)) + continue; - break; - } + goto add_quoted_string; + /* break; */ default: - /* This is the fix for " $@ " */ - if (quoted) + if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) { temp = make_quoted_char (c); - if (string[sindex]) - sindex++; - goto add_string; + goto dollar_add_string; } add_character: - if (istring_index + 1 >= istring_size) - { - while (istring_index + 1 >= istring_size) - istring_size += DEFAULT_ARRAY_SIZE; - istring = xrealloc (istring, istring_size); - } + RESIZE_MALLOCED_BUFFER (istring, istring_index, 1, istring_size, + DEFAULT_ARRAY_SIZE); istring[istring_index++] = c; istring[istring_index] = '\0'; @@ -3542,100 +4725,98 @@ expand_word_internal (word, quoted, contains_dollar_at, expanded_something) } finished_with_string: -final_exit: /* OK, we're ready to return. If we have a quoted string, and quoted_dollar_at is not set, we do no splitting at all; otherwise we split on ' '. The routines that call this will handle what to do if nothing has been expanded. */ - if (istring) - { - WORD_LIST *temp_list; - - /* Partially and wholly quoted strings which expand to the empty - string are retained as an empty arguments. Unquoted strings - which expand to the empty string are discarded. The single - exception is the case of expanding "$@" when there are no - positional parameters. In that case, we discard the expansion. */ - - /* Because of how the code that handles "" and '' in partially - quoted strings works, we need to make ISTRING into a QUOTED_NULL - if we saw quoting characters, but the expansion was empty. - "" and '' are tossed away before we get to this point when - processing partially quoted strings. This makes "" and $xxx"" - equivalent when xxx is unset. */ - if (!*istring && quoted_state == PARTIALLY_QUOTED) + + /* Partially and wholly quoted strings which expand to the empty + string are retained as an empty arguments. Unquoted strings + which expand to the empty string are discarded. The single + exception is the case of expanding "$@" when there are no + positional parameters. In that case, we discard the expansion. */ + + /* Because of how the code that handles "" and '' in partially + quoted strings works, we need to make ISTRING into a QUOTED_NULL + if we saw quoting characters, but the expansion was empty. + "" and '' are tossed away before we get to this point when + processing partially quoted strings. This makes "" and $xxx"" + equivalent when xxx is unset. We also look to see whether we + saw a quoted null from a ${} expansion and add one back if we + need to. */ + + /* If we expand to nothing and there were no single or double quotes + in the word, we throw it away. Otherwise, we return a NULL word. + The single exception is for $@ surrounded by double quotes when + there are no positional parameters. In that case, we also throw + the word away. */ + + if (*istring == '\0') + { + if (quoted_dollar_at == 0 && (had_quoted_null || quoted_state == PARTIALLY_QUOTED)) { - if (istring_size < 2) - istring = xrealloc (istring, istring_size += 2); istring[0] = CTLNUL; istring[1] = '\0'; + tword = make_bare_word (istring); + list = make_word_list (tword, (WORD_LIST *)NULL); + if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) + tword->flags |= W_QUOTED; } - - /* If we expand to nothing and there were no single or double quotes - in the word, we throw it away. Otherwise, we return a NULL word. - The single exception is for $@ surrounded by double quotes when - there are no positional parameters. In that case, we also throw - the word away. */ - if (!*istring) + /* According to sh, ksh, and Posix.2, if a word expands into nothing + and a double-quoted "$@" appears anywhere in it, then the entire + word is removed. */ + else if (quoted_state == UNQUOTED || quoted_dollar_at) + list = (WORD_LIST *)NULL; +#if 0 + else { - if (quoted_state == UNQUOTED || - (quoted_dollar_at && quoted_state == WHOLLY_QUOTED)) - temp_list = (WORD_LIST *)NULL; - else - { - temp_list = make_word_list - (make_word (istring), (WORD_LIST *)NULL); - temp_list->word->quoted = quoted; - } + tword = make_bare_word (istring); + list = make_word_list (tword, (WORD_LIST *)NULL); + if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) + tword->flags |= W_QUOTED; } - else if (word->assignment) +#endif + } + else if (word->flags & W_NOSPLIT) + { + tword = make_bare_word (istring); + list = make_word_list (tword, (WORD_LIST *)NULL); + if (word->flags & W_ASSIGNMENT) + tword->flags |= W_ASSIGNMENT; /* XXX */ + if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) + tword->flags |= W_QUOTED; + } + else + { + char *ifs_chars; + + if (quoted_dollar_at) { - temp_list = make_word_list (make_word (istring), (WORD_LIST *)NULL); - temp_list->word->quoted = quoted; - temp_list->word->assignment = assignment (temp_list->word->word); + var = find_variable ("IFS"); + ifs_chars = var ? value_cell (var) : " \t\n"; } else - { - char *ifs_chars = (char *)NULL; - - if (quoted_dollar_at) - { - SHELL_VAR *ifs = find_variable ("IFS"); - if (ifs) - ifs_chars = value_cell (ifs); - else - ifs_chars = " \t\n"; - } + ifs_chars = (char *)NULL; - /* According to Posix.2, "$@" expands to a single word if - IFS="" and the positional parameters are not empty. */ - if (quoted_dollar_at && ifs_chars && *ifs_chars) - { - temp_list = list_string (istring, " ", 1); -#if 0 - /* This turns quoted null strings back into CTLNULs */ - dequote_list (temp_list); - quote_list (temp_list); -#endif - } - else - { - WORD_DESC *tword; - tword = make_word (istring); - temp_list = make_word_list (tword, (WORD_LIST *)NULL); - tword->quoted = quoted || (quoted_state == WHOLLY_QUOTED); - tword->assignment = word->assignment; - } + /* According to Posix.2, "$@" expands to a single word if + IFS="" and the positional parameters are not empty. */ + if (quoted_dollar_at && ifs_chars && *ifs_chars) + { + list = list_string (istring, " ", 1); + } + else + { + tword = make_bare_word (istring); + list = make_word_list (tword, (WORD_LIST *)NULL); + if ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) || (quoted_state == WHOLLY_QUOTED)) + tword->flags |= W_QUOTED; + if (word->flags & W_ASSIGNMENT) + tword->flags |= W_ASSIGNMENT; } - - free (istring); - result = (WORD_LIST *) - list_append (REVERSE_LIST (result, WORD_LIST *), temp_list); } - else - result = (WORD_LIST *)NULL; - return (result); + free (istring); + return (list); } /* **************************************************************** */ @@ -3651,20 +4832,21 @@ string_quote_removal (string, quoted) char *string; int quoted; { - char *r, *result_string, *temp, *temp1; + char *r, *result_string, *temp; int sindex, tindex, c, dquote; /* The result can be no longer than the original string. */ r = result_string = xmalloc (strlen (string) + 1); - for (sindex = dquote = 0; c = string[sindex];) + for (dquote = sindex = 0; c = string[sindex];) { switch (c) { case '\\': c = string[++sindex]; - if ((quoted || dquote) && !member (c, slashify_in_quotes)) + if (((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || dquote) && member (c, slashify_in_quotes) == 0) *r++ = '\\'; + /* FALLTHROUGH */ default: *r++ = c; @@ -3672,24 +4854,21 @@ string_quote_removal (string, quoted) break; case '\'': - if (quoted || dquote) + if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || dquote) { *r++ = c; sindex++; + break; } - else + tindex = sindex + 1; + temp = string_extract_single_quoted (string, &tindex); + if (temp) { - tindex = ++sindex; - temp = string_extract_single_quoted (string, &tindex); - sindex = tindex; - - if (temp) - { - strcpy (r, temp); - r += strlen (r); - free (temp); - } + strcpy (r, temp); + r += strlen (r); + free (temp); } + sindex = tindex; break; case '"': @@ -3702,6 +4881,8 @@ string_quote_removal (string, quoted) return (result_string); } +#if 0 +/* UNUSED */ /* Perform quote removal on word WORD. This allocates and returns a new WORD_DESC *. */ WORD_DESC * @@ -3713,7 +4894,7 @@ word_quote_removal (word, quoted) char *t; t = string_quote_removal (word->word, quoted); - w = make_word (t); + w = make_bare_word (t); return (w); } @@ -3725,19 +4906,18 @@ word_list_quote_removal (list, quoted) WORD_LIST *list; int quoted; { - WORD_LIST *result = (WORD_LIST *)NULL, *t, *tresult; + WORD_LIST *result, *t, *tresult; - t = list; - while (t) + for (t = list, result = (WORD_LIST *)NULL; t; t = t->next) { tresult = (WORD_LIST *)xmalloc (sizeof (WORD_LIST)); tresult->word = word_quote_removal (t->word, quoted); tresult->next = (WORD_LIST *)NULL; result = (WORD_LIST *) list_append (result, tresult); - t = t->next; } return (result); } +#endif /* Return 1 if CHARACTER appears in an unquoted portion of STRING. Return 0 otherwise. */ @@ -3746,40 +4926,32 @@ unquoted_member (character, string) int character; char *string; { - int sindex, tindex, c; - char *temp; - - sindex = 0; + int sindex, c; - while (c = string[sindex]) + for (sindex = 0; c = string[sindex]; ) { if (c == character) return (1); switch (c) { - case '\\': - sindex++; - if (string[sindex]) - sindex++; - break; - - case '"': - case '\'': + default: + sindex++; + break; - tindex = ++sindex; - if (c == '"') - temp = string_extract_double_quoted (string, &tindex); - else - temp = string_extract_single_quoted (string, &tindex); - sindex = tindex; + case '\\': + sindex++; + if (string[sindex]) + sindex++; + break; - FREE (temp); - break; + case '\'': + sindex = skip_single_quoted (string, ++sindex); + break; - default: - sindex++; - break; + case '"': + sindex = skip_double_quoted (string, ++sindex); + break; } } return (0); @@ -3790,47 +4962,37 @@ static int unquoted_substring (substr, string) char *substr, *string; { - int sindex, tindex, c, sublen; - char *temp; + int sindex, c, sublen; - if (!substr || !*substr) + if (substr == 0 || *substr == '\0') return (0); sublen = strlen (substr); - sindex = 0; - - while (c = string[sindex]) + for (sindex = 0; c = string[sindex]; ) { if (STREQN (string + sindex, substr, sublen)) return (1); switch (c) { - case '\\': - sindex++; - - if (string[sindex]) - sindex++; - break; - - case '"': - case '\'': - - tindex = ++sindex; + case '\\': + sindex++; - if (c == '"') - temp = string_extract_double_quoted (string, &tindex); - else - temp = string_extract_single_quoted (string, &tindex); - sindex = tindex; + if (string[sindex]) + sindex++; + break; - FREE (temp); + case '\'': + sindex = skip_single_quoted (string, ++sindex); + break; - break; + case '"': + sindex = skip_double_quoted (string, ++sindex); + break; - default: - sindex++; - break; + default: + sindex++; + break; } } return (0); @@ -3850,36 +5012,23 @@ word_split (w) WORD_DESC *w; { WORD_LIST *result; + SHELL_VAR *ifs; + char *ifs_chars; if (w) { - SHELL_VAR *ifs = find_variable ("IFS"); - char *ifs_chars; - + ifs = find_variable ("IFS"); /* If IFS is unset, it defaults to " \t\n". */ - if (ifs) - ifs_chars = value_cell (ifs); - else - ifs_chars = " \t\n"; + ifs_chars = ifs ? value_cell (ifs) : " \t\n"; - if (w->quoted || !ifs_chars) + if ((w->flags & W_QUOTED) || !ifs_chars) ifs_chars = ""; -#ifdef NOT_YET_MAYBE_LATER - if (!*ifs) - { - /* No splitting done if word quoted or ifs set to "". */ - WORD_DESC *wtemp; - wtemp = make_word (w->word); - wtemp->quoted = w->quoted; - result = make_word_list (wtemp); - } - else -#endif - result = list_string (w->word, ifs_chars, w->quoted); + result = list_string (w->word, ifs_chars, w->flags & W_QUOTED); } else result = (WORD_LIST *)NULL; + return (result); } @@ -3889,14 +5038,12 @@ static WORD_LIST * word_list_split (list) WORD_LIST *list; { - WORD_LIST *result = (WORD_LIST *)NULL, *t, *tresult; + WORD_LIST *result, *t, *tresult; - t = list; - while (t) + for (t = list, result = (WORD_LIST *)NULL; t; t = t->next) { tresult = word_split (t->word); result = (WORD_LIST *) list_append (result, tresult); - t = t->next; } return (result); } @@ -3931,7 +5078,7 @@ separate_out_assignments (tlist) lp = list of words left after assignment statements skipped tlist = original list of words */ - while (lp && lp->word->assignment) + while (lp && (lp->word->flags & W_ASSIGNMENT)) { vp = lp; lp = lp->next; @@ -3955,7 +5102,7 @@ separate_out_assignments (tlist) return ((WORD_LIST *)NULL); /* ASSERT(tlist != NULL); */ - /* ASSERT(tlist->word->assignment == 0); */ + /* ASSERT((tlist->word->flags & W_ASSIGNMENT) == 0); */ /* If the -k option is in effect, we need to go through the remaining words, separate out the assignment words, and place them on VARLIST. */ @@ -3970,7 +5117,7 @@ separate_out_assignments (tlist) /* Loop postcondition: tlist == word list without assignment statements */ while (lp) { - if (lp->word->assignment) + if (lp->word->flags & W_ASSIGNMENT) { /* Found an assignment statement, add this word to end of varlist (vp). */ @@ -4006,7 +5153,7 @@ WORD_LIST * expand_words (list) WORD_LIST *list; { - return (expand_words_internal (list, 1)); + return (expand_word_list_internal (list, 1)); } /* Same as expand_words (), but doesn't hack variable or environment @@ -4015,33 +5162,30 @@ WORD_LIST * expand_words_no_vars (list) WORD_LIST *list; { - return (expand_words_internal (list, 0)); + return (expand_word_list_internal (list, 0)); } -/* Non-zero means to allow unmatched globbed filenames to expand to - a null file. */ -static int allow_null_glob_expansion = 0; - -/* The workhorse for expand_words () and expand_words_no_var (). +/* The workhorse for expand_words () and expand_words_no_vars (). First arg is LIST, a WORD_LIST of words. Second arg DO_VARS is non-zero if you want to do environment and variable assignments, else zero. This does all of the substitutions: brace expansion, tilde expansion, parameter expansion, command substitution, arithmetic expansion, - process substitution, word splitting, and pathname expansion. - Words with the `quoted' or `assignment' bits set, or for which no - expansion is done, do not undergo word splitting. Words with the - `assignment' but set do not undergo pathname expansion. */ + process substitution, word splitting, and pathname expansion. Words + with the W_QUOTED or W_NOSPLIT bits set, or for which no expansion + is done, do not undergo word splitting. Words with the W_ASSIGNMENT + bit set do not undergo pathname expansion. */ static WORD_LIST * -expand_words_internal (list, do_vars) +expand_word_list_internal (list, do_vars) WORD_LIST *list; int do_vars; { - register WORD_LIST *tlist, *new_list = (WORD_LIST *)NULL; - WORD_LIST *orig_list; + WORD_LIST *tlist, *new_list, *next, *temp_list, *orig_list, *disposables; + char *temp_string; + int tint; - if (!list) + if (list == 0) return ((WORD_LIST *)NULL); tlist = copy_word_list (list); @@ -4049,15 +5193,24 @@ expand_words_internal (list, do_vars) if (do_vars) { tlist = separate_out_assignments (tlist); - if (!tlist) + if (tlist == 0) { if (varlist) { /* All the words were variable assignments, so they are placed into the shell's environment. */ - register WORD_LIST *lp; - for (lp = varlist; lp; lp = lp->next) - do_assignment (lp->word->word); + for (new_list = varlist; new_list; new_list = new_list->next) + { + this_command_name = (char *)NULL; /* no arithmetic errors */ + tint = do_assignment (new_list->word->word); + /* Variable assignment errors in non-interactive shells + running in Posix.2 mode cause the shell to exit. */ + if (tint == 0 && interactive_shell == 0 && posixly_correct) + { + last_command_exit_value = EXECUTION_FAILURE; + jump_to_top_level (FORCE_EOF); + } + } dispose_words (varlist); varlist = (WORD_LIST *)NULL; } @@ -4071,16 +5224,14 @@ expand_words_internal (list, do_vars) #if defined (BRACE_EXPANSION) /* Do brace expansion on this word if there are any brace characters in the string. */ - if (!no_brace_expansion) + if (brace_expansion && tlist) { register char **expansions; - WORD_LIST *braces = (WORD_LIST *)NULL, *disposables = (WORD_LIST *)NULL; + WORD_LIST *braces; int eindex; - while (tlist) + for (braces = disposables = (WORD_LIST *)NULL; tlist; tlist = next) { - WORD_LIST *next; - next = tlist->next; /* Only do brace expansion if the word has a brace character. If @@ -4094,10 +5245,9 @@ expand_words_internal (list, do_vars) { expansions = brace_expand (tlist->word->word); - for (eindex = 0; expansions[eindex]; eindex++) + for (eindex = 0; temp_string = expansions[eindex]; eindex++) { - braces = make_word_list (make_word (expansions[eindex]), - braces); + braces = make_word_list (make_word (temp_string), braces); free (expansions[eindex]); } free (expansions); @@ -4112,8 +5262,6 @@ expand_words_internal (list, do_vars) tlist->next = braces; braces = tlist; } - - tlist = next; } dispose_words (disposables); @@ -4121,58 +5269,56 @@ expand_words_internal (list, do_vars) } #endif /* BRACE_EXPANSION */ - orig_list = tlist; - /* We do tilde expansion all the time. This is what 1003.2 says. */ - while (tlist) + for (orig_list = tlist, new_list = (WORD_LIST *)NULL; tlist; tlist = next) { - register char *current_word; - WORD_LIST *expanded, *t, *reversed, *next; - int expanded_something = 0; + WORD_LIST *expanded; + int expanded_something, has_dollar_at; - current_word = tlist->word->word; + temp_string = tlist->word->word; next = tlist->next; /* Posix.2 section 3.6.1 says that tildes following `=' in words which are not assignment statements are not expanded. We do - this only if POSIXLY_CORRECT is enabled. */ - if (current_word[0] == '~' || - (!posixly_correct && strchr (current_word, '~') && - unquoted_substring ("=~", current_word))) + this only if POSIXLY_CORRECT is enabled. Essentially, we do + tilde expansion on unquoted assignment statements (flags include + W_ASSIGNMENT but not W_QUOTED). */ + if (temp_string[0] == '~' || + (((tlist->word->flags & (W_ASSIGNMENT|W_QUOTED)) == W_ASSIGNMENT) && + posixly_correct == 0 && + strchr (temp_string, '~') && + (unquoted_substring ("=~", temp_string) || unquoted_substring (":~", temp_string)))) { - char *tt; - - tt = tlist->word->word; - tlist->word->word = tilde_expand (tt); - free (tt); + tlist->word->word = bash_tilde_expand (temp_string); + free (temp_string); } + expanded_something = 0; expanded = expand_word_internal - (tlist->word, 0, (int *)NULL, &expanded_something); + (tlist->word, 0, &has_dollar_at, &expanded_something); if (expanded == &expand_word_error || expanded == &expand_word_fatal) { /* By convention, each time this error is returned, tlist->word->word has already been freed. */ tlist->word->word = (char *)NULL; - + /* Dispose our copy of the original list. */ dispose_words (orig_list); /* Dispose the new list we're building. */ dispose_words (new_list); if (expanded == &expand_word_error) - longjmp (top_level, DISCARD); + jump_to_top_level (DISCARD); else - longjmp (top_level, FORCE_EOF); + jump_to_top_level (FORCE_EOF); } - /* Don't split assignment words, even when they do not precede a - command name. */ - if (expanded_something && tlist->word->assignment == 0) + /* Don't split words marked W_NOSPLIT. */ + if (expanded_something && (tlist->word->flags & W_NOSPLIT) == 0) { - t = word_list_split (expanded); + temp_list = word_list_split (expanded); dispose_words (expanded); } else @@ -4182,41 +5328,35 @@ expand_words_internal (list, do_vars) do not do word splitting. We still have to remove quoted null characters from the result. */ word_list_remove_quoted_nulls (expanded); - t = expanded; + temp_list = expanded; } /* In the most common cases, t will be a list containing only one element, so the call to reverse_list would be wasted. */ - reversed = REVERSE_LIST (t, WORD_LIST *); - new_list = (WORD_LIST *)list_append (reversed, new_list); - - tlist = next; + expanded = REVERSE_LIST (temp_list, WORD_LIST *); + new_list = (WORD_LIST *)list_append (expanded, new_list); } new_list = REVERSE_LIST (new_list, WORD_LIST *); dispose_words (orig_list); -#if defined (USE_POSIX_GLOB_LIBRARY) -# define GLOB_FAILED(glist) !(glist) -#else /* !USE_POSIX_GLOB_LIBRARY */ -# define GLOB_FAILED(glist) (glist) == (char **)&glob_error_return -#endif /* !USE_POSIX_GLOB_LIBRARY */ - /* Okay, we're almost done. Now let's just do some filename globbing. */ if (new_list) { - char **temp_list = (char **)NULL; - register int list_index; - WORD_LIST *glob_list, *disposables; + char **glob_array; + register int glob_index; + WORD_LIST *glob_list; + WORD_DESC *tword; orig_list = disposables = (WORD_LIST *)NULL; tlist = new_list; /* orig_list == output list, despite the name. */ - if (!disallow_filename_globbing) + if (disallow_filename_globbing == 0) { + glob_array = (char **)NULL; while (tlist) { /* For each word, either globbing is attempted or the word is @@ -4230,75 +5370,74 @@ expand_words_internal (list, do_vars) in reverse order and requires a call to reverse_list to be set right. After all words are examined, the disposable words are freed. */ - WORD_LIST *next; - next = tlist->next; /* If the word isn't quoted and there is an unquoted pattern matching character in the word, then glob it. */ - if (!tlist->word->quoted && !tlist->word->assignment && + if ((tlist->word->flags & (W_QUOTED|W_ASSIGNMENT)) == 0 && unquoted_glob_pattern_p (tlist->word->word)) { - temp_list = shell_glob_filename (tlist->word->word); + glob_array = shell_glob_filename (tlist->word->word); /* Handle error cases. I don't think we should report errors like "No such file or directory". However, I would like to report errors like "Read failed". */ - if (GLOB_FAILED (temp_list)) + if (GLOB_FAILED (glob_array)) { - temp_list = (char **) xmalloc (sizeof (char *)); - temp_list[0] = (char *)NULL; + glob_array = (char **) xmalloc (sizeof (char *)); + glob_array[0] = (char *)NULL; } /* Dequote the current word in case we have to use it. */ - if (!temp_list[0]) + if (glob_array[0] == NULL) { - register char *t = dequote_string (tlist->word->word); + temp_string = dequote_string (tlist->word->word); free (tlist->word->word); - tlist->word->word = t; + tlist->word->word = temp_string; } /* Make the array into a word list. */ glob_list = (WORD_LIST *)NULL; - for (list_index = 0; temp_list[list_index]; list_index++) - glob_list = make_word_list - (make_word (temp_list[list_index]), glob_list); + for (glob_index = 0; glob_array[glob_index]; glob_index++) + { + tword = make_bare_word (glob_array[glob_index]); + tword->flags |= W_GLOBEXP; /* XXX */ + glob_list = make_word_list (tword, glob_list); + } if (glob_list) { - orig_list = (WORD_LIST *)list_append - (glob_list, orig_list); + orig_list = (WORD_LIST *)list_append (glob_list, orig_list); tlist->next = disposables; disposables = tlist; } + else if (allow_null_glob_expansion == 0) + { + /* Failed glob expressions are left unchanged. */ + tlist->next = orig_list; + orig_list = tlist; + } else - if (!allow_null_glob_expansion) - { - /* Failed glob expressions are left unchanged. */ - tlist->next = orig_list; - orig_list = tlist; - } - else - { - /* Failed glob expressions are removed. */ - tlist->next = disposables; - disposables = tlist; - } + { + /* Failed glob expressions are removed. */ + tlist->next = disposables; + disposables = tlist; + } } else { /* Dequote the string. */ - register char *t = dequote_string (tlist->word->word); + temp_string = dequote_string (tlist->word->word); free (tlist->word->word); - tlist->word->word = t; + tlist->word->word = temp_string; tlist->next = orig_list; orig_list = tlist; } - free_array (temp_list); - temp_list = (char **)NULL; + free_array (glob_array); + glob_array = (char **)NULL; tlist = next; } @@ -4311,21 +5450,17 @@ expand_words_internal (list, do_vars) else { /* Dequote the words, because we're not performing globbing. */ - register WORD_LIST *wl = new_list; - register char *wp; - while (wl) + for (temp_list = new_list; temp_list; temp_list = temp_list->next) { - wp = dequote_string (wl->word->word); - free (wl->word->word); - wl->word->word = wp; - wl = wl->next; + temp_string = dequote_string (temp_list->word->word); + free (temp_list->word->word); + temp_list->word->word = temp_string; } } } if (do_vars) { - register WORD_LIST *lp; Function *assign_func; /* If the remainder of the words expand to nothing, Posix.2 requires @@ -4333,131 +5468,31 @@ expand_words_internal (list, do_vars) environment. */ assign_func = new_list ? assign_in_env : do_assignment; - for (lp = varlist; lp; lp = lp->next) - (*assign_func) (lp->word->word); - - dispose_words (varlist); - varlist = (WORD_LIST *)NULL; - } - - return (new_list); -} - -/* Return nonzero if S has any unquoted special globbing chars in it. */ -static int -unquoted_glob_pattern_p (string) - register char *string; -{ - register int c; - int open = 0; - - while (c = *string++) - { - switch (c) + for (temp_list = varlist; temp_list; temp_list = temp_list->next) { - case '?': - case '*': - return (1); - - case '[': - open++; - continue; - - case ']': - if (open) - return (1); - continue; - - case CTLESC: - case '\\': - if (*string++ == '\0') - return (0); + this_command_name = (char *)NULL; + tint = (*assign_func) (temp_list->word->word); + /* Variable assignment errors in non-interactive shells running + in Posix.2 mode cause the shell to exit. */ + if (tint == 0 && assign_func == do_assignment && + interactive_shell == 0 && posixly_correct) + { + last_command_exit_value = EXECUTION_FAILURE; + jump_to_top_level (FORCE_EOF); + } } - } - return (0); -} - -/* PATHNAME can contain characters prefixed by CTLESC; this indicates - that the character is to be quoted. We quote it here in the style - that the glob library recognizes. If CONVERT_QUOTED_NULLS is non-zero, - we change quoted null strings (pathname[0] == CTLNUL) into empty - strings (pathname[0] == 0). If this is called after quote removal - is performed, CONVERT_QUOTED_NULLS should be 0; if called when quote - removal has not been done (for example, before attempting to match a - pattern while executing a case statement), CONVERT_QUOTED_NULLS should - be 1. */ -char * -quote_string_for_globbing (pathname, convert_quoted_nulls) - char *pathname; - int convert_quoted_nulls; -{ - char *temp; - register int i; - - temp = savestring (pathname); - - if (convert_quoted_nulls && QUOTED_NULL (pathname)) - { - temp[0] = '\0'; - return temp; - } - for (i = 0; temp[i]; i++) - { - if (temp[i] == CTLESC) - temp[i++] = '\\'; + dispose_words (varlist); + varlist = (WORD_LIST *)NULL; } - return (temp); -} - -/* Call the glob library to do globbing on PATHNAME. */ -char ** -shell_glob_filename (pathname) - char *pathname; -{ -#if defined (USE_POSIX_GLOB_LIBRARY) - extern int glob_dot_filenames; - register int i; - char *temp, **return_value; - glob_t filenames; - int glob_flags; - - temp = quote_string_for_globbing (pathname, 0); - - filenames.gl_offs = 0; - - glob_flags = glob_dot_filenames ? GLOB_PERIOD : 0; - glob_flags |= (GLOB_ERR | GLOB_DOOFFS); - - i = glob (temp, glob_flags, (Function *)NULL, &filenames); - - free (temp); - - if (i == GLOB_NOSPACE || i == GLOB_ABEND) - return ((char **)NULL); - - if (i == GLOB_NOMATCH) - filenames.gl_pathv[0] = (char *)NULL; - - return (filenames.gl_pathv); - -#else /* !USE_POSIX_GLOB_LIBRARY */ - - char *temp, **results; - - noglob_dot_filenames = !glob_dot_filenames; - - temp = quote_string_for_globbing (pathname, 0); - - results = glob_filename (temp); - free (temp); - - if (results && !(GLOB_FAILED(results))) - sort_char_array (results); + tint = list_length (new_list) + 1; + RESIZE_MALLOCED_BUFFER (glob_argv_flags, 0, tint, glob_argv_flags_size, 16); + for (tint = 0, tlist = new_list; tlist; tlist = tlist->next) + glob_argv_flags[tint++] = (tlist->word->flags & W_GLOBEXP) ? '1' : '0'; + glob_argv_flags[tint] = '\0'; - return (results); -#endif /* !USE_POSIX_GLOB_LIBRARY */ + return (new_list); } /************************************************* @@ -4471,32 +5506,6 @@ shell_glob_filename (pathname) switch statement, but by the end of this file, I am sick of switch statements. */ -/* The functions that get called. */ -void - sv_path (), sv_mail (), sv_uids (), sv_ignoreeof (), - sv_glob_dot_filenames (), sv_nolinks (), - sv_noclobber (), sv_allow_null_glob_expansion (), sv_strict_posix (); - -#if defined (READLINE) -void sv_terminal (), sv_hostname_completion_file (); -#endif - -#if defined (HISTORY) -void sv_histsize (), sv_histfilesize (), - sv_history_control (), sv_command_oriented_history (); -# if defined (BANG_HISTORY) -void sv_histchars (); -# endif -#endif /* HISTORY */ - -#if defined (GETOPTS_BUILTIN) -void sv_optind (), sv_opterr (); -#endif /* GETOPTS_BUILTIN */ - -#if defined (JOB_CONTROL) -void sv_notify (); -#endif - #define SET_INT_VAR(name, intvar) intvar = find_variable (name) != 0 struct name_and_function { @@ -4509,47 +5518,46 @@ struct name_and_function { { "MAILCHECK", sv_mail }, { "POSIXLY_CORRECT", sv_strict_posix }, - { "POSIX_PEDANTIC", sv_strict_posix }, + { "GLOBIGNORE", sv_globignore }, + /* Variables which only do something special when READLINE is defined. */ #if defined (READLINE) { "TERM", sv_terminal }, { "TERMCAP", sv_terminal }, { "TERMINFO", sv_terminal }, - { "hostname_completion_file", sv_hostname_completion_file }, - { "HOSTFILE", sv_hostname_completion_file }, + { "HOSTFILE", sv_hostfile }, #endif /* READLINE */ /* Variables which only do something special when HISTORY is defined. */ #if defined (HISTORY) + { "HISTIGNORE", sv_histignore }, { "HISTSIZE", sv_histsize }, - { "HISTFILESIZE", sv_histfilesize }, - { "command_oriented_history", sv_command_oriented_history }, + { "HISTFILESIZE", sv_histsize }, + { "HISTCONTROL", sv_history_control }, # if defined (BANG_HISTORY) { "histchars", sv_histchars }, -# endif - { "history_control", sv_history_control }, - { "HISTCONTROL", sv_history_control }, +# endif /* BANG_HISTORY */ #endif /* HISTORY */ - { "EUID", sv_uids}, - { "UID", sv_uids}, { "IGNOREEOF", sv_ignoreeof }, { "ignoreeof", sv_ignoreeof }, -#if defined (GETOPTS_BUILTIN) { "OPTIND", sv_optind }, { "OPTERR", sv_opterr }, -#endif /* GETOPTS_BUILTIN */ -#if defined (JOB_CONTROL) - { "notify", sv_notify }, -#endif /* JOB_CONTROL */ - - { "glob_dot_filenames", sv_glob_dot_filenames }, - { "allow_null_glob_expansion", sv_allow_null_glob_expansion }, - { "noclobber", sv_noclobber }, - { "nolinks", sv_nolinks }, - { (char *)0x00, (VFunction *)0x00 } + { "TEXTDOMAIN", sv_locale }, + { "TEXTDOMAINDIR", sv_locale }, + { "LC_ALL", sv_locale }, + { "LC_COLLATE", sv_locale }, + { "LC_CTYPE", sv_locale }, + { "LC_MESSAGES", sv_locale }, + { "LANG", sv_locale }, + +#if defined (HAVE_TZSET) && defined (PROMPT_STRING_DECODE) + { "TZ", sv_tz }, +#endif + + { (char *)0, (VFunction *)0 } }; /* The variable in NAME has just had its state changed. Check to see if it @@ -4558,38 +5566,25 @@ void stupidly_hack_special_variables (name) char *name; { - int i = 0; + int i; - while (special_vars[i].name) + for (i = 0; special_vars[i].name; i++) { if (STREQ (special_vars[i].name, name)) { (*(special_vars[i].function)) (name); return; } - i++; } } -/* Set/unset noclobber. */ -void -sv_noclobber (name) - char *name; -{ - SET_INT_VAR (name, noclobber); -} - /* What to do just after the PATH variable has changed. */ void sv_path (name) char *name; { /* hash -r */ - WORD_LIST *args; - - args = make_word_list (make_word ("-r"), NULL); - hash_builtin (args); - dispose_words (args); + flush_hashed_filenames (); } /* What to do just after one of the MAILxxxx variables has changed. NAME @@ -4612,6 +5607,14 @@ sv_mail (name) } } +/* What to do when GLOBIGNORE changes. */ +void +sv_globignore (name) + char *name; +{ + setup_glob_ignore (name); +} + #if defined (READLINE) /* What to do just after one of the TERMxxx variables has changed. If we are an interactive shell, then try to reset the terminal @@ -4620,12 +5623,12 @@ void sv_terminal (name) char *name; { - if (interactive_shell && !no_line_editing) + if (interactive_shell && no_line_editing == 0) rl_reset_terminal (get_string_value ("TERM")); } void -sv_hostname_completion_file (name) +sv_hostfile (name) char *name; { hostname_list_initialized = 0; @@ -4633,86 +5636,82 @@ sv_hostname_completion_file (name) #endif /* READLINE */ #if defined (HISTORY) -/* What to do after the HISTSIZE variable changes. - If there is a value for this variable (and it is numeric), then stifle +/* What to do after the HISTSIZE or HISTFILESIZE variables change. + If there is a value for this HISTSIZE (and it is numeric), then stifle the history. Otherwise, if there is NO value for this variable, - unstifle the history. */ + unstifle the history. If name is HISTFILESIZE, and its value is + numeric, truncate the history file to hold no more than that many + lines. */ void sv_histsize (name) char *name; { - char *temp = get_string_value (name); + char *temp; + long num; + + temp = get_string_value (name); if (temp && *temp) { - int num; - if (sscanf (temp, "%d", &num) == 1) - { - stifle_history (num); - if (history_lines_this_session > where_history ()) - history_lines_this_session = where_history (); + if (legal_number (temp, &num)) + { + if (name[4] == 'S') + { + stifle_history (num); + num = where_history (); + if (history_lines_this_session > num) + history_lines_this_session = num; + } + else + { + history_truncate_file (get_string_value ("HISTFILE"), (int)num); + if (num <= history_lines_in_file) + history_lines_in_file = num; + } } } - else + else if (name[4] == 'S') unstifle_history (); } -/* What to do if the HISTFILESIZE variable changes. */ +/* What to do after the HISTIGNORE variable changes. */ void -sv_histfilesize (name) +sv_histignore (name) char *name; { - char *temp = get_string_value (name); - - if (temp && *temp) - { - int num; - if (sscanf (temp, "%d", &num) == 1) - { - history_truncate_file (get_string_value ("HISTFILE"), num); - if (num <= history_lines_in_file) - history_lines_in_file = num; - } - } + setup_history_ignore (name); } -/* What to do after the HISTORY_CONTROL variable changes. */ +/* What to do after the HISTCONTROL variable changes. */ void sv_history_control (name) char *name; { - char *temp = get_string_value (name); + char *temp; history_control = 0; + temp = get_string_value (name); - if (temp && *temp) + if (temp && *temp && STREQN (temp, "ignore", 6)) { - if (strcmp (temp, "ignorespace") == 0) + if (temp[6] == 's') /* ignorespace */ history_control = 1; - else if (strcmp (temp, "ignoredups") == 0) + else if (temp[6] == 'd') /* ignoredups */ history_control = 2; - else if (strcmp (temp, "ignoreboth") == 0) + else if (temp[6] == 'b') /* ignoreboth */ history_control = 3; } } -/* What to do after the COMMAND_ORIENTED_HISTORY variable changes. */ -void -sv_command_oriented_history (name) - char *name; -{ - SET_INT_VAR (name, command_oriented_history); -} - -# if defined (BANG_HISTORY) +#if defined (BANG_HISTORY) /* Setting/unsetting of the history expansion character. */ - void sv_histchars (name) char *name; { - char *temp = get_string_value (name); + char *temp; + temp = get_string_value (name); if (temp) { history_expansion_char = *temp; @@ -4730,15 +5729,17 @@ sv_histchars (name) history_comment_char = '#'; } } -# endif /* BANG_HISTORY */ +#endif /* BANG_HISTORY */ #endif /* HISTORY */ +#if defined (HAVE_TZSET) && defined (PROMPT_STRING_DECODE) void -sv_allow_null_glob_expansion (name) +sv_tz (name) char *name; { - SET_INT_VAR (name, allow_null_glob_expansion); + tzset (); } +#endif /* If the variable exists, then the value of it can be the number of times we actually ignore the EOF. The default is small, @@ -4749,7 +5750,6 @@ sv_ignoreeof (name) { SHELL_VAR *tmp_var; char *temp; - int new_limit; eof_encountered = 0; @@ -4757,78 +5757,17 @@ sv_ignoreeof (name) ignoreeof = tmp_var != 0; temp = tmp_var ? value_cell (tmp_var) : (char *)NULL; if (temp) - { - if (sscanf (temp, "%d", &new_limit) == 1) - eof_encountered_limit = new_limit; - else - eof_encountered_limit = 10; /* csh uses 26. */ - } -} - -/* Control whether * matches .files in globbing. Yechh. */ -int glob_dot_filenames = 0; - -void -sv_glob_dot_filenames (name) - char *name; -{ - SET_INT_VAR (name, glob_dot_filenames); -} - -#if defined (JOB_CONTROL) -/* Job notification feature desired? */ -void -sv_notify (name) - char *name; -{ - SET_INT_VAR (name, asynchronous_notification); -} -#endif /* JOB_CONTROL */ - -/* If the variable `nolinks' exists, it specifies that symbolic links are - not to be followed in `cd' commands. */ -void -sv_nolinks (name) - char *name; -{ - SET_INT_VAR (name, no_symbolic_links); -} - -/* Don't let users hack the user id variables. */ -void -sv_uids (name) - char *name; -{ - char *buff; - register SHELL_VAR *v; - - buff = itos (current_user.uid); - v = find_variable ("UID"); - if (v) - v->attributes &= ~att_readonly; - - v = bind_variable ("UID", buff); - v->attributes |= (att_readonly | att_integer); - free (buff); - - buff = itos (current_user.euid); - v = find_variable ("EUID"); - if (v) - v->attributes &= ~att_readonly; - - v = bind_variable ("EUID", buff); - v->attributes |= (att_readonly | att_integer); - free (buff); + eof_encountered_limit = (*temp && all_digits (temp)) ? atoi (temp) : 10; } -#if defined (GETOPTS_BUILTIN) void sv_optind (name) char *name; { - char *tt = get_string_value ("OPTIND"); - int s = 0; + char *tt; + int s; + tt = get_string_value ("OPTIND"); if (tt && *tt) { s = atoi (tt); @@ -4838,6 +5777,8 @@ sv_optind (name) if (s < 0 || s == 1) s = 0; } + else + s = 0; getopts_reset (s); } @@ -4845,23 +5786,32 @@ void sv_opterr (name) char *name; { - char *tt = get_string_value ("OPTERR"); - int s = 1; + char *tt; - if (tt && *tt) - s = atoi (tt); - sh_opterr = s; + tt = get_string_value ("OPTERR"); + sh_opterr = (tt && *tt) ? atoi (tt) : 1; } -#endif /* GETOPTS_BUILTIN */ void sv_strict_posix (name) char *name; { SET_INT_VAR (name, posixly_correct); - if (posixly_correct) - interactive_comments = 1; + posix_initialize (posixly_correct); #if defined (READLINE) posix_readline_initialize (posixly_correct); #endif /* READLINE */ } + +void +sv_locale (name) + char *name; +{ + char *v; + + v = get_string_value (name); + if (name[0] == 'L' && name[1] == 'A') /* LANG */ + set_lang (name, v); + else + set_locale_var (name, v); /* LC_*, TEXTDOMAIN* */ +} diff --git a/subst.h b/subst.h index 6584ef9..2085580 100644 --- a/subst.h +++ b/subst.h @@ -84,6 +84,10 @@ extern char *strip_trailing_ifs_whitespace __P((char *, char *, int)); extern int do_assignment __P((char *)); extern int do_assignment_no_expand __P((char *)); +#if defined (ARRAY_VARS) +extern SHELL_VAR *do_array_element_assignment __P((char *, char *)); +#endif + /* Append SOURCE to TARGET at INDEX. SIZE is the current amount of space allocated to TARGET. SOURCE can be NULL, in which case nothing happens. Gets rid of SOURCE by free ()ing it. @@ -102,6 +106,8 @@ extern WORD_LIST *list_rest_of_args __P((void)); case of "$*" with respect to IFS. */ extern char *string_rest_of_args __P((int)); +extern int number_of_args __P((void)); + /* Expand STRING by performing parameter expansion, command substitution, and arithmetic expansion. Dequote the resulting WORD_LIST before returning it, but do not perform word splitting. The call to @@ -133,6 +139,9 @@ extern WORD_LIST *expand_word_leave_quoted __P((WORD_DESC *, int)); /* Return the value of a positional parameter. This handles values > 10. */ extern char *get_dollar_var_value __P((int)); +/* Quote a string to protect it from word splitting. */ +extern char *quote_string __P((char *)); + /* Perform quote removal on STRING. If QUOTED > 0, assume we are obeying the backslash quoting rules for within double quotes. */ extern char *string_quote_removal __P((char *, int)); @@ -160,22 +169,47 @@ extern WORD_LIST *expand_words __P((WORD_LIST *)); variables. */ extern WORD_LIST *expand_words_no_vars __P((WORD_LIST *)); -/* PATHNAME can contain characters prefixed by CTLESC;; this indicates - that the character is to be quoted. We quote it here in the style - that the glob library recognizes. If CONVERT_QUOTED_NULLS is non-zero, - we change quoted null strings (pathname[0] == CTLNUL) into empty - strings (pathname[0] == 0). If this is called after quote removal - is performed, CONVERT_QUOTED_NULLS should be 0; if called when quote - removal has not been done (for example, before attempting to match a - pattern while executing a case statement), CONVERT_QUOTED_NULLS should - be 1. */ -extern char *quote_string_for_globbing __P((char *, int)); - -/* Call the glob library to do globbing on PATHNAME. */ -extern char **shell_glob_filename __P((char *)); - /* The variable in NAME has just had its state changed. Check to see if it is one of the special ones where something special happens. */ extern void stupidly_hack_special_variables __P((char *)); +extern char *pat_subst __P((char *, char *, char *, int)); + +extern void unlink_fifo_list __P((void)); + +#if defined (ARRAY_VARS) +extern int array_expand_index __P((char *, int)); +extern int valid_array_reference __P((char *)); +extern char *get_array_value __P((char *, int)); +extern SHELL_VAR *array_variable_part __P((char *, char **, int *)); +extern WORD_LIST *list_string_with_quotes __P((char *)); +extern char *extract_array_assignment_list __P((char *, int *)); +#endif + +/* The `special variable' functions that get called when a particular + variable is set. */ +void sv_path (), sv_mail (), sv_ignoreeof (), sv_strict_posix (); +void sv_optind (), sv_opterr (), sv_globignore (), sv_locale (); + +#if defined (READLINE) +void sv_terminal (), sv_hostfile (); +#endif + +#if defined (HAVE_TZSET) && defined (PROMPT_STRING_DECODE) +void sv_tz (); +#endif + +#if defined (HISTORY) +void sv_histsize (), sv_histignore (), sv_history_control (); +# if defined (BANG_HISTORY) +void sv_histchars (); +# endif +#endif /* HISTORY */ + +/* How to determine the quoted state of the character C. */ +#define QUOTED_CHAR(c) ((c) == CTLESC) + +/* Is the first character of STRING a quoted NULL character? */ +#define QUOTED_NULL(string) ((string)[0] == CTLNUL && (string)[1] == '\0') + #endif /* !_SUBST_H_ */ diff --git a/support/PORTING b/support/PORTING deleted file mode 100644 index 1869472..0000000 --- a/support/PORTING +++ /dev/null @@ -1,22 +0,0 @@ -if _mkfifo cannot be found, add "-DMKFIFO_MISSING" to SYSDEP_CFLAGS in -your machine's entry in machines.h. - -If bash compiles, but hangs when executing a non-builtin, there is a -problem with the defines in your /usr/include/sys/wait.h. If you -don't have one, there is a problem in our defines. At any rate, -perhaps you have a partially POSIX system, instead of a fully -operational one. Try defining _POSIX_SOURCE just before the inclusion -of in jobs.h, and then undefining it immediately after -the inclusion. - -Finding out if your system has something (like setpgid, for example) -You can always do "nm -o /lib/*.a | grep setpgid". If an entry for -the function appears, you have it, and you might have to link with -that library by adding "#defined REQUIRED_LIBRARIES -lfoo" to the -entry in machines.h. - -If you seem to be going around in circles, and they are related to -job control and posixness, try #undef HAVE_UNISTD_H in the entry for -your machine in machines.h. This can work by keeping unistd.h from -defining _POSIX_VERSION, which in turn prevents bash from assuming -full Posix semantics. diff --git a/support/SYMLINKS b/support/SYMLINKS index bd36b7e..ec2a5c6 100644 --- a/support/SYMLINKS +++ b/support/SYMLINKS @@ -3,19 +3,16 @@ # # link name link target # -lib/readline/doc/texindex.c ../../doc-support/texindex.c -# lib/readline/tilde.c ../tilde/tilde.c lib/readline/tilde.h ../tilde/tilde.h +lib/readline/posixdir.h ../posixheaders/posixdir.h lib/readline/posixstat.h ../posixheaders/posixstat.h lib/readline/ansi_stdlib.h ../posixheaders/ansi_stdlib.h -lib/readline/memalloc.h ../posixheaders/memalloc.h lib/readline/xmalloc.c ../malloc/xmalloc.c # -lib/tilde/memalloc.h ../posixheaders/memalloc.h -# -lib/doc-support/getopt.h ../../builtins/getopt.h +#lib/tilde/memalloc.h ../posixheaders/memalloc.h # +posixdir.h lib/posixheaders/posixdir.h posixstat.h lib/posixheaders/posixstat.h ansi_stdlib.h lib/posixheaders/ansi_stdlib.h stdc.h lib/posixheaders/stdc.h diff --git a/support/bashbug.sh b/support/bashbug.sh index fb5600b..6a2a47b 100644 --- a/support/bashbug.sh +++ b/support/bashbug.sh @@ -1,26 +1,39 @@ #!/bin/sh - # -# bashbug - create a bug report and mail it to bug-bash@prep.ai.mit.edu +# bashbug - create a bug report and mail it to the bug address +# +# The bug address depends on the release status of the shell. Versions +# with status `alpha' or `beta' mail bug reports to chet@po.cwru.edu. +# Other versions send mail to bug-bash@prep.ai.mit.edu. # # configuration section: # these variables are filled in by the make target in cpp-Makefile # -MACHINE="@MACHINE@" -OS="@OS@" -CC="@CC@" -CFLAGS="@CFLAGS@" -RELEASE="@RELEASE@" -PATCHLEVEL="@PATCHLEVEL@" - -PATH=/bin:/usr/bin:usr/local/bin:$PATH +MACHINE="!MACHINE!" +OS="!OS!" +CC="!CC!" +CFLAGS="!CFLAGS!" +RELEASE="!RELEASE!" +PATCHLEVEL="!PATCHLEVEL!" +RELSTATUS="!RELSTATUS!" +MACHTYPE="!MACHTYPE!" + +PATH=/bin:/usr/bin:/usr/local/bin:$PATH export PATH TEMP=/tmp/bashbug.$$ -BUGADDR=${1-bug-bash@prep.ai.mit.edu} +case "$RELSTATUS" in +alpha*|beta*) BUGBASH=chet@po.cwru.edu ;; +*) BUGBASH=bug-bash@prep.ai.mit.edu ;; +esac + +BUGADDR=${1-$BUGBASH} : ${EDITOR=emacs} +: ${USER=${LOGNAME-`whoami`}} + trap 'rm -f $TEMP $TEMP.x; exit 1' 1 2 3 13 15 trap 'rm -f $TEMP $TEMP.x' 0 @@ -48,37 +61,60 @@ OS: $OS Compiler: $CC Compilation CFLAGS: $CFLAGS uname output: $UN +Machine Type: $MACHTYPE Bash Version: $RELEASE Patch Level: $PATCHLEVEL +Release Status: $RELSTATUS Description: - [Detailed description of the problem, suggestion, or complaint.] + [Detailed description of the problem, suggestion, or complaint.] Repeat-By: - [Describe the sequence of events that causes the problem - to occur.] + [Describe the sequence of events that causes the problem + to occur.] Fix: - [Description of how to fix the problem. If you don't know a - fix for the problem, don't include this section.] + [Description of how to fix the problem. If you don't know a + fix for the problem, don't include this section.] EOF chmod u+w $TEMP cp $TEMP $TEMP.x -if $EDITOR $TEMP +# Figure out how to echo a string without a trailing newline +N=`echo 'hi there\c'` +case "$N" in +*c) n=-n c= ;; +*) n= c='\c' ;; +esac + +trap '' 2 # ignore interrupts while in editor + +until $EDITOR $TEMP; do + echo "$0: editor \`$EDITOR' exited with nonzero status." + echo "$0: Perhaps it was interrupted." + echo "$0: Type `y' to give up, and lose your bug report;" + echo "$0: type `n' to re-enter the editor." + echo $n "$0: Do you want to give up? $c" + + read ans + case "$ans" in + Yy]*) exit 1 ;; + esac +done + +trap 'rm -f $TEMP $TEMP.x; exit 1' 2 # restore trap on SIGINT + +if cmp -s $TEMP $TEMP.x then - if cmp -s $TEMP $TEMP.x - then - echo "File not changed, no bug report submitted." - exit - fi - - ${RMAIL} $BUGADDR < $TEMP || { - cat $TEMP >> $HOME/dead.bashbug - echo "$0: mail failed: report saved in $HOME/dead.bashbug" >&2 - } + echo "File not changed, no bug report submitted." + exit fi +${RMAIL} $BUGADDR < $TEMP || { + cat $TEMP >> $HOME/dead.bashbug + echo "$0: mail failed: report saved in $HOME/dead.bashbug" >&2 +} + exit 0 diff --git a/support/cat-s b/support/cat-s deleted file mode 100644 index 87ba163..0000000 --- a/support/cat-s +++ /dev/null @@ -1,16 +0,0 @@ -# This awk script is called from within Makefile to strip multiple blank -# lines from stdin. -BEGIN { newlines = 0 } -{ - if (NF == 0) - newlines = 1; - else - { - if (newlines) - { - printf "\n"; - newlines = 0; - } - print $0; - } -} diff --git a/support/clone-bash b/support/clone-bash deleted file mode 100755 index 89e0752..0000000 --- a/support/clone-bash +++ /dev/null @@ -1,95 +0,0 @@ -#! /bin/sh -# -# -src=src -case "$1" in --s) shift; src=$1; shift ;; -esac - -if [ ! -d $1 ]; then - mkdir $1 -fi - -prog=`basename $0` - -echo "${prog}: creating clone of bash source tree (from $src) in $1" - -case $src in -/*) abs=yes ;; -esac - -d=${PWD-`pwd`} - -cd $1 || { echo "$0: cannot cd to $1" ; exit 1; } - -d=$d/$1 - -SUBDIRS="CWRU builtins documentation examples support tests" -LIBDIRS="malloc termcap glob readline tilde malloclib posixheaders doc-support" -CWRUDIRS="misc" - -mkdir $SUBDIRS -for i in $SUBDIRS -do - cd $i - case "$abs" in - yes) ln -s $src/$i/* . ;; - *) ln -s ../../$src/$i/* . ;; - esac - echo -n $i.. - cd .. -done -cd $d - -cd CWRU -for i in $CWRUDIRS -do - rm -f $i - mkdir $i - cd $i - case "$abs" in - yes) ln -s $src/CWRU/$i/* . ;; - *) ln -s ../../../$src/CWRU/$i/* . ;; - esac - echo -n "CWRU/$i.." - cd .. -done -cd $d - -if [ ! -d lib ] ; then - mkdir lib -fi - -cd lib -mkdir $LIBDIRS - -for i in $LIBDIRS -do - cd $i - case "$abs" in - yes) ln -s $src/lib/$i/* . ;; - *) ln -s ../../../$src/lib/$i/* . ;; - esac - echo -n "lib/$i.." - cd .. -done - -cd $d - -case "$abs" in -yes) ln -s $src/.[a-z]* . ; ln -s $src/* . 2>&1 | grep -v exists ;; -*) ln -s ../$src/.[a-z]* . ; ln -s ../$src/* . 2>&1 | grep -v exists ;; -esac - -echo -n src.. - -SPECIAL="parser-built y.tab.h y.tab.c" -for x in $SPECIAL -do - rm -f $x - cp ../$src/$x . -done - -echo special - -exit 0 diff --git a/support/config.guess b/support/config.guess new file mode 100755 index 0000000..5f8b4bf --- /dev/null +++ b/support/config.guess @@ -0,0 +1,904 @@ +#! /bin/sh +# Attempt to guess a canonical system name. +# Copyright (C) 1992, 1993, 1994, 1995 Free Software Foundation, Inc. +# +# This file 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 of the License, or +# (at your option) any later version. +# +# This program 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 this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# Written by Per Bothner . +# The master version of this file is at the FSF in /home/gd/gnu/lib. +# +# This script attempts to guess a canonical system name similar to +# config.sub. If it succeeds, it prints the system name on stdout, and +# exits with 0. Otherwise, it exits with 1. +# +# The plan is that this can be called by configure scripts if you +# don't specify an explicit system type (host/target name). +# +# Only a few systems have been added to this list; please add others +# (but try to keep the structure clean). +# + +# This is needed to find uname on a Pyramid OSx when run in the BSD universe. +# (ghazi@noc.rutgers.edu 8/24/94.) +if (test -f /.attbin/uname) >/dev/null 2>&1 ; then + PATH=$PATH:/.attbin ; export PATH +elif (test -f /usr/5bin/uname) >/dev/null 2>&1 ; then + PATH=$PATH:/usr/5bin +fi + +UNAME=`(uname) 2>/dev/null` || UNAME=unknown # SunOS +UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown # sun4m +UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown # 4.1.2 +UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown # SunOS +UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown # 13 + +RELEASE=`expr "$UNAME_RELEASE" : '[^0-9]*\([0-9]*\)'` # 4 +case "$RELEASE" in +"") RELEASE=0 ;; +*) RELEASE=`expr "$RELEASE" + 0` ;; +esac +REL_LEVEL=`expr "$UNAME_RELEASE" : '[^0-9]*[0-9]*.\([0-9]*\)'` # 1 +REL_SUBLEVEL=`expr "$UNAME_RELEASE" : '[^0-9]*[0-9]*.[0-9]*.\([0-9]*\)'` # 2 + +trap 'rm -f dummy.c dummy.o dummy; exit 1' 1 2 15 + +# Some versions of i386 SVR4.2 make `uname' equivalent to `uname -n', which +# is contrary to all other versions of uname +if [ -n "$UNAME" ] && [ "$UNAME_S" != "$UNAME" ] && [ "$UNAME_S" = UNIX_SV ]; then + UNAME=UNIX_SV +fi + +# Note: order is significant - the case branches are not exclusive. + +case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in + alpha:OSF1:V*:*) + # After 1.2, OSF1 uses "V1.3" for uname -r. + echo alpha-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^V//'` + exit 0 ;; + alpha:OSF1:*:*) + # 1.2 uses "1.2" for uname -r. + echo alpha-dec-osf${UNAME_RELEASE} + exit 0 ;; + i[3456]86:NetBSD:*:*) + echo ${UNAME_MACHINE}-unknown-netbsd`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` + exit 0 ;; + alpha:NetBSD:*:*) + echo alpha-dec-netbsd${UNAME_RELEASE} + exit 0 ;; + sparc:NetBSD:*:*) + echo sparc-sun-netbsd${UNAME_RELEASE} + exit 0 ;; + sun3*:NetBSD:*:*) + echo m68k-sun-netbsd${UNAME_RELEASE} + exit 0 ;; + atari*:NetBSD:*:*) + echo m68k-atari-netbsd${UNAME_RELEASE} + exit 0 ;; + mac68k:NetBSD:*:*) + echo m68k-apple-netbsd${UNAME_RELEASE} + exit 0 ;; + hp3[0-9][05]:NetBSD:*:*) + echo m68k-hp-netbsd${UNAME_RELEASE} + exit 0 ;; + amiga:NetBSD:*:*) + echo m68k-cbm-netbsd${UNAME_RELEASE} + exit 0 ;; + vax:NetBSD:*:*) + echo vax-dec-netbsd${UNAME_RELEASE} + exit 0 ;; + i[3456]86:OpenBSD:*:*) + echo ${UNAME_MACHINE}-unknown-openbsd`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` + exit 0 ;; + alpha:OpenBSD:*:*) + echo alpha-dec-openbsd${UNAME_RELEASE} + exit 0 ;; + sparc:OpenBSD:*:*) + echo sparc-sun-openbsd${UNAME_RELEASE} + exit 0 ;; + sun3*:OpenBSD:*:*) + echo m68k-sun-openbsd${UNAME_RELEASE} + exit 0 ;; + atari*:OpenBSD:*:*) + echo m68k-atari-openbsd${UNAME_RELEASE} + exit 0 ;; + mac68k:OpenBSD:*:*) + echo m68k-apple-openbsd${UNAME_RELEASE} + exit 0 ;; + hp3[0-9][05]:OpenBSD:*:*) + echo m68k-hp-openbsd${UNAME_RELEASE} + exit 0 ;; + amiga:OpenBSD:*:*) + echo m68k-cbm-openbsd${UNAME_RELEASE} + exit 0 ;; + vax:OpenBSD:*:*) + echo vax-dec-openbsd${UNAME_RELEASE} + exit 0 ;; + powerpc:machten:*:*) + echo powerpc-apple-machten${UNAME_RELEASE} + exit 0 ;; + mac68k:machten:*:*) + echo mac68k-apple-machten${UNAME_RELEASE} + exit 0 ;; + RISC*:Mach:*:*) + echo mips-dec-mach_bsd4.3 + exit 0 ;; + 21064:Windows_NT:50:3) + echo alpha-dec-winnt3.5 + exit 0 ;; + Amiga*:UNIX_System_V:4.*:*) + echo m68k-cbm-sysv${UNAME_RELEASE} + exit 0 ;; + arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) + echo arm-acorn-riscix${UNAME_RELEASE} + exit 0;; + Pyramid*:OSx*:*:*|MIS*:OSx*:*:*) + if test "`(/bin/universe) 2>/dev/null`" = att ; then + echo pyramid-pyramid-sysv3 + else + echo pyramid-pyramid-bsd + fi + exit 0 ;; + NILE:*:*:dcosx) + echo pyramid-pyramid-svr4 + exit 0 ;; + concurrent*:*:*:*) + if test "`(/bin/universe) 2>/dev/null`" = att ; then + echo concurrent-concurrent-sysv3 + else + echo concurrent-concurrent-bsd + fi + exit 0 ;; + ppc*:SunOS:5.*:*) + echo ppc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit 0 ;; + prep*:SunOS:5.*:*) + echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit 0 ;; + i86pc:SunOS:5.*:*) + echo i386-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit 0 ;; + sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) + echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit 0 ;; + sun4*:SunOS:6*:*) + # According to config.sub, this is the proper way to canonicalize + # SunOS6. Hard to guess exactly what SunOS6 will be like, but + # it's likely to be more like Solaris than SunOS4. + echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit 0 ;; + sun4*:SunOS:*:*) + case "`/usr/bin/arch -k`" in + Series*|S4*) + UNAME_RELEASE=`uname -v` + ;; + esac + # Japanese Language versions have a version number like `4.1.3-JL'. + echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'` + exit 0 ;; + sun3*:SunOS:*:*) + echo m68k-sun-sunos${UNAME_RELEASE} + exit 0 ;; + aushp:SunOS:*:*) + echo sparc-auspex-sunos${UNAME_RELEASE} + exit 0 ;; + RISC*:ULTRIX:*:*) + echo mips-dec-ultrix${UNAME_RELEASE} + exit 0 ;; + VAX*:ULTRIX*:*:*) + echo vax-dec-ultrix${UNAME_RELEASE} + exit 0 ;; + sparc:UNIX_SV:4.*:*) + echo sparc-unknown-sysv${UNAME_RELEASE} + exit 0 ;; + mips:UNIX_SV:4.*:*) + echo mips-mips-sysv${UNAME_RELEASE} + exit 0 ;; + mips:OSF*1:*:*) + echo mips-mips-osf1 + exit 0 ;; + mips:4.4BSD:*:*) + echo mips-mips-bsd4.4 + exit 0 ;; + mips:*:*:UMIPS | mips:*:*:RISCos) + sed 's/^ //' << EOF >dummy.c + int main (argc, argv) int argc; char **argv; { + #if defined (host_mips) && defined (MIPSEB) + #if defined (SYSTYPE_SYSV) + printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_SVR4) + printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) + printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0); + #endif + #endif + exit (-1); + } +EOF + ${CC-cc} dummy.c -o dummy \ + && ./dummy `echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` \ + && rm dummy.c dummy && exit 0 + rm -f dummy.c dummy + echo mips-mips-riscos${UNAME_RELEASE} + exit 0 ;; + MIServer-S:SMP_DC.OSx:*:dcosx) + echo mips-pyramid-sysv4 + exit 0 ;; + Night_Hawk:Power_UNIX:*:*) + echo powerpc-harris-powerunix + exit 0 ;; + news*:NEWS*:*:*) + echo mips-sony-newsos${UNAME_RELEASE} + exit 0 ;; + m88k:CX/UX:7*:*) + echo m88k-harris-cxux7 + exit 0 ;; + m88k:*:4*:R4*) + echo m88k-motorola-sysv4 + exit 0 ;; + m88k:*:3*:R3*) + echo m88k-motorola-sysv3 + exit 0 ;; + AViiON:dgux:*:*) + # DG/UX returns AViiON for all architectures + UNAME_PROCESSOR=`uname -p` + if [ $UNAME_PROCESSOR = mc88100 -o $UNAME_PROCESSOR = mc88110 ] ; then + if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx \ + -o ${TARGET_BINARY_INTERFACE}x = x ] ; then + echo m88k-dg-dgux${UNAME_RELEASE} + else + echo m88k-dg-dguxbcs${UNAME_RELEASE} + fi + else echo i586-dg-dgux${UNAME_RELEASE} + fi + exit 0 ;; + M88*:DolphinOS:*:*) # DolphinOS (SVR3) + echo m88k-dolphin-sysv3 + exit 0 ;; + M88*:*:R3*:*) + # Delta 88k system running SVR3 + echo m88k-motorola-sysv3 + exit 0 ;; + XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) + echo m88k-tektronix-sysv3 + exit 0 ;; + Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) + echo m68k-tektronix-bsd + exit 0 ;; + i?86:NEXTSTEP:*:*) + echo i386-next-nextstep${RELEASE} + exit 0 ;; + *680?0:NEXTSTEP:*:*) + echo m68k-next-nextstep${RELEASE} + exit 0 ;; + *:IRIX*:*:*) + echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` + exit 0 ;; + ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. + echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id + exit 0 ;; # Note that: echo "'`uname -s`'" gives 'AIX ' + i?86:AIX:*:*) + echo i386-ibm-aix + exit 0 ;; + *370:AIX:*:*) + echo ibm370-ibm-aix + exit 0 ;; + *:AIX:2:3) + if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then + sed 's/^ //' << EOF >dummy.c + #include + + main() + { + if (!__power_pc()) + exit(1); + puts("powerpc-ibm-aix3.2.5"); + exit(0); + } +EOF + ${CC-cc} dummy.c -o dummy && ./dummy && rm dummy.c dummy && exit 0 + rm -f dummy.c dummy + echo rs6000-ibm-aix3.2.5 + elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then + echo rs6000-ibm-aix3.2.4 + else + echo rs6000-ibm-aix3.2 + fi + exit 0 ;; + *:AIX:*:4) + if /usr/sbin/lsattr -EHl proc0 | grep POWER >/dev/null 2>&1; then + IBM_ARCH=rs6000 + else + IBM_ARCH=powerpc + fi + if [ -x /usr/bin/oslevel ] ; then + IBM_REV=`/usr/bin/oslevel` + elif grep bos410 /usr/include/stdio.h >/dev/null 2>&1; then + IBM_REV=4.1 + elif grep bos411 /usr/include/stdio.h >/dev/null 2>&1; then + IBM_REV=4.1.1 + else + IBM_REV=4.${UNAME_RELEASE} + fi + echo ${IBM_ARCH}-ibm-aix${IBM_REV} + exit 0 ;; + *:AIX:*:*) + echo rs6000-ibm-aix + exit 0 ;; + ibmrt:4.4BSD:*|romp-ibm:BSD:*) + echo romp-ibm-bsd4.4 + exit 0 ;; + ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC NetBSD and + echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to + exit 0 ;; # report: romp-ibm BSD 4.3 + *:BOSX:*:*) + echo rs6000-bull-bosx + exit 0 ;; + DPX/2?00:B.O.S.:*:*) + echo m68k-bull-sysv3 + exit 0 ;; + 9000/[34]??:4.3bsd:1.*:*) + echo m68k-hp-bsd + exit 0 ;; + hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) + echo m68k-hp-bsd4.4 + exit 0 ;; + 9000/[3478]??:HP-UX:*:*) + case "${UNAME_MACHINE}" in + 9000/31? ) HP_ARCH=m68000 ;; + 9000/[34]?? ) HP_ARCH=m68k ;; + 9000/7?? | 9000/8?[679] ) HP_ARCH=hppa1.1 ;; + 9000/8?? ) HP_ARCH=hppa1.0 ;; + esac + HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` + echo ${HP_ARCH}-hp-hpux${HPUX_REV} + exit 0 ;; + 3050*:HI-UX:*:*) + sed 's/^ //' << EOF >dummy.c + #include + int + main () + { + long cpu = sysconf (_SC_CPU_VERSION); + /* The order matters, because CPU_IS_HP_MC68K erroneously returns + true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct + results, however. */ + if (CPU_IS_PA_RISC (cpu)) + { + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; + case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; + default: puts ("hppa-hitachi-hiuxwe2"); break; + } + } + else if (CPU_IS_HP_MC68K (cpu)) + puts ("m68k-hitachi-hiuxwe2"); + else puts ("unknown-hitachi-hiuxwe2"); + exit (0); + } +EOF + ${CC-cc} dummy.c -o dummy && ./dummy && rm dummy.c dummy && exit 0 + rm -f dummy.c dummy + echo unknown-hitachi-hiuxwe2 + exit 0 ;; + 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) + echo hppa1.1-hp-bsd + exit 0 ;; + 9000/8??:4.3bsd:*:*) + echo hppa1.0-hp-bsd + exit 0 ;; + hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* ) + echo hppa1.1-hp-osf + exit 0 ;; + hp8??:OSF1:*:*) + echo hppa1.0-hp-osf + exit 0 ;; + parisc*:Lites*:*:*) + echo hppa1.1-hp-lites + exit 0 ;; + C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) + echo c1-convex-bsd + exit 0 ;; + C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) + if getsysinfo -f scalar_acc + then echo c32-convex-bsd + else echo c2-convex-bsd + fi + exit 0 ;; + C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) + echo c34-convex-bsd + exit 0 ;; + C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) + echo c38-convex-bsd + exit 0 ;; + C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) + echo c4-convex-bsd + exit 0 ;; + CRAY*X-MP:*:*:*) + echo xmp-cray-unicos + exit 0 ;; + CRAY*Y-MP:*:*:*) + echo ymp-cray-unicos${UNAME_RELEASE} + exit 0 ;; + CRAY*[A-Z]90:*:*:*) + echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ + | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ + -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ + exit 0 ;; + CRAY*TS:*:*:*) + echo t90-cray-unicos${UNAME_RELEASE} + exit 0 ;; + CRAY-2:*:*:*) + echo cray2-cray-unicos + exit 0 ;; + F300:UNIX_System_V:*:*) + FUJITSU_SYS=`uname -p | tr [A-Z] [a-z] | sed -e 's/\///'` + FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` + echo "f300-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + exit 0 ;; + F301:UNIX_System_V:*:*) + echo f301-fujitsu-uxpv`echo $UNAME_RELEASE | sed 's/ .*//'` + exit 0 ;; + i?86:BSD/386:*:* | *:BSD/OS:*:*) + echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} + exit 0 ;; + *:FreeBSD:*:*) + echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` + exit 0 ;; + *:NetBSD:*:*) + echo ${UNAME_MACHINE}-unknown-netbsd`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` + exit 0 ;; + *:OpenBSD:*:*) + echo ${UNAME_MACHINE}-unknown-openbsd`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` + exit 0 ;; + i*:CYGWIN*:*) + echo i386-pc-cygwin32 + exit 0 ;; + p*:CYGWIN*:*) + echo powerpcle-unknown-cygwin32 + exit 0 ;; + *:GNU:*:*) + echo `echo ${UNAME_MACHINE}|sed -e 's,/.*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` + exit 0 ;; + *:Linux:*:*) + # The BFD linker knows what the default object file format is, so + # first see if it will tell us. + ld_help_string=`ld --help 2>&1` + if echo $ld_help_string | grep >/dev/null 2>&1 "supported emulations: elf_i[345]86"; then + echo "${UNAME_MACHINE}-unknown-linux" ; exit 0 + elif echo $ld_help_string | grep >/dev/null 2>&1 "supported emulations: i[345]86linux"; then + echo "${UNAME_MACHINE}-unknown-linuxaout" ; exit 0 + elif echo $ld_help_string | grep >/dev/null 2>&1 "supported emulations: i[345]86coff"; then + echo "${UNAME_MACHINE}-unknown-linuxcoff" ; exit 0 + elif test "${UNAME_MACHINE}" = "alpha" ; then + echo alpha-unknown-linux ; exit 0 + elif test "${UNAME_MACHINE}" = "sparc" ; then + echo sparc-unknown-linux ; exit 0 + else + # Either a pre-BFD a.out linker (linuxoldld) or one that does not give us + # useful --help. Gcc wants to distinguish between linuxoldld and linuxaout. + test ! -d /usr/lib/ldscripts/. \ + && echo "${UNAME_MACHINE}-unknown-linuxoldld" && exit 0 + # Determine whether the default compiler is a.out or elf + cat >dummy.c </dev/null && ./dummy "${UNAME_MACHINE}" && rm dummy.c dummy && exit 0 + rm -f dummy.c dummy + fi ;; +# ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. earlier versions +# are messed up and put the nodename in both sysname and nodename. + i?86:DYNIX/ptx:4*:*) + echo i386-sequent-sysv4 + exit 0 ;; + i?86:OSF1:*:*) + echo i386-unknown-osf1 + exit 0 ;; + i?86:*:4.*:* | i?86:SYSTEM_V:4.*:* | i[34]86:UNIX_SV:4.*:*) + if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then + echo ${UNAME_MACHINE}-univel-sysv${UNAME_RELEASE} + else + echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE} + fi + exit 0 ;; + i?86:*:3.2:*) + if test -f /usr/options/cb.name; then + UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then + UNAME_REL=`(/bin/uname -X|egrep Release|sed -e 's/.*= //')` + (/bin/uname -X|egrep i80486 >/dev/null) && UNAME_MACHINE=i486 + (/bin/uname -X|egrep '^Machine.*Pentium' >/dev/null) \ + && UNAME_MACHINE=i586 + echo ${UNAME_MACHINE}-unknown-sco$UNAME_REL + else + echo ${UNAME_MACHINE}-unknown-sysv32 + fi + exit 0 ;; + Intel:Mach:3*:*) + echo i386-unknown-mach3 + exit 0 ;; + paragon:*:*:*) + echo i860-intel-osf1 + exit 0 ;; + i860:*:4.*:*) # i860-SVR4 + if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then + echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4 + else # Add other i860-SVR4 vendors below as they are discovered. + echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4 + fi + exit 0 ;; + ksr1:OSF*1:*:*) + echo ksr1-ksr-osf1 + exit 0 ;; + esa:OSF*1:*:* | ESA:OSF*:*:*) + echo esa-ibm-osf1 + exit 0 ;; + mini*:CTIX:SYS*5:*) + # "miniframe" + echo m68010-convergent-sysv + exit 0 ;; + M68*:*:R3V[567]*:*) + test -r /sysV68 && echo 'm68k-motorola-sysv' && exit 0 ;; + 3[34]??:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 4850:*:4.0:3.0) + OS_REL='' + test -r /etc/.relid \ + && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && echo i486-ncr-sysv4.3${OS_REL} && exit 0 + /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ + && echo i586-ncr-sysv4.3${OS_REL} && exit 0 ;; + 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && echo i486-ncr-sysv4 && exit 0 ;; + mc68030:UNIX_System_V:4.*:*) + echo m68k-atari-sysv4 + exit 0 ;; + m68*:LynxOS:2.*:*) + echo m68k-lynx-lynxos${UNAME_RELEASE} + exit 0 ;; + i?86:LynxOS:2.*:*) + echo i386-lynx-lynxos${UNAME_RELEASE} + exit 0 ;; + TSUNAMI:LynxOS:2.*:*) + echo sparc-lynx-lynxos${UNAME_RELEASE} + exit 0 ;; + rs6000:LynxOS:2.*:* | PowerPC:LynxOS:2.*:*) + echo rs6000-lynx-lynxos${UNAME_RELEASE} + exit 0 ;; + *:LynxOS:*:*) + echo ${UNAME_MACHINE}-unknown-lynxos${UNAME_RELEASE} + exit 0 ;; + SM[BE]S:UNIX_SV:*:*) + echo mips-dde-sysv${UNAME_RELEASE} + exit 0 ;; + DNP*:DNIX:*:*) + echo m68k-dnix-sysv + exit 0 ;; + RM*:SINIX-*:*:*) + echo mips-sni-sysv4 + exit 0 ;; + *:SINIX-*:*:*) + if uname -p 2>/dev/null >/dev/null ; then + UNAME_MACHINE=`(uname -p) 2>/dev/null` + echo ${UNAME_MACHINE}-sni-sysv4 + else + echo ns32k-sni-sysv + fi + exit 0 ;; + *:UNIX_System_V:4*:FTX*) + # From Gerald Hewes . + # How about differentiating between stratus architectures? -djm + echo hppa1.1-stratus-sysv4 + exit 0 ;; + *:*:*:FTX*) + # From seanf@swdc.stratus.com. + echo i860-stratus-sysv4 + exit 0 ;; + mc68*:A/UX:*:*) + echo m68k-apple-aux${UNAME_RELEASE} + exit 0 ;; + R3000:*System_V*:*:* | R4000:UNIX_SYSV:*:*) + if [ -d /usr/nec ]; then + echo mips-nec-sysv${UNAME_RELEASE} + else + echo mips-unknown-sysv${UNAME_RELEASE} + fi + exit 0 ;; + PENTIUM:CPunix:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort + # says + echo i586-unisys-sysv4 + exit 0 ;; + *3b2*:*:*:*) + echo we32k-att-sysv3 + exit 0 ;; +esac + +#echo '(No uname command or uname output not recognized.)' 1>&2 +#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2 + +cat >dummy.c < +# include +#endif +main () +{ +#if defined (sony) +#if defined (MIPSEB) + /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, + I don't know.... */ + printf ("mips-sony-bsd\n"); exit (0); +#else +#include + printf ("m68k-sony-newsos%s\n", +#ifdef NEWSOS4 + "4" +#else + "" +#endif + ); exit (0); +#endif +#endif + +#if defined (__arm) && defined (__acorn) && defined (__unix) + printf ("arm-acorn-riscix\n"); exit (0); +#endif + +#if defined (hp9000) && !defined (hpux) + printf ("m68k-hp-bsd\n"); exit (0); +#endif + +#if defined (hp300) && !defined (hpux) + printf ("m68k-hp-bsd\n"); exit (0); +#endif + +#if defined (NeXT) +#if !defined (__ARCHITECTURE__) +#define __ARCHITECTURE__ "m68k" +#endif + int version; + version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; + printf ("%s-next-nextstep%s\n", __ARCHITECTURE__, version==2 ? "2" : "3"); + exit (0); +#endif + +#if defined (MULTIMAX) || defined (n16) +#if defined (UMAXV) + printf ("ns32k-encore-sysv\n"); exit (0); +#else +#if defined (CMU) + printf ("ns32k-encore-mach\n"); exit (0); +#else + printf ("ns32k-encore-bsd\n"); exit (0); +#endif +#endif +#endif + +#if defined (__386BSD__) + printf ("i386-unknown-bsd\n"); exit (0); +#endif + +#if defined (sequent) +#if defined (i386) + printf ("i386-sequent-dynix\n"); exit (0); +#endif +#if defined (ns32000) + printf ("ns32k-sequent-dynix\n"); exit (0); +#endif +#endif + +#if defined (_SEQUENT_) + struct utsname un; + + uname(&un); + + if (strncmp(un.version, "V2", 2) == 0) { + printf ("i386-sequent-ptx2\n"); exit (0); + } + if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ + printf ("i386-sequent-ptx1\n"); exit (0); + } + printf ("i386-sequent-ptx\n"); exit (0); + +#endif + +#if defined (vax) +#if !defined (ultrix) + printf ("vax-dec-bsd\n"); exit (0); +#else + printf ("vax-dec-ultrix\n"); exit (0); +#endif +#endif + +#if defined (alliant) && defined (i860) + printf ("i860-alliant-bsd\n"); exit (0); +#endif + +#if defined (tahoe) + printf ("tahoe-cci-bsd\n"); exit (0); +#endif + +#if defined (nec_ews) +# if defined (SYSTYPE_SYSV) + printf ("ews4800-nec-sysv4\n"); exit 0; +# else + printf ("ews4800-nec-bsd\n"); exit (0); +# endif +#endif + +#if defined (sony) +# if defined (SYSTYPE_SYSV) + printf ("mips-sony-sysv4\n"); exit 0; +# else + printf ("mips-sony-bsd\n"); exit (0); +# endif +#endif + +#if defined (ardent) + printf ("titan-ardent-bsd\n"); exit (0); +#endif + +#if defined (stardent) + printf ("stardent-stardent-sysv\n"); exit (0); +#endif + +#if defined (ibm032) + printf ("ibmrt-ibm-bsd4.3\n"); exit (0); +#endif + +#if defined (sequent) && defined (i386) + printf ("i386-sequent-bsd\n"); exit (0); +#endif + +#if defined (qnx) && defined (i386) + printf ("i386-unknown-qnx\n"); exit (0); +#endif + +#if defined (gould) + printf ("gould-gould-bsd\n"); exit (0); +#endif + +#if defined (unixpc) + printf ("unixpc-att-sysv\n"); exit (0); +#endif + +#if defined (att386) + printf ("i386-att-sysv3\n"); exit (0); +#endif + +#if defined (__m88k) && defined (__UMAXV__) + printf ("m88k-encore-sysv3\n"); exit (0); +#endif + +#if defined (drs6000) + printf ("drs6000-icl-sysv4.2\n"); exit (0); +#endif + +#if defined (clipper) + printf ("clipper-orion-bsd\n"); exit (0); +#endif + +#if defined (is68k) + printf ("m68k-isi-bsd\n"); exit (0); +#endif + +#if defined (luna88k) + printf ("luna88k-omron-bsd\n"); exit (0); +#endif + +#if defined (butterfly) && defined (BFLY1) + printf ("butterfly-bbn-mach\n"); exit (0); +#endif + +#if defined (tower32) + printf ("tower32-ncr-sysv4\n"); exit (0); +#endif + +#if defined (MagicStation) + printf ("magicstation-unknown-bsd\n"); exit (0); +#endif + +#if defined (scs) + printf ("symmetric-scs-bsd4.2\n"); exit (0); +#endif + +#if defined (tandem) + printf ("tandem-tandem-sysv\n"); exit (0); +#endif + +#if defined (cadmus) + printf ("cadmus-pcs-sysv\n"); exit (0); +#endif + +#if defined (masscomp) + printf ("masscomp-masscomp-sysv3\n"); exit (0); +#endif + +#if defined (hbullx20) + printf ("hbullx20-bull-sysv3\n"); exit (0); +#endif + + exit (1); +} +EOF + +${CC-cc} dummy.c -o dummy 2>/dev/null && ./dummy && rm dummy.c dummy && exit 0 +rm -f dummy.c dummy + +# Apollos put the system type in the environment. + +test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit 0; } + +# Convex versions that predate uname can use getsysinfo(1) + +if [ -x /usr/convex/getsysinfo ] +then + case `getsysinfo -f cpu_type` in + c1*) + echo c1-convex-bsd + exit 0 ;; + c2*) + if getsysinfo -f scalar_acc + then echo c32-convex-bsd + else echo c2-convex-bsd + fi + exit 0 ;; + c34*) + echo c34-convex-bsd + exit 0 ;; + c38*) + echo c38-convex-bsd + exit 0 ;; + c4*) + echo c4-convex-bsd + exit 0 ;; + esac +fi + +case "$UNAME" in +uts) echo uts-amdahl-sysv${UNAME_RELEASE}; exit 0 ;; +esac + +if [ -d /usr/amiga ]; then + echo m68k-cbm-sysv${UNAME_RELEASE}; exit 0; +fi + +if [ -f /bin/fxc.info ]; then + echo fxc-alliant-concentrix + exit 0 +fi + +#echo '(Unable to guess system type)' 1>&2 + +exit 1 diff --git a/support/config.sub b/support/config.sub new file mode 100755 index 0000000..cd1299a --- /dev/null +++ b/support/config.sub @@ -0,0 +1,903 @@ +#! /bin/sh +# Configuration validation subroutine script, version 1.1. +# Copyright (C) 1991, 92, 93, 94, 95, 1996 Free Software Foundation, Inc. +# This file is (in principle) common to ALL GNU software. +# The presence of a machine in this file suggests that SOME GNU software +# can handle that machine. It does not imply ALL GNU software can. +# +# This file 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 of the License, or +# (at your option) any later version. +# +# This program 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 this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# Configuration subroutine to validate and canonicalize a configuration type. +# Supply the specified configuration type as an argument. +# If it is invalid, we print an error message on stderr and exit with code 1. +# Otherwise, we print the canonical config type on stdout and succeed. + +# This file is supposed to be the same for all GNU packages +# and recognize all the CPU types, system types and aliases +# that are meaningful with *any* GNU software. +# Each package is responsible for reporting which valid configurations +# it does not support. The user should be able to distinguish +# a failure to support a valid configuration from a meaningless +# configuration. + +# The goal of this file is to map all the various variations of a given +# machine specification into a single specification in the form: +# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM +# It is wrong to echo any other type of specification. + +if [ x$1 = x ] +then + echo Configuration name missing. 1>&2 + echo "Usage: $0 CPU-MFR-OPSYS" 1>&2 + echo "or $0 ALIAS" 1>&2 + echo where ALIAS is a recognized configuration type. 1>&2 + exit 1 +fi + +# First pass through any local machine types. +case $1 in + *local*) + echo $1 + exit 0 + ;; + *) + ;; +esac + +# Separate what the user gave into CPU-COMPANY and OS (if any). +basic_machine=`echo $1 | sed 's/-[^-]*$//'` +if [ $basic_machine != $1 ] +then os=`echo $1 | sed 's/.*-/-/'` +else os=; fi + +### Let's recognize common machines as not being operating systems so +### that things like config.sub decstation-3100 work. We also +### recognize some manufacturers as not being operating systems, so we +### can provide default operating systems below. +case $os in + -sun*os*) + # Prevent following clause from handling this invalid input. + ;; + -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \ + -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \ + -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \ + -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ + -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ + -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp ) + os= + basic_machine=$1 + ;; + -hiux*) + os=-hiuxwe2 + ;; + -sco5) + os=sco3.2v5 + basic_machine=`echo $1 | sed -e 's/86-.*/86-unknown/'` + ;; + -sco4) + os=-sco3.2v4 + basic_machine=`echo $1 | sed -e 's/86-.*/86-unknown/'` + ;; + -sco3.2.[4-9]*) + os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` + basic_machine=`echo $1 | sed -e 's/86-.*/86-unknown/'` + ;; + -sco3.2v[4-9]*) + # Don't forget version if it is 3.2v4 or newer. + basic_machine=`echo $1 | sed -e 's/86-.*/86-unknown/'` + ;; + -sco*) + os=-sco3.2v2 + basic_machine=`echo $1 | sed -e 's/86-.*/86-unknown/'` + ;; + -isc) + os=-isc2.2 + basic_machine=`echo $1 | sed -e 's/86-.*/86-unknown/'` + ;; + -clix*) + basic_machine=clipper-intergraph + ;; + -isc*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-unknown/'` + ;; + -lynx*) + os=-lynxos + ;; + -ptx*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'` + ;; + -windowsnt*) + os=`echo $os | sed -e 's/windowsnt/winnt/'` + ;; +esac + +# Decode aliases for certain CPU-COMPANY combinations. +case $basic_machine in + # Recognize the basic CPU types without company name. + # Some are omitted here because they have special meanings below. + tahoe | i[3456]86 | i860 | m68k | m68000 | m88k | ns32k | arm \ + | arme[lb] | pyramid \ + | tron | a29k | 580 | i960 | h8300 | hppa1.0 | hppa1.1 \ + | alpha | we32k | ns16k | clipper | sparclite | i370 | sh \ + | powerpc | powerpcle | sparc64 | 1750a | dsp16xx | mips64 | mipsel \ + | pdp11 | mips64el | mips64orion | mips64orionel \ + | sparc) + basic_machine=$basic_machine-unknown + ;; + # Object if more than one company name word. + *-*-*) + echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 + exit 1 + ;; + # Recognize the basic CPU types with company name. + vax-* | tahoe-* | i[3456]86-* | i860-* | m68k-* | m68000-* | m88k-* \ + | sparc-* | ns32k-* | fx80-* | arm-* | c[123]* \ + | mips-* | pyramid-* | tron-* | a29k-* | romp-* | rs6000-* | power-* \ + | none-* | 580-* | cray2-* | h8300-* | i960-* | xmp-* | ymp-* \ + | hppa1.0-* | hppa1.1-* | alpha-* | we32k-* | cydra-* | ns16k-* \ + | pn-* | np1-* | xps100-* | clipper-* | orion-* | sparclite-* \ + | c90-* | t90-* \ + | pdp11-* | sh-* | powerpc-* | powerpcle-* | sparc64-* | mips64-* | mipsel-* \ + | mips64el-* | mips64orion-* | mips64orionel-* | butterfly-bbn* \ + | cadmus-* | ews*-nec | ibmrt-ibm* | masscomp-masscomp \ + | tandem-* | symmetric-* | drs6000-icl | *-*ardent | gould-gould \ + | concurrent-* | ksr1-* | esa-ibm | fxc-alliant | *370-amdahl \ + | *-convex) + ;; + # Recognize the various machine names and aliases which stand + # for a CPU type and a company and sometimes even an OS. + 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc*) + basic_machine=m68000-att + ;; + 3b*) + basic_machine=we32k-att + ;; + alliant | fx80) + basic_machine=fx80-alliant + ;; + altos | altos3068) + basic_machine=m68k-altos + ;; + am29k) + basic_machine=a29k-none + os=-bsd + ;; + amdahl) + basic_machine=580-amdahl + os=-sysv + ;; + amiga | amiga-*) + basic_machine=m68k-cbm + ;; + amigados) + basic_machine=m68k-cbm + os=-amigados + ;; + amigaunix | amix) + basic_machine=m68k-cbm + os=-sysv4 + ;; + apollo68) + basic_machine=m68k-apollo + os=-sysv + ;; + balance) + basic_machine=ns32k-sequent + os=-dynix + ;; + convex-c1) + basic_machine=c1-convex + os=-bsd + ;; + convex-c2) + basic_machine=c2-convex + os=-bsd + ;; + convex-c32) + basic_machine=c32-convex + os=-bsd + ;; + convex-c34) + basic_machine=c34-convex + os=-bsd + ;; + convex-c38) + basic_machine=c38-convex + os=-bsd + ;; + c90) + basic_machine=c90-cray + os=-unicos + ;; + t90) + basic_machine=t90-cray + os=-unicos + ;; + cray | ymp) + basic_machine=ymp-cray + os=-unicos + ;; + cray2) + basic_machine=cray2-cray + os=-unicos + ;; + crds | unos) + basic_machine=m68k-crds + ;; + da30 | da30-*) + basic_machine=m68k-da30 + ;; + decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) + basic_machine=mips-dec + ;; + delta | 3300 | motorola-3300 | motorola-delta \ + | 3300-motorola | delta-motorola) + basic_machine=m68k-motorola + ;; + delta88) + basic_machine=m88k-motorola + os=-sysv3 + ;; + dpx20 | dpx20-*) + basic_machine=rs6000-bull + os=-bosx + ;; + dpx2* | dpx2*-bull) + basic_machine=m68k-bull + os=-sysv3 + ;; + hbullx20-bull) + basic_machine=m68k-bull + ;; + ebmon29k) + basic_machine=a29k-amd + os=-ebmon + ;; + elxsi) + basic_machine=elxsi-elxsi + os=-bsd + ;; + encore | umax | mmax | multimax) + basic_machine=ns32k-encore + ;; + fx2800) + basic_machine=i860-alliant + ;; + genix) + basic_machine=ns32k-ns + ;; + gmicro) + basic_machine=tron-gmicro + os=-sysv + ;; + h3050r* | hiux*) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + h8300hms) + basic_machine=h8300-hitachi + os=-hms + ;; + harris) + basic_machine=m88k-harris + os=-sysv3 + ;; + hp300-*) + basic_machine=m68k-hp + ;; + hp300bsd) + basic_machine=m68k-hp + os=-bsd + ;; + hp300hpux) + basic_machine=m68k-hp + os=-hpux + ;; + hp9k2[0-9][0-9] | hp9k31[0-9]) + basic_machine=m68000-hp + ;; + hp9k3[2-9][0-9]) + basic_machine=m68k-hp + ;; + hp9k7[0-9][0-9] | hp7[0-9][0-9] | hp9k8[0-9]7 | hp8[0-9]7) + basic_machine=hppa1.1-hp + ;; + hp9k8[0-9][0-9] | hp8[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + ibm032-*) + basic_machine=ibmrt-ibm + ;; + i370-ibm* | ibm*) + basic_machine=i370-ibm + os=-mvs + ;; +# I'm not sure what "Sysv32" means. Should this be sysv3.2? + i[3456]86v32) + basic_machine=`echo $1 | sed -e 's/86.*/86-unknown/'` + os=-sysv32 + ;; + i[3456]86v4*) + basic_machine=`echo $1 | sed -e 's/86.*/86-unknown/'` + os=-sysv4 + ;; + i[3456]86v) + basic_machine=`echo $1 | sed -e 's/86.*/86-unknown/'` + os=-sysv + ;; + i[3456]86sol2) + basic_machine=`echo $1 | sed -e 's/86.*/86-unknown/'` + os=-solaris2 + ;; + iris | iris4d) + basic_machine=mips-sgi + case $os in + -irix*) + ;; + *) + os=-irix4 + ;; + esac + ;; + isi68 | isi) + basic_machine=m68k-isi + os=-sysv + ;; + luna88k-omron* | m88k-omron*) + basic_machine=m88k-omron + ;; + magicstation*) + basic_machine=magicstation-unknown + ;; + magnum | m3230) + basic_machine=mips-mips + os=-sysv + ;; + merlin) + basic_machine=ns32k-utek + os=-sysv + ;; + miniframe) + basic_machine=m68000-convergent + ;; + mips3*-*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` + ;; + mips3*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown + ;; + ncr3000) + basic_machine=i486-ncr + os=-sysv4 + ;; + news | news700 | news800 | news900) + basic_machine=m68k-sony + os=-newsos + ;; + news1000) + basic_machine=m68030-sony + os=-newsos + ;; + news-3600 | risc-news) + basic_machine=mips-sony + os=-newsos + ;; + next | m*-next ) + basic_machine=m68k-next + case $os in + -nextstep* ) + ;; + -ns2*) + os=-nextstep2 + ;; + *) + os=-nextstep3 + ;; + esac + ;; + nh3000) + basic_machine=m68k-harris + os=-cxux + ;; + nh[45]000) + basic_machine=m88k-harris + os=-cxux + ;; + nindy960) + basic_machine=i960-intel + os=-nindy + ;; + np1) + basic_machine=np1-gould + ;; + pa-hitachi) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + paragon) + basic_machine=i860-intel + os=-osf + ;; + pbd) + basic_machine=sparc-tti + ;; + pbb) + basic_machine=m68k-tti + ;; + pc532 | pc532-*) + basic_machine=ns32k-pc532 + ;; + pentium | p5) + basic_machine=i586-intel + ;; + pentiumpro | p6) + basic_machine=i686-intel + ;; + pentium-* | p5-*) + basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentiumpro-* | p6-*) + basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + k5) + # We don't have specific support for AMD's K5 yet, so just call it a Pentium + basic_machine=i586-amd + ;; + nexen) + # We don't have specific support for Nexgen yet, so just call it a Pentium + basic_machine=i586-nexgen + ;; + pn) + basic_machine=pn-gould + ;; + power) basic_machine=rs6000-ibm + ;; + ppc) basic_machine=powerpc-unknown + ;; + ppc-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppcle | powerpclittle | ppc-le | powerpc-little) + basic_machine=powerpcle-unknown + ;; + ppcle-* | powerpclittle-*) + basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ps2) + basic_machine=i386-ibm + ;; + rm[46]00) + basic_machine=mips-siemens + ;; + rtpc | rtpc-*) + basic_machine=romp-ibm + ;; + sequent) + basic_machine=i386-sequent + ;; + sh) + basic_machine=sh-hitachi + os=-hms + ;; + sps7) + basic_machine=m68k-bull + os=-sysv2 + ;; + spur) + basic_machine=spur-unknown + ;; + sun2) + basic_machine=m68000-sun + ;; + sun2os3) + basic_machine=m68000-sun + os=-sunos3 + ;; + sun2os4) + basic_machine=m68000-sun + os=-sunos4 + ;; + sun3os3) + basic_machine=m68k-sun + os=-sunos3 + ;; + sun3os4) + basic_machine=m68k-sun + os=-sunos4 + ;; + sun4os3) + basic_machine=sparc-sun + os=-sunos3 + ;; + sun4os4) + basic_machine=sparc-sun + os=-sunos4 + ;; + sun4sol2) + basic_machine=sparc-sun + os=-solaris2 + ;; + sun3 | sun3-*) + basic_machine=m68k-sun + ;; + sun4) + basic_machine=sparc-sun + ;; + sun386 | sun386i | roadrunner) + basic_machine=i386-sun + ;; + symmetry) + basic_machine=i386-sequent + os=-dynix + ;; + tower | tower-32) + basic_machine=m68k-ncr + ;; + udi29k) + basic_machine=a29k-amd + os=-udi + ;; + ultra3) + basic_machine=a29k-nyu + os=-sym1 + ;; + vaxv) + basic_machine=vax-dec + os=-sysv + ;; + vms) + basic_machine=vax-dec + os=-vms + ;; + vxworks960) + basic_machine=i960-wrs + os=-vxworks + ;; + vxworks68) + basic_machine=m68k-wrs + os=-vxworks + ;; + vxworks29k) + basic_machine=a29k-wrs + os=-vxworks + ;; + xmp) + basic_machine=xmp-cray + os=-unicos + ;; + xps | xps100) + basic_machine=xps100-honeywell + ;; + none) + basic_machine=none-none + os=-none + ;; + +# Here we handle the default manufacturer of certain CPU types. It is in +# some cases the only manufacturer, in others, it is the most popular. + mips) + basic_machine=mips-mips + ;; + romp) + basic_machine=romp-ibm + ;; + rs6000) + basic_machine=rs6000-ibm + ;; + vax) + basic_machine=vax-dec + ;; + pdp11) + basic_machine=pdp11-dec + ;; + we32k) + basic_machine=we32k-att + ;; + sparc) + basic_machine=sparc-sun + ;; + cydra) + basic_machine=cydra-cydrome + ;; + orion) + basic_machine=orion-highlevel + ;; + orion105) + basic_machine=clipper-highlevel + ;; + *) + echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 + exit 1 + ;; +esac + +# Here we canonicalize certain aliases for manufacturers. +case $basic_machine in + *-digital*) + basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'` + ;; + *-commodore*) + basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'` + ;; + *) + ;; +esac + +# Decode manufacturer-specific aliases for certain operating systems. + +if [ x"$os" != x"" ] +then +case $os in + # -solaris* is a basic system type, with this one exception. + -solaris1 | -solaris1.*) + os=`echo $os | sed -e 's|solaris1|sunos4|'` + ;; + -solaris) + os=-solaris2 + ;; + -unixware* | svr4*) + os=-sysv4 + ;; + -gnu/linux*) + os=`echo $os | sed -e 's|gnu/linux|linux|'` + ;; + # First accept the basic system types. + # The portable systems comes first. + # Each alternative MUST END IN A *, to match a version number. + # -sysv* is not here because it comes later, after sysvr4. + -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ + | -vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[3456]* \ + | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \ + | -amigados* | -msdos* | -newsos* | -unicos* | -aof* | -aos* \ + | -nindy* | -vxworks* | -ebmon* | -hms* | -mvs* | -clix* \ + | -riscos* | -linux* | -uniplus* | -iris* | -rtu* | -xenix* \ + | -hiux* | -386bsd* | -netbsd* | -freebsd* | -riscix* \ + | -lynxos* | -bosx* | -nextstep* | -cxux* | -aout* | -elf* \ + | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ + | -udi* | -eabi* | -lites* | -ieee* | -go32* | -qnx*) + # Remember, each alternative MUST END IN *, to match a version number. + ;; + -sunos5*) + os=`echo $os | sed -e 's|sunos5|solaris2|'` + ;; + -sunos6*) + os=`echo $os | sed -e 's|sunos6|solaris3|'` + ;; + -osfrose*) + os=-osfrose + ;; + -osf*) + os=-osf + ;; + -utek*) + os=-bsd + ;; + -dynix*) + os=-bsd + ;; + -acis*) + os=-aos + ;; + -ctix* | -uts*) + os=-sysv + ;; + -ns2 ) + os=-nextstep2 + ;; + # Preserve the version number of sinix5. + -sinix5.*) + os=`echo $os | sed -e 's|sinix|sysv|'` + ;; + -sinix*) + os=-sysv4 + ;; + -triton*) + os=-sysv3 + ;; + -oss*) + os=-sysv3 + ;; + -svr4) + os=-sysv4 + ;; + -svr3) + os=-sysv3 + ;; + -sysvr4) + os=-sysv4 + ;; + # This must come after -sysvr4. + -sysv*) + ;; + -xenix) + os=-xenix + ;; + -none) + ;; + *) + # Get rid of the `-' at the beginning of $os. + os=`echo $os | sed 's/[^-]*-//'` + echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2 + exit 1 + ;; +esac +else + +# Here we handle the default operating systems that come with various machines. +# The value should be what the vendor currently ships out the door with their +# machine or put another way, the most popular os provided with the machine. + +# Note that if you're going to try to match "-MANUFACTURER" here (say, +# "-sun"), then you have to tell the case statement up towards the top +# that MANUFACTURER isn't an operating system. Otherwise, code above +# will signal an error saying that MANUFACTURER isn't an operating +# system, and we'll never get to this point. + +case $basic_machine in + *-acorn) + os=-riscix1.2 + ;; + arm*-semi) + os=-aout + ;; + pdp11-*) + os=-none + ;; + *-dec | vax-*) + os=-ultrix4.2 + ;; + m68*-apollo) + os=-domain + ;; + i386-sun) + os=-sunos4.0.2 + ;; + m68000-sun) + os=-sunos3 + # This also exists in the configure program, but was not the + # default. + # os=-sunos4 + ;; + *-tti) # must be before sparc entry or we get the wrong os. + os=-sysv3 + ;; + sparc-* | *-sun) + os=-sunos4.1.1 + ;; + *-ibm) + os=-aix + ;; + *-hp) + os=-hpux + ;; + *-hitachi) + os=-hiux + ;; + i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) + os=-sysv + ;; + *-cbm) + os=-amigados + ;; + *-dg) + os=-dgux + ;; + *-dolphin) + os=-sysv3 + ;; + m68k-ccur) + os=-rtu + ;; + m88k-omron*) + os=-luna + ;; + *-next ) + os=-nextstep + ;; + *-sequent) + os=-ptx + ;; + *-crds) + os=-unos + ;; + *-ns) + os=-genix + ;; + i370-*) + os=-mvs + ;; + *-next) + os=-nextstep3 + ;; + *-gould) + os=-sysv + ;; + *-highlevel) + os=-bsd + ;; + *-encore) + os=-bsd + ;; + *-sgi) + os=-irix + ;; + *-siemens) + os=-sysv4 + ;; + *-masscomp) + os=-rtu + ;; + *) + os=-none + ;; +esac +fi + +# Here we handle the case where we know the os, and the CPU type, but not the +# manufacturer. We pick the logical manufacturer. +vendor=unknown +case $basic_machine in + *-unknown) + case $os in + -riscix*) + vendor=acorn + ;; + -sunos*) + vendor=sun + ;; + -lynxos*) + vendor=lynx + ;; + -aix*) + vendor=ibm + ;; + -hpux*) + vendor=hp + ;; + -hiux*) + vendor=hitachi + ;; + -unos*) + vendor=crds + ;; + -dgux*) + vendor=dg + ;; + -luna*) + vendor=omron + ;; + -genix*) + vendor=ns + ;; + -mvs*) + vendor=ibm + ;; + -ptx*) + vendor=sequent + ;; + -vxworks*) + vendor=wrs + ;; + esac + basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` + ;; +esac + +echo $basic_machine$os diff --git a/support/cppmagic b/support/cppmagic deleted file mode 100755 index b0a951c..0000000 --- a/support/cppmagic +++ /dev/null @@ -1,51 +0,0 @@ -#!/bin/sh -# Return a full cpp specification, complete with system dependent flags. -# -# Syntax: cppmagic [ program-to-generate-flags [ guessed-cpp ]] -# -# If only one arg is present it is the name of a program to invoke -# which should generate -Dfoo defines. -# -# If two args are present the second arg is the name of the C -# preprocessor to use. -# -# Invoked with no args, provides a C preprocessor name and -# -traditional flag if that is appropriate. -# -# ../Makefile calls this file thusly: "cppmagic getcppsyms". -# -# Typical output: -# -# /lib/cpp -Dunix -Dm68k -# - -Cpp= - -if [ "$2" ]; then - Cpp=$2 -else - for cpp in /lib/cpp /usr/lib/cpp /usr/ccs/lib/cpp; do - if [ -f $cpp ]; then - Cpp=$cpp - fi - done - if [ "$Cpp" = "" ]; then - Cpp=cpp - fi -fi - -TRADITIONAL= -FLAGS= - -# First flag might be `-traditional' if this is Gnu Cpp. -unknown_flag=`$Cpp -traditional /dev/null 2>&1 | - egrep 'known|recognized|valid|bad|legal'` -if [ "$unknown_flag" = "" ]; then - TRADITIONAL=-traditional -fi - -if [ "$1" ]; then - FLAGS=`$1` -fi - -echo $Cpp $TRADITIONAL $FLAGS diff --git a/support/fixlinks b/support/fixlinks index b82ca4d..bc286e5 100755 --- a/support/fixlinks +++ b/support/fixlinks @@ -10,8 +10,9 @@ while [ $# -gt 0 ]; do case "$1" in -s) shift; SRCDIR=$1 ;; -u) unfix=yes ;; + -h) hardlinks=yes ;; -*) echo "$0: $1: bad option" 1>&2 - echo "$0: usage: $0 [-u] [-s srcdir] [linkmap]" 1>&2 + echo "$0: usage: $0 [-hu] [-s srcdir] [linkmap]" 1>&2 exit 1;; *) break ;; esac @@ -35,11 +36,16 @@ if [ ! -f "$linkfile" ]; then fi rm -f /tmp/z -if (ln -s /dev/null /tmp/z) >/dev/null 2>&1; then +# if the user specified hard links, then do that. otherwise, try to use +# symlinks if they're present +if [ -n "$hardlinks" ]; then + LN=ln +elif (ln -s /dev/null /tmp/z) >/dev/null 2>&1; then LN="ln -s" else LN=ln fi +rm -f /tmp/z while read name target do diff --git a/support/getcppsyms.c b/support/getcppsyms.c deleted file mode 100644 index eb4c72d..0000000 --- a/support/getcppsyms.c +++ /dev/null @@ -1,428 +0,0 @@ -/* getcppsyms.c - Find unique compiler symbols. */ - -/* Copyright (C) 1993 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, 675 Mass Ave, Cambridge, MA 02139, USA. */ - -/* Some cpp's do not define any symbols, but instead let /bin/cc do it - for them. For such machines, running this file may prove useful. It - outputs the list of symbols which /bin/cc or /lib/cpp define and which - we had the foresight to guess at. */ - -#include -main () -{ -#if defined (__BSD_4_4__) - printf ("-D__BSD_4_4__"); -#endif /* __BSD_4_4__ */ -#if defined (CMU) - printf (" -DCMU"); -#endif /* CMU */ -#if defined (_COFF) - printf (" -D_COFF"); -#endif /* _COFF */ -#if defined (DGUX) - printf (" -DDGUX"); -#endif /* DGUX */ -#if defined (GOULD_PN) - printf (" -DGOULD_PN"); -#endif /* GOULD_PN */ -#if defined (MACH) - printf (" -DMACH"); -#endif /* MACH */ -#if defined (MIPSEB) - printf (" -DMIPSEB"); -#endif /* MIPSEB */ -#if defined (MIPSEL) - printf (" -DMIPSEL"); -#endif /* MIPSEL */ -#if defined (MULTIMAX) - printf (" -DMULTIMAX"); -#endif /* MULTIMAX */ -#if defined (M_UNIX) - printf (" -DM_UNIX"); -#endif /* M_UNIX */ -#if defined (M_XENIX) - printf (" -DM_XENIX"); -#endif /* M_XENIX */ -#if defined (_M_XENIX) - printf (" -D_M_XENIX"); -#endif /* _M_XENIX */ -#if defined (NeXT) - printf (" -DNeXT"); -#endif /* NeXT */ -#if defined (__PARAGON__) - printf (" -D__PARAGON__"); -#endif /* __PARAGON__ */ -#if defined (_PGC_) - printf (" -D_PGC_"); -#endif /* _PGC_ */ -#if defined (__PGC__) - printf (" -D__PGC__"); -#endif /* __PGC__ */ -#if defined (RES) - printf (" -DRES"); -#endif /* RES */ -#if defined (RISC6000) - printf (" -DRISC6000"); -#endif /* RISC6000 */ -#if defined (RT) - printf (" -DRT"); -#endif /* RT */ -#if defined (SYSTYPE_BSD) - printf (" -DSYSTYPE_BSD"); -#endif /* SYSTYPE_BSD */ -#if defined (SYSTYPE_SYSV) - printf (" -DSYSTYPE_SYSV"); -#endif /* SYSTYPE_SYSV */ -#if defined (Sun386i) - printf (" -DSun386i"); -#endif /* Sun386i */ -#if defined (Tek4132) - printf (" -DTek4132"); -#endif /* Tek4132 */ -#if defined (Tek4300) - printf (" -DTek4300"); -#endif /* Tek4300 */ -#if defined (UMAXV) - printf (" -DUMAXV"); -#endif /* UMAXV */ -#if defined (USGr4) - printf (" -DUSGr4"); -#endif /* USGr4 */ -#if defined (USGr4_2) - printf (" -DUSGr4_2"); -#endif /* USGr4_2 */ -#if defined (__SVR4_2__) - printf (" -D__SVR4_2__"); -#endif /* __SVR4_2__ */ -#if defined (Xenix286) - printf (" -DXenix286"); -#endif /* Xenix286 */ -#if defined (_AIX) - printf (" -D_AIX"); -#endif /* _AIX */ -#if defined (_AIX370) - printf (" -D_AIX370"); -#endif /* _AIX370 */ -#if defined (_IBMESA) - printf (" -D_IBMESA"); -#endif /* _IBMESA */ -#if defined (__ibmesa) - printf (" -D__ibmesa"); -#endif /* __ibmesa */ -#if defined (_U370) - printf (" -D_U370"); -#endif /* _U370 */ -#if defined (_NLS) - printf (" -D_NLS"); -#endif /* _NLS */ -#if defined (_CX_UX) - printf (" -D_CX_UX"); -#endif /* _CX_UX */ -#if defined (_IBMR2) - printf (" -D_IBMR2"); -#endif /* _IBMR2 */ -#if defined (_M88K) - printf (" -D_M88K"); -#endif /* _M88K */ -#if defined (_M88KBCS_TARGET) - printf (" -D_M88KBCS_TARGET"); -#endif /* _M88KBCS_TARGET */ -#if defined (__DGUX__) - printf (" -D__DGUX__"); -#endif /* __DGUX__ */ -#if defined (__UMAXV__) - printf (" -D__UMAXV__"); -#endif /* __UMAXV__ */ -#if defined (__m88k) - printf (" -D__m88k"); -#endif /* __m88k */ -#if defined (__uxpm__) - printf (" -DUSGr4 -Du370 -D__uxpm__"); -#endif /* __uxpm__ */ -#if defined (__uxps__) - printf (" -D__svr4__ -D__uxps__"); -#endif /* __uxps__ */ -#if defined (alliant) - printf (" -Dalliant"); -#endif /* alliant */ -#if defined (alpha) - printf (" -Dalpha"); -#endif /* alpha */ -#if defined (__alpha) - printf (" -D__alpha"); -#endif /* __alpha */ -#if defined (aix) - printf (" -Daix"); -#endif /* aix */ -#if defined (aixpc) - printf (" -Daixpc"); -#endif /* aixpc */ -#if defined (apollo) - printf (" -Dapollo"); -#endif /* apollo */ -#if defined (ardent) - printf (" -Dardent"); -#endif /* ardent */ -#if defined (att386) - printf (" -Datt386"); -#endif /* att386 */ -#if defined (att3b) - printf (" -Datt3b"); -#endif /* att3b */ -#if defined (bsd4_2) - printf (" -Dbsd4_2"); -#endif /* bsd4_2 */ -#if defined (bsd4_3) - printf (" -Dbsd4_3"); -#endif /* bsd4_3 */ -#if defined (__bsdi__) - printf (" -D__bsdi__"); -#endif /* __bsdi__ */ -#if defined (bsdi) - printf (" -Dbsdi"); -#endif /* bsdi */ -#if defined (__386BSD__) - printf (" -D__386BSD__"); -#endif /* __386BSD__ */ -#if defined (cadmus) - printf (" -Dcadmus"); -#endif /* cadmus */ -#if defined (clipper) - printf (" -Dclipper"); -#endif /* clipper */ -#if defined (concurrent) - printf (" -Dconcurrent"); -#endif /* concurrent */ -#if defined (convex) || defined (__convex__) || defined (__convexc__) -# if !defined (__GNUC__) - printf (" -pcc"); -# endif /* !__GNUC__ */ - printf (" -Dconvex"); -#endif /* convex */ -#if defined (dmert) - printf (" -Ddmert"); -#endif /* dmert */ -#if defined (gcos) - printf (" -Dgcos"); -#endif /* gcos */ -#if defined (gcx) - printf (" -Dgcx"); -#endif /* gcx */ -#if defined (gould) - printf (" -Dgould"); -#endif /* gould */ -#if defined (hbullx20) - printf (" -Dhbullx20"); -#endif /* hbullx20 */ -#if defined (hcx) - printf (" -Dhcx"); -#endif /* hcx */ -#if defined (host_mips) - printf (" -Dhost_mips"); -#endif /* host_mips */ -#if defined (hp9000) || defined (__hp9000) - printf (" -Dhp9000"); -#endif /* hp9000 || __hp9000 */ -#if defined (hp9000s200) || defined (__hp9000s200) - printf (" -Dhp9000s200"); -#endif /* hp9000s200 || __hp9000s200 */ -#if defined (hp9000s300) || defined (__hp9000s300) - printf (" -Dhp9000s300"); -#endif /* hp9000s300 || __hp9000s300 */ -#if defined (hp9000s500) || defined (__hp9000s500) - printf (" -Dhp9000s500"); -#endif /* hp9000s500 || __hp9000s500 */ -#if defined (hp9000s700) || defined (__hp9000s700) - printf (" -Dhp9000s700"); -#endif /* hp9000s700 || __hp9000s700 */ -#if defined (hp9000s800) || defined (__hp9000s800) - printf (" -Dhp9000s800"); -#endif /* hp9000s800 || __hp9000s800 */ -#if defined (hppa) || defined (__hppa) - printf (" -Dhppa"); -#endif /* hppa || __hppa */ -#if defined (hpux) || defined (__hpux) - printf (" -Dhpux"); -#endif /* hpux */ -#if defined (__hp_osf) - printf (" -D__hp_osf"); -#endif /* __hp_osf */ -#if defined (i386) - printf (" -Di386"); -#endif /* i386 */ -#if defined (__i386__) - printf (" -D__i386__"); -#endif -#if defined (__i860) - printf(" -D__i860"); -#endif /* __i860 */ -#if defined (__i860__) - printf(" -D__i860__"); -#endif /* __i860__ */ -#if defined (ibm) - printf (" -Dibm"); -#endif /* ibm */ -#if defined (ibm032) - printf (" -Dibm032"); -#endif /* ibm032 */ -#if defined (ibmrt) - printf (" -Dibmrt"); -#endif /* ibmrt */ -#if defined (interdata) - printf (" -Dinterdata"); -#endif /* interdata */ -#if defined (is68k) - printf (" -Dis68k"); -#endif /* is68k */ -#if defined (ksr1) - printf (" -Dksr1"); -#endif /* ksr1 */ -#if defined (__ksr1__) - printf (" -D__ksr1__"); -#endif /* __ksr1__ */ -#if defined (linux) - printf (" -Dlinux"); -#endif /* linux */ -#if defined (__linux__) - printf (" -D__linux__"); -#endif /* __linux__ */ -#if defined (luna88k) - printf (" -Dluna88k"); -#endif /* luna88k */ -#if defined (m68k) - printf (" -Dm68k"); -#endif /* m68k */ -#if defined (m88k) - printf (" -Dm88k"); -#endif /* m88k */ -#if defined (mc68010) - printf (" -Dmc68010"); -#endif /* mc68010 */ -#if defined (mc68020) - printf (" -Dmc68020"); -#endif /* mc68020 */ -#if defined (mc68030) - printf (" -Dmc68030"); -#endif /* mc68030 */ -#if defined (mc68040) - printf (" -Dmc68040"); -#endif /* mc68040 */ -#if defined (mc68k32) - printf (" -Dmc68k32"); -#endif /* mc68k32 */ -#if defined (mips) - printf (" -Dmips"); -#endif /* mips */ -#if defined (n16) - printf (" -Dn16"); -#endif /* n16 */ -#if defined __nonstopux - printf (" -D__nonstopux"); -#endif -#if defined (ns32000) - printf (" -Dns32000"); -#endif /* ns32000 */ -#if defined (os) - printf (" -Dos"); -#endif /* os */ -#if defined (osf) - printf (" -Dosf"); -#endif /* osf */ -#if defined (__osf__) - printf (" -D__osf__"); -#endif /* __osf__ */ -#if defined (__OSF1__) - printf(" -D__OSF1__"); -#endif /* __OSF1__ */ -#if defined (pdp11) - printf (" -Dpdp11"); -#endif /* pdp11 */ -#if defined (plexus) - printf (" -Dplexus") -#endif /* plexus */ -#if defined (pyr) - printf (" -Dpyr"); -#endif /* pyr */ -#if defined (scs) - printf (" -Dscs"); -#endif /* scs */ -#if defined (sequent) - printf (" -Dsequent"); -#endif /* sequent */ -#if defined (sgi) - printf (" -Dsgi"); -#endif /* sgi */ -#if defined (sony) - printf (" -Dsony"); -#endif /* sony */ -#if defined (sparc) - printf (" -Dsparc"); -#endif /* sparc */ -#if defined (stardent) - printf (" -Dstardent"); -#endif /* stardent */ -#if defined (sun) - printf (" -Dsun"); -#endif /* sun */ -#if defined (sun2) - printf (" -Dsun2"); -#endif /* sun2 */ -#if defined (sun3) - printf (" -Dsun3"); -#endif /* sun3 */ -#if defined (sun4) - printf (" -Dsun4"); -#endif /* sun4 */ -#if defined (__svr4__) - printf (" -D__svr4__"); -#endif /* __svr4__ */ -#if defined (tower32) - printf (" -Dtower32"); -#endif /* tower32 */ -#if defined (tss) - printf (" -Dtss"); -#endif /* tss */ -#if defined (u370) - printf (" -Du370"); -#endif /* u370 */ -#if defined (u3b) - printf (" -Du3b"); -#endif /* u3b */ -#if defined (u3b2) - printf (" -Du3b2"); -#endif /* u3b2 */ -#if defined (u3b20d) - printf (" -Du3b20d"); -#endif /* u3b20d */ -#if defined (u3b5) - printf (" -Du3b5"); -#endif /* u3b5 */ -#if defined (ultrix) - printf (" -Dultrix"); -#endif /* ultrix */ -#if defined (unix) - printf (" -Dunix"); -#endif /* unix */ -#if defined (vax) - printf (" -Dvax"); -#endif /* vax */ - - printf ("\n"); - exit (0); -} diff --git a/support/mkclone b/support/mkclone new file mode 100755 index 0000000..fce7b6d --- /dev/null +++ b/support/mkclone @@ -0,0 +1,102 @@ +#! /bin/bash +# +# mkclone - symlink every file appearing in $src/MANIFEST to a corresponding +# file in the target directory ($1). Directories specified in +# MANIFEST are created in the target directory +# +prog=`basename $0` + +SRCDIR=src + +USAGE="usage: $prog [-m manifest] [-s srcdir] [-v] [-d] [-h] target" +while getopts dhm:s:v opt +do + case "$opt" in + m) MANIFEST=$OPTARG ;; + s) SRCDIR=$OPTARG ;; + v) verbose=y ;; + d) ECHO=echo debug=y ;; + h) hardlinks=y ;; + ?) echo $USAGE >&2 + exit 2;; + esac +done + +: ${MANIFEST:=${SRCDIR}/MANIFEST} + +[ -n "$debug" ] && verbose= + +shift $(( $OPTIND - 1 )) + +if [ $# -lt 1 ]; then + echo $USAGE >&2 + exit 2 +fi + +if [ ! -f $MANIFEST ]; then + echo "$prog: $MANIFEST: no such file or directory" >&2 + echo "$prog: must be run with valid -s argument or from source directory" >&2 + exit 1 +fi + +rm -f /tmp/z +# if the user specified hard links, then do that. otherwise, try to use +# symlinks if they're present +if [ -n "$hardlinks" ]; then + LN=ln +elif (ln -s /dev/null /tmp/z) >/dev/null 2>&1; then + LN="ln -s" +else + LN=ln +fi +rm -f /tmp/z + +TARGET=$1 + +if [ ! -d "$TARGET" ]; then + mkdir "$TARGET" +fi + +echo "${prog}: creating clone of bash source tree (from $SRCDIR) in $TARGET" + +cd "$TARGET" || { echo "${prog}: cannot cd to $TARGET" >&2 ; exit 1; } + +while read fname type mode +do + [ -z "$fname" ] && continue + + case "$fname" in + \#*) continue ;; + esac + + case "$type" in + d) [ -n "$verbose" ] && echo mkdir $fname + $ECHO mkdir $fname ;; # already in $TARGET + f) fn=${fname##*/} + case "$fname" in + */*) dn=${fname%/*} ;; + *) dn=. ;; + esac + if [ -n "$verbose" ] || [ -n "$debug" ]; then + echo "( cd $dn && $LN $SRCDIR/$fname $fn )" + fi + [ -z "$debug" ] && ( cd $dn && $LN $SRCDIR/$fname $fn ) + ;; + *) echo "${prog}: ${fname}: unknown file type $type" 1>&2 ;; + esac +done < $MANIFEST + +# special +SPECIAL="parser-built y.tab.c y.tab.h" + +rm -f $SPECIAL +for sf in $SPECIAL +do + [ -n "$verbose" ] && echo cp -p $SRCDIR/$sf $TARGET + $ECHO cp -p $SRCDIR/$sf $TARGET +done + +$ECHO $LN $SRCDIR/.distribution . +$ECHO $LN $SRCDIR/.patchlevel . + +exit 0 diff --git a/support/mkdirs b/support/mkdirs index 52228d1..b79d971 100755 --- a/support/mkdirs +++ b/support/mkdirs @@ -8,21 +8,24 @@ for dir do - [ -d "$dir" ] && continue + test -d "$dir" && continue tomake=$dir - while [ "$dir" ]; do + while test -n "$dir" ; do # dir=${dir%/*} - # dir=`expr "$dir" ':' '^\(/.*\)/[^/]*'` - dir=`expr "$dir" ':' '^\(.*\)/[^/]*'` - tomake="$dir $tomake" + # dir=`expr "$dir" ':' '\(/.*\)/[^/]*'` + if dir=`expr "$dir" ':' '\(.*\)/[^/]*'`; then + tomake="$dir $tomake" + else + dir= + fi done for d in $tomake do - [ -d $d ] && continue - echo mkdir $d - mkdir $d + test -d "$d" && continue + echo mkdir "$d" + mkdir "$d" done done diff --git a/support/mklinks b/support/mklinks deleted file mode 100755 index 612aa99..0000000 --- a/support/mklinks +++ /dev/null @@ -1,41 +0,0 @@ - -# Yet another script which requires an already built Bash. -# -# This makes links in the current directory to the directory specified as -# the first argument. -# - -topdir=$1 - -if [ ! "$topdir" ]; then - echo "No directory specified. Read the script $0." - exit 1 -fi - -function clone_files () -{ - local dir=$1; - local files; - - files=$(cd $dir; echo *); - - if [ ! "$files" ]; then - return 0; - fi - - for filename in $files; do - if [ -d $dir/$filename ]; then - # If the file to clone is this directory, then skip it. - if [ $(cd $dir/$filename; pwd) = $(pwd) ]; then - continue; - fi - mkdir $filename; - (cd $filename; clone_files ../$dir/$filename) - else - ln -s $dir/$filename .; - fi - done - rm -f \#* *~ .*~ *.bak .*.bak *.tmp .*.tmp *.o core a.out; -} - -clone_files $topdir diff --git a/support/mkmachtype b/support/mkmachtype deleted file mode 100755 index 00b7403..0000000 --- a/support/mkmachtype +++ /dev/null @@ -1,279 +0,0 @@ -#!/bin/sh -# This script attempts to guess a canonical system name. -# Copyright (C) 1992, 1993 Free Software Foundation, Inc. -# -# This file 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 of the License, or -# (at your option) any later version. -# -# This program 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 this program; if not, write to the Free Software -# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ - -# -# This script attempts to guess a canonical system name similar to -# config.sub. If it succeeds, it prints the system name on stdout, and -# exits with 0. Otherwise, it exits with 1. -# -# The plan is that this can be called by configure scripts if you -# don't specify an explicit system type (host/target name). -# -# Only a few systems have been added to this list; please add others -# (but try to keep the structure clean). -# - -UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown -UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown -UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown -UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown - -# Note: order is significant - the case branches are not exclusive. - -case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in - alpha:OSF1:1.*:*) - # 1.2 uses "1.2" for uname -r. - echo alpha-dec-osf${UNAME_RELEASE} - exit 0 ;; - alpha:OSF1:V1.*:*) - # 1.3 uses "V1.3" for uname -r. - echo alpha-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^V//'` - exit 0 ;; - arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) - echo arm-acorn-riscix${UNAME_RELEASE} - exit 0;; - sun4*:SunOS:5.*:*) - echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` - exit 0 ;; - sun4*:SunOS:6*:*) - # According to config.sub, this is the proper way to canonicalize - # SunOS6. Hard to guess exactly what SunOS6 will be like, but - # it's likely to be more like Solaris than SunOS4. - echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` - exit 0 ;; - sun4*:SunOS:*:*) - echo sparc-sun-sunos${UNAME_RELEASE} - exit 0 ;; - sun3*:SunOS:*:*) - echo m68k-sun-sunos${UNAME_RELEASE} - exit 0 ;; - RISC*:ULTRIX:*:*) - echo mips-dec-ultrix${UNAME_RELEASE} - exit 0 ;; - VAX*:ULTRIX*:*:*) - echo vax-dec-ultrix${UNAME_RELEASE} - exit 0 ;; - mips:*:5*:RISCos) - echo mips-mips-riscos${UNAME_RELEASE} - exit 0 ;; - m88k:*:4*:R4*) - echo m88k-motorola-sysv4 - exit 0 ;; - m88k:*:3*:R3*) - echo m88k-motorola-sysv3 - exit 0 ;; - AViiON:dgux:*:*) - echo m88k-dg-dgux${UNAME_RELEASE} - exit 0 ;; - M88*:*:R3*:*) - # Delta 88k system running SVR3 - echo m88k-motorola-sysv3 - exit 0 ;; - *:IRIX:*:*) - echo mips-sgi-irix${UNAME_RELEASE} - exit 0 ;; - i[34]86:AIX:*:*) - echo i386-ibm-aix - exit 0 ;; - *:AIX:2:3) - echo rs6000-ibm-aix3.2 - exit 0 ;; - *:AIX:*:*) - echo rs6000-ibm-aix - exit 0 ;; - *:BOSX:*:*) - echo rs6000-bull-bosx - exit 0 ;; - DPX/2?00:B.O.S.:*:*) - echo m68k-bull-sysv3 - exit 0 ;; - 9000/31?:HP-UX:*:*) - echo m68000-hp-hpux - exit 0 ;; - 9000/[34]??:HP-UX:*:*) - echo m68k-hp-hpux - exit 0 ;; - 9000/[34]??:4.3bsd:1.*:*) - echo m68k-hp-bsd - exit 0 ;; - hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) - echo m68k-hp-bsd4.4 - exit 0 ;; - 9000/7??:HP-UX:*:* | 9000/8?7:HP-UX:*:* ) - echo hppa1.1-hp-hpux - exit 0 ;; - 9000/8??:HP-UX:*:*) - echo hppa1.0-hp-hpux - exit 0 ;; - 3050*:HI-UX:*:*) - sed 's/^ //' << EOF >dummy.c - #include - int - main () - { - long cpu = sysconf (_SC_CPU_VERSION); - if (CPU_IS_HP_MC68K (cpu)) - puts ("m68k-hitachi-hiuxwe2"); - else if (CPU_IS_PA_RISC (cpu)) - { - switch (cpu) - { - case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; - case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; - case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; - default: puts ("hppa-hitachi-hiuxwe2"); break; - } - } - else puts ("unknown-hitachi-hiuxwe2"); - exit (0); - } -EOF - ${CC-cc} dummy.c -o dummy && ./dummy && rm dummy.c dummy && exit 0 - rm -f dummy.c dummy - echo unknown-hitachi-hiuxwe2 - exit 0 ;; - 9000/7??:4.3bsd:*:* | 9000/8?7:4.3bsd:*:* ) - echo hppa1.1-hp-bsd - exit 0 ;; - 9000/8??:4.3bsd:*:*) - echo hppa1.0-hp-bsd - exit 0 ;; - C1*:ConvexOS:*:*) - echo c1-convex-bsd - exit 0 ;; - C2*:ConvexOS:*:*) - echo c2-convex-bsd - exit 0 ;; - CRAY*X-MP:UNICOS:*:*) - echo xmp-cray-unicos - exit 0 ;; - CRAY*Y-MP:UNICOS:*:*) - echo ymp-cray-unicos - exit 0 ;; - CRAY-2:UNICOS:*:*) - echo cray2-cray-unicos - exit 0 ;; - hp3[0-9][05]:NetBSD:*:*) - echo m68k-hp-netbsd${UNAME_RELEASE} - exit 0 ;; - i[34]86:NetBSD:*:*) - echo ${UNAME_MACHINE}-unknown-netbsd${UNAME_RELEASE} - exit 0 ;; - i[34]86:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux - exit 0 ;; - i[34]86:UNIX_SV:4.*:*) - if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then - echo ${UNAME_MACHINE}-univel-sysv${UNAME_RELEASE} - else - echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE} - fi - exit 0 ;; - i[34]86:*:3.2:*) - if /bin/uname -X 2>/dev/null >/dev/null ; then - UNAME_REL=`(/bin/uname -X|egrep Release|sed -e 's/.*= //')` - (/bin/uname -X|egrep i80486 >/dev/null) && UNAME_MACHINE=i486 - echo ${UNAME_MACHINE}-unknown-sco$UNAME_REL - else - echo ${UNAME_MACHINE}-unknown-sysv3.2 - fi - exit 0 ;; - mini*:CTIX:SYS*5:*) - # "miniframe" - echo m68010-convergent-sysv - exit 0 ;; - M680[234]0:*:R3V[567]*:*) - test -r /sysV68 && echo 'm68k-motorola-sysv' && exit 0 ;; - 3[34]??:*:4.0:*) - uname -p 2>/dev/null | grep 86 >/dev/null \ - && echo i486-ncr-sysv4 && exit 0 ;; - m680[234]0:LynxOS:2.2*:*) - echo m68k-lynx-lynxos${UNAME_RELEASE} - exit 0 ;; - i[34]86:LynxOS:2.2*:*) - echo i386-lynx-lynxos${UNAME_RELEASE} - exit 0 ;; - TSUNAMI:LynxOS:2.2*:*) - echo sparc-lynx-lynxos${UNAME_RELEASE} - exit 0 ;; -esac - -#echo '(No uname command or uname output not recognized.)' 1>&2 -#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2 - -cat >dummy.c <&2 - -exit 1 diff --git a/signames.c b/support/mksignames.c similarity index 97% rename from signames.c rename to support/mksignames.c index f5216d5..655485b 100644 --- a/signames.c +++ b/support/mksignames.c @@ -36,6 +36,7 @@ char *signal_names[2 * NSIG]; char *progname; +void initialize_signames () { register int i; @@ -238,8 +239,11 @@ initialize_signames () signal_names[i] = (char *)malloc (18); sprintf (signal_names[i], "SIGJUNK(%d)", i); } + + signal_names[NSIG] = "DEBUG"; } +void write_signames (stream) FILE *stream; { @@ -247,18 +251,19 @@ write_signames (stream) fprintf (stream, "/* This file was automatically created by %s.\n", progname); - fprintf (stream, " Do not edit. Edit signames.c instead. */\n\n"); + fprintf (stream, " Do not edit. Edit support/mksignames.c instead. */\n\n"); fprintf (stream, "/* A translation list so we can be polite to our users. */\n"); fprintf (stream, "char *signal_names[NSIG + 2] = {\n"); - for (i = 0; i < NSIG; i++) + for (i = 0; i <= NSIG; i++) fprintf (stream, " \"%s\",\n", signal_names[i]); fprintf (stream, " (char *)0x0,\n"); fprintf (stream, "};\n"); } +int main (argc, argv) int argc; char **argv; @@ -286,7 +291,7 @@ main (argc, argv) if (!stream) { - fprintf (stderr, "%s: %s Cannot be opened or written to.\n", + fprintf (stderr, "%s: %s: cannot open for writing\n", progname, stream_name); exit (2); } diff --git a/support/mksysdefs b/support/mksysdefs deleted file mode 100755 index 37b188e..0000000 --- a/support/mksysdefs +++ /dev/null @@ -1,497 +0,0 @@ -#!/bin/sh -# -# This file creates a file called "sysdefs.h" which contains CPP defines -# helping to describe the operating system features. We just take guesses -# by looking at random files. - -# Removes any inherited definitions. -SYSDEF= -MAKE_ANSI= - -while [ $# -gt 0 ]; do - case "$1" in - -s) shift; srcdir=$1; shift ;; - -i) shift; incdir="$1"; shift ;; - -A) shift; MAKE_ANSI=true ;; - *) break ;; - esac -done - -if [ -n "$1" ]; then - sysdefs=$1 -else - sysdefs=./sysdefs.h -fi - -if [ -z "$srcdir" ]; then - srcdir=. -fi - -rm -f $sysdefs - -echo "/* sysdefs.h -- #defines for your system created by $0." >>$sysdefs -echo " Do NOT EDIT this file, since any changes will disappear." >>$sysdefs -echo " Instead, edit $0, or config.h, or machines.h. */" >>$sysdefs -echo "" >>$sysdefs -echo "#if !defined (_SYSDEFS_H_)" >>$sysdefs -echo "# define _SYSDEFS_H_" >>$sysdefs - -# was if [ -f /usr/bin/uname ] || [ -f /bin/uname ] -if ( uname >/dev/null 2>&1 ) 2>/dev/null -then - UNAME=`uname` - UNAME_R=`uname -r 2>/dev/null` - UNAME_M=`uname -m 2>/dev/null` - UNAME_V=`uname -v 2>/dev/null` - UNAME_S=`uname -s 2>/dev/null` - RELEASE=`expr "$UNAME_R" : '[^0-9]*\([0-9]*\)'` - case "$RELEASE" in - "") RELEASE=0 ;; - *) RELEASE=`expr "$RELEASE" + 0` ;; - esac - LEVEL=`expr "$UNAME_R" : '[^0-9]*[0-9]*.\([0-9]*\)'` -fi - -# check for versions of SunOS and BSD/OS -case "${UNAME}${RELEASE}" in -SunOS4*) SYSDEF=SunOS4 ;; -SunOS5*) SYSDEF=SunOS5 ;; -BSD/OS2*) SYSDEF=BSDI2 ;; -esac - -# Test for NeXT -if [ -d /NextLibrary ]; then - MAKE_ANSI=true -fi - -# Intel Paragon -case "$UNAME_M" in -paragon) MAKE_ANSI=true ;; -esac - -# Test for shared libraries (this is pretty sVr4ish). -if [ -f /usr/ccs/lib/libc.so ]; then - SYSDEF=USGr4 -fi - -# Some versions of i386 SVR4.2 make `uname' equivalent to `uname -n', which -# is contrary to all other versions of uname -if [ -n "$UNAME" ] && [ "$UNAME_S" != "$UNAME" ] && [ "$UNAME_S" = UNIX_SV ]; then - UNAME=UNIX_SV -fi - -# (sound of teeth grinding...) -if [ "$UNAME" = "UNIX_SV" ] && [ "$UNAME_R" != "4.2" ] && [ "$RELEASE"."$LEVEL" = "4.2" ]; then - UNAME_R="4.2" -fi - -# another check for SVR4 on 386 or 486 machines -case "${UNAME_M}:${UNAME}:${UNAME_R}" in -i[34]86:UNIX_SV:4.*) SYSDEF=USGr4 ;; -esac - -# A check for Mips RISCos -case "$UNAME_V" in -UMIPS|RISCos) SYSDEF=RISCos_${RELEASE}_${LEVEL} ;; -esac - -# A check for Amdahl UTS -case "$UNAME" in -uts) SYSDEF=UTS ;; -esac - -# Look for an error message when trying to exec bison. If we find -# what we're looking for, then we don't have it. If we get something -# else (like an error message about no grammar file), then we have -# it. -HAVE_BISON= -if ( cd /tmp ; bison /dev/null 2>&1 >/dev/null | grep 'no input grammar' >/dev/null 2>&1 ) 2>/dev/null -then - HAVE_BISON=yes -fi - -# Try to locate ranlib. I think this is a bad idea. -if sh ${srcdir}/support/inpath ranlib; then - RANLIB_LOCATION=ranlib -elif [ -f /usr/bin/ranlib ]; then - RANLIB_LOCATION=/usr/bin/ranlib; -elif [ -f /bin/ranlib ]; then - RANLIB_LOCATION=/bin/ranlib; -elif [ -f /usr/local/bin/ranlib ]; then - RANLIB_LOCATION=/usr/local/bin/ranlib; -elif [ -f /usr/local/gnubin/ranlib ]; then - RANLIB_LOCATION=/usr/local/gnubin/ranlib; -else - RANLIB_LOCATION=: # XXX -fi - -if [ -n "${RANLIB_LOCATION}" ]; then - echo "" >>$sysdefs - echo "#if !defined (RANLIB_LOCATION)" >>$sysdefs - echo "# define RANLIB_LOCATION ${RANLIB_LOCATION}" >>$sysdefs - echo "#endif /* RANLIB_LOCATION */" >>$sysdefs -fi - -# -# Is this a Xenix system? -# -if [ -f /xenix ]; then - SYSDEF="Xenix" - case "`/bin/uname -p`" in - *286) SYSDEF="Xenix286" ;; - *386) SYSDEF="Xenix386" ;; - esac - - # make sure that `i386' is defined for machines.h - if [ "$SYSDEF" = "Xenix386" ]; then - echo "" >>$sysdefs - echo "#if !defined (i386)" >>$sysdefs - echo "# define i386" >>$sysdefs - echo "#endif /* !i386 */" >>$sysdefs - fi - - # Pass the release number of the OS through to the machine descriptions - # in machines.h. - if [ -f /etc/perms/soft ]; then - rel=`grep rel= /etc/perms/soft` - case "$rel" in - *2.2.*) XREL=XENIX_22 ;; - *2.3.*) XREL=XENIX_23 ;; - *3.2.*) XREL=XENIX_32 ;; - *) XREL= ;; - esac - - if [ "$XREL" ]; then - echo "" >>$sysdefs - echo "#if !defined ($XREL)" >>$sysdefs - echo "# define $XREL" >>$sysdefs - echo "#endif /* !$XREL */" >>$sysdefs - fi - fi -fi - -# -# Is this some kind of Sys Vish system? -# -if [ -f /unix ]; then - if [ -d /generic ]; then # This is an AIX system. - SYSDEF="aixpc" - MAKE_ANSI=true - elif [ -d /etc/conf/kconfig.d ] && [ -f /usr/include/sys/limits.h ]; then - SYSDEF="isc386" # This is a 386 running ISC? - ISCREL="ISC_$RELEASE" - echo "#if !defined ($ISCREL)" >>$sysdefs - echo "# define $ISCREL" >>$sysdefs - echo "#endif /* $ISCREL */" >>$sysdefs - elif [ -f /etc/xlc.cfg ]; then - if fgrep _IBMR2 /etc/xlc.cfg >/dev/null 2>&1; then - SYSDEF=RISC6000 - MAKE_ANSI=true - fi - elif [ -f /bin/4d -a -f /bin/uname ]; then - case "$UNAME_R" in - 3.*) SYSDEF="Irix3" ;; - 4.*) SYSDEF="Irix4" ;; - 5.*) SYSDEF="Irix5" ;; - 6.*) SYSDEF="Irix6" ;; - *) SYSDEF="Irix3" ;; - esac - elif [ -d /usr/amiga ]; then - SYSDEF="amiga" # An Amiga running V.4. - elif [ -f /bin/fxc.info ]; then - SYSDEF="alliant" - fi -fi - -# Is this a Unicos system? -if [ -f /unicos ]; then - MAKE_ANSI=true - UnicosMachine= - - # Test for the variaous flavors of Cray machines. - if [ -x /bin/cray1 ] && /bin/cray1 2>/dev/null; then - UnicosMachine=Cray1 - fi - - if [ -x /bin/cray2 ] && /bin/cray2 2>/dev/null; then - UnicosMachine=Cray2 - fi - - if [ -x /bin/crayxmp ] && /bin/crayxmp 2>/dev/null; then - UnicosMachine=CrayXMP - fi - if [ -x /bin/crayymp ] && /bin/crayymp 2>/dev/null; then - UnicosMachine=CrayYMP - fi - - if [ "$UnicosMachine" ]; then - echo "#if !defined ($UnicosMachine)" >>$sysdefs - echo "# define $UnicosMachine" >>$sysdefs - echo "#endif /* !$UnicosMachine */" >>$sysdefs - fi -fi - -# Is this (and what kind of) a HPUX system? -if [ -f /hp-ux ]; then - SYSDEF=HPUX_${RELEASE} - if [ "$RELEASE" = 6 -a "$LEVEL" -lt 2 ]; then - SYSDEF=HPUX_USG - fi -fi - -if [ "$SYSDEF" = "" ]; then - case "$UNAME_M" in - ESA) SYSDEF=AIXESA ;; - XD88*) SYSDEF=XD88 ;; - M88100) SYSDEF=M88100 ;; # Motorola Delta 88K - esac -fi - -if [ "$SYSDEF" = "" ]; then - case "$UNAME_V" in - V[0-9]*L[0-9]*) SYSDEF=UXP ;; # Fujitsu DS/90 - esac -fi - -# What release of SCO Unix is this? -if [ "$SYSDEF" = "" -a -f /bin/uname ]; then - case `/bin/uname -X 2>/dev/null | grep '^Release' 2>/dev/null` in - *3.2v4.*) SYSDEF=SCOv4 ;; - *3.2v5.*) SYSDEF=SCOv5 ;; - *) SYSDEF=SCO ;; - esac -fi - -# -# Default to cadmus for unknown SysVish systems -# -if [ -f /unix ] && [ "$SYSDEF" = "" ]; then - SYSDEF="cadmus" -fi - -if [ "$SYSDEF" != "" ]; then - echo "" >>$sysdefs - echo "#if !defined ($SYSDEF)" >>$sysdefs - echo "# define $SYSDEF" >>$sysdefs - echo "#endif /* $SYSDEF */" >>$sysdefs -fi - -# Now look for certain include files in a list of directories -# Poor substitute for autoconf - -# Add any other directories where include files are found to this list or -# create another case -if [ -n "$incdir" ]; then - dirlist="$incdir" -else - case "$SYSDEF" in - RISCos*) dirlist="/bsd43/usr/include";; - *) dirlist="/usr/include /usr/include/bsd /usr/include/ansi" ;; - esac -fi - -# Code fragment to be executed to find a particular include file. Make sure -# to set `file' to the pathname of the file you want, relative to /usr/include, -# before calling `eval $findf'. -findf=" -found=''; -for d in \$dirlist; -do - if test -f \$d/\$file; - then - found=yes; - break; - fi; -done -" - -found= -file=sys/stream.h -eval $findf -if [ -n "$found" ]; then - echo "" >>$sysdefs - echo "#if !defined (HAVE_SYS_STREAM_H)" >>$sysdefs - echo "# define HAVE_SYS_STREAM_H" >>$sysdefs - echo "#endif /* HAVE_SYS_STREAM_H */" >>$sysdefs -fi - -found= -file=sys/ptem.h -eval $findf -if [ -n "$found" ]; then - echo "" >>$sysdefs - echo "#if !defined (HAVE_SYS_PTEM_H)" >>$sysdefs - echo "# define HAVE_SYS_PTEM_H" >>$sysdefs - echo "#endif /* HAVE_SYS_PTEM_H */" >>$sysdefs -fi - -file=sys/pte.h -eval $findf -if [ -n "$found" ]; then - echo "" >>$sysdefs - echo "#if !defined (HAVE_SYS_PTE_H)" >>$sysdefs - echo "# define HAVE_SYS_PTE_H" >>$sysdefs - echo "#endif /* HAVE_SYS_PTE_H */" >>$sysdefs -fi - -file=sys/wait.h -eval $findf -if [ -n "$found" ]; then - echo "" >>$sysdefs - echo "#if !defined (HAVE_WAIT_H)" >>$sysdefs - echo "# define HAVE_WAIT_H" >>$sysdefs - echo "#endif /* HAVE_WAIT_H */" >>$sysdefs -fi - -file=sys/resource.h -eval $findf -if [ -n "$found" ]; then - echo "" >>$sysdefs - echo "#if !defined (HAVE_RESOURCE)" >>$sysdefs - echo "# define HAVE_RESOURCE" >>$sysdefs - echo "#endif /* HAVE_RESOURCE */" >>$sysdefs -fi - -file=sys/param.h -eval $findf -if [ -n "$found" ]; then - echo "" >>$sysdefs - echo "#if !defined (HAVE_SYS_PARAM)" >>$sysdefs - echo "# define HAVE_SYS_PARAM" >>$sysdefs - echo "#endif /* HAVE_SYS_PARAM */" >>$sysdefs -fi - -file=unistd.h -eval $findf -if [ -n "$found" ]; then - echo "" >>$sysdefs - echo "#if !defined (HAVE_UNISTD_H)" >>$sysdefs - echo "# define HAVE_UNISTD_H" >>$sysdefs - echo "#endif /* HAVE_UNISTD_H */" >>$sysdefs -fi - -file=stdlib.h -eval $findf -if [ -n "$found" ]; then - echo "" >>$sysdefs - echo "#if !defined (HAVE_STDLIB_H)" >>$sysdefs - echo "# define HAVE_STDLIB_H" >>$sysdefs - echo "#endif /* HAVE_STDLIB_H */" >>$sysdefs -fi - -file=limits.h -eval $findf -if [ -n "$found" ]; then - echo "" >>$sysdefs - echo "#if !defined (HAVE_LIMITS_H)" >>$sysdefs - echo "# define HAVE_LIMITS_H" >>$sysdefs - echo "#endif /* HAVE_LIMITS_H */" >>$sysdefs -fi - -file=alloca.h -eval $findf -if [ -f /usr/include/alloca.h ]; then - echo "" >>$sysdefs - echo "#if !defined (HAVE_ALLOCA_H)" >>$sysdefs - echo "# define HAVE_ALLOCA_H" >>$sysdefs - echo "#endif /* HAVE_ALLOCA_H */" >>$sysdefs -fi - -file=dirent.h -eval $findf -if [ -n "$found" ]; then - echo "" >>$sysdefs - echo "#if !defined (HAVE_DIRENT_H)" >>$sysdefs - echo "# define HAVE_DIRENT_H" >>$sysdefs - echo "#endif /* HAVE_DIRENT_H */" >>$sysdefs -fi - -file=string.h -eval $findf -if [ -n "$found" ]; then - echo "" >>$sysdefs - echo "#if !defined (HAVE_STRING_H)" >>$sysdefs - echo "# define HAVE_STRING_H" >>$sysdefs - echo "#endif /* HAVE_STRING_H */" >>$sysdefs -fi - -file=varargs.h -eval $findf -if [ -n "$found" ]; then - echo "" >>$sysdefs - echo "#if !defined (HAVE_VARARGS_H)" >>$sysdefs - echo "# define HAVE_VARARGS_H" >>$sysdefs - echo "#endif /* HAVE_VARARGS_H */" >>$sysdefs -fi - -# Does the system have a /dev/fd directory? -if [ -d /dev/fd ]; then - echo "" >>$sysdefs - echo "#if !defined (HAVE_DEV_FD)" >>$sysdefs - echo "# define HAVE_DEV_FD" >>$sysdefs - echo "#endif /* HAVE_DEV_FD */" >>$sysdefs -fi - -# Is this SVR4.2? It's subtly different from USGr4 -if [ "$UNAME" = "UNIX_SV" ] && [ "$UNAME_R" = "4.2" ]; then - echo "" >>$sysdefs - echo "#if !defined (USGr4_2)" >>$sysdefs - echo "# define USGr4_2" >>$sysdefs - echo "#endif /* USGr4_2 */" >>$sysdefs -fi - -# Is this AIX PS/2 1.3? Yuck. -if [ "$UNAME" = "AIX" ] && [ "$UNAME_V" = "1" ] && [ "$RELEASE" = "3" ]; then - case "$UNAME_M" in - i386|i486) - echo "" >>$sysdefs - echo "#if !defined (AIX_13)" >>$sysdefs - echo "# define AIX_13" >>$sysdefs - echo "#endif /* AIX_13 */" >>$sysdefs - ;; - esac -fi - -if [ -n "$HAVE_BISON" ]; then - echo "" >>$sysdefs - echo "#if !defined (HAVE_BISON)" >>$sysdefs - echo "# define HAVE_BISON" >>$sysdefs - echo "#endif /* HAVE_BISON */" >>$sysdefs -fi - -# Functions to test for a la autoconf -# getwd -# getcwd -# strchr -# strcasecmp -# getgroups -# setlinebuf -# strerror -# vfprintf -# bcopy -# getdtablesize -# setdtablesize -# alloca -# gethostname -# memmove (missing) -# mkfifo (missing) -# -# Other things to test -# opendir robustness -# dup2 working -# void sighandler -# sys_siglist[] -# uid_t, gid_t -# have_getpw_decls -# reversed setvbuf args -# int getgroups - -# If this system's cpp might not like `/**/#' in cpp-Makefile, make an -# alternate ansi-style cpp-Makefile. -if [ -n "$MAKE_ANSI" ]; then - grep -v '/\*\*/' ${srcdir}/cpp-Makefile >ansi-Makefile -fi - -# These should be the last 2 lines in this file! -echo "" >>$sysdefs -echo "#endif /* _SYSDEFS_H_ */" >>$sysdefs diff --git a/newversion.c b/support/mkversion.c similarity index 81% rename from newversion.c rename to support/mkversion.c index bdba480..8164a8f 100644 --- a/newversion.c +++ b/support/mkversion.c @@ -20,12 +20,16 @@ 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, 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include "config.h" + #include #include "posixstat.h" #include +#include "bashansi.h" char *progname; char *dir; +char *status; FILE *must_open (); @@ -44,6 +48,7 @@ main (argc, argv) progname = argv[0]; + status = dir = (char *)0; while (arg_index < argc && argv[arg_index][0] == '-') { if (strcmp (argv[arg_index], "-dist") == 0) @@ -80,6 +85,15 @@ main (argc, argv) exit (1); } } + else if (strcmp (argv[arg_index], "-status") == 0) + { + status = argv[++arg_index]; + if (status == 0) + { + fprintf (stderr, "%s: `-status' requires an argument\n", progname); + exit (1); + } + } else { fprintf (stderr, "%s: unknown option: %s\n", progname, argv[arg_index]); @@ -89,16 +103,16 @@ main (argc, argv) arg_index++; } - if (get_float_from_file (".distribution", &distver) == 0) + if (get_float_from_file (".distribution", &distver, 1) == 0) dot_dist_needs_making++; - if (get_int_from_file (".patchlevel", &patchlevel) == 0) + if (get_int_from_file (".patchlevel", &patchlevel, 1) == 0) { patchlevel = 0; patch_inc = 0; } - if (get_int_from_file (".build", &buildver) == 0) + if (get_int_from_file (".build", &buildver, 0) == 0) buildver = 0; /* Setting distribution version. */ @@ -162,7 +176,7 @@ main (argc, argv) /* Output the leading comment. */ fprintf (file, "/* Version control for the shell. This file gets changed when you say\n\ - `make newversion' to the Makefile. It is created by newversion.aux. */\n"); + `make newversion' to the Makefile. It is created by mkversion. */\n"); fprintf (file, "\n/* The distribution version number of this shell. */\n"); fprintf (file, "#define DISTVERSION \"%.2f\"\n", distver); @@ -173,9 +187,19 @@ main (argc, argv) fprintf (file, "\n/* The last built version of this shell. */\n"); fprintf (file, "#define BUILDVERSION %d\n", buildver); + if (status) + { + fprintf (file, "\n/* The release status of this shell. */\n"); + fprintf (file, "#define RELSTATUS \"%s\"\n", status); + } + fprintf (file, "\n/* A version string for use by sccs and the what command. */\n\n"); - fprintf (file, "#define SCCSVERSION \"@(#)Bash version %.2f.%d(%d) GNU\"\n\n", - distver, patchlevel, buildver); + if (status) + fprintf (file, "#define SCCSVERSION \"@(#)Bash version %.2f.%d(%d) %s GNU\"\n\n", + distver, patchlevel, buildver, status); + else + fprintf (file, "#define SCCSVERSION \"@(#)Bash version %.2f.%d(%d) GNU\"\n\n", + distver, patchlevel, buildver); fclose (file); @@ -203,37 +227,37 @@ main (argc, argv) } char * -makename (fn) +makename (fn, from_srcdir) char *fn; { char *ret; - int dlen = 0; + int dlen; - if (dir) - dlen = strlen (dir) + 1; + dlen = (from_srcdir && dir) ? strlen (dir) + 1 : 0; ret = (char *)malloc (dlen + strlen (fn) + 1); if (ret == 0) { fprintf (stderr, "%s: malloc failed\n", progname); exit (1); } - if (dir) + if (from_srcdir && dir) sprintf (ret, "%s/%s", dir, fn); else - strcpy (ret, fn); + (void)strcpy (ret, fn); return ret; } -get_float_from_file (filename, var) +get_float_from_file (filename, var, from_srcdir) char *filename; float *var; + int from_srcdir; { FILE *stream; int result; char *name; - name = makename (filename); + name = makename (filename, from_srcdir); stream = fopen (name, "r"); free (name); if (stream == (FILE *)NULL) @@ -243,15 +267,15 @@ get_float_from_file (filename, var) return (result == 1); } -get_int_from_file (filename, var) +get_int_from_file (filename, var, from_srcdir) char *filename; - int *var; + int *var, from_srcdir; { FILE *stream; int result; char *name; - name = makename (filename); + name = makename (filename, from_srcdir); stream = fopen (name, "r"); free (name); if (stream == (FILE *)NULL) diff --git a/support/recho.c b/support/recho.c index b9dc00b..847fa2c 100644 --- a/support/recho.c +++ b/support/recho.c @@ -29,4 +29,5 @@ char *str; } else putchar(*s); } + return(0); } diff --git a/support/srcdir b/support/srcdir deleted file mode 100755 index 9d8ccd7..0000000 --- a/support/srcdir +++ /dev/null @@ -1,13 +0,0 @@ -#! /bin/sh -# -# srcdir - print out the absolute pathname of the top of the bash source -# tree. Used for getting the right value to makes in subdirectories -# - -case "$1" in -'.'|./) pwd ;; -./*|..*) echo `pwd`/"$1" ;; -*) echo "$1" ;; -esac - -exit 0 diff --git a/support/texi2dvi b/support/texi2dvi index 12281e5..8fb2f90 100755 --- a/support/texi2dvi +++ b/support/texi2dvi @@ -1,8 +1,10 @@ -#!/bin/sh -# texi2dvi -- smartly produce DVI files from texinfo sources -# -# Copyright (C) 1992, 1993 Free Software Foundation. -# +#! /bin/sh +# texi2dvi --- smartly produce DVI files from texinfo sources + +# Copyright (C) 1992, 1993, 1994, 1995 Free Software Foundation, Inc. + +# $Id: texi2dvi,v 0.5 1995/06/20 02:21:36 friedman Exp $ + # This program 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) @@ -15,110 +17,122 @@ # # You should have received a copy of the GNU General Public License # along with this program; if not, you can either send email to this -# program's author (see below) or write to: -# -# Free Software Foundation, Inc. -# 675 Mass Ave. -# Cambridge, MA 02139, USA. -# +# program's maintainer or write to: The Free Software Foundation, +# Inc.; 59 Temple Place, Suite 330; Boston, MA 02111-1307, USA. + +# Commentary: + +# Author: Noah Friedman + # Please send bug reports, etc. to bug-texinfo@prep.ai.mit.edu # If possible, please send a copy of the output of the script called with -# the `--debug' option when making a bug report. -# -# Version 0.4 -# Last modified 26-Mar-93 -# +# the `--debug' option when making a bug report. -# Please note that in the interest of general portability, some common -# bourne shell constructs were avoided because they weren't guaranteed to -# be available in some earlier implementations. I've tried to make this as -# portable as possible. +# In the interest of general portability, some common bourne shell +# constructs were avoided because they weren't guaranteed to be available +# in some earlier implementations. I've tried to make this program as +# portable as possible. Welcome to unix, where the lowest common +# denominator is rapidly diminishing. # # Among the more interesting lossages I noticed with some bourne shells # are: -# 1) Some don't have an `unset' builtin -# 2) In some implementations the `shift' builtin can't take a -# numerical argument. - -progname=`basename $0` +# * No shell functions. +# * No `unset' builtin. +# * `shift' cannot take a numeric argument, and signals an error if +# there are no arguments to shift. -usage="Usage: ${progname} {-D} {-h} [file1] {file2} {...} - {--debug} {--help} +# Code: - Options in braces are optional. Those in brackets are required. -" +# Name by which this script was invoked. +progname=`echo "$0" | sed -e 's/[^\/]*\///g'` -if test $# -eq 0 ; then - echo "${usage}" 1>&2; - exit 1 -fi +# This string is expanded by rcs automatically when this file is checked out. +rcs_revision='$Revision: 0.5 $' +version=`set - $rcs_revision; echo $2` -backup_extension=".bak" -texindex="texindex" -tex="tex" -bq="\`" # To prevent hairy quoting and escaping later. +# To prevent hairy quoting and escaping later. +bq='`' eq="'" -orig_pwd="`pwd`" -if test "z${TEXINDEX}" != "z" ; then - texindex="${TEXINDEX}" -fi +usage="Usage: $progname {options} [file1] {file2 {...}} +(version $version) + +Options are: +-D, --debug Turn on shell debugging ($bq${bq}set -x$eq$eq). +-h, --help You're looking at it. +-v, --version Print version number. -if test "z${TEX}" != "z" ; then - tex="${TEX}" -fi +Arguments in brackets are required. Those in braces are optional. +" + +# Initialize variables. +# Don't use `unset' since old bourne shells don't have this command. +# Instead, assign them an empty value. +# Some of these, like TEX and TEXINDEX, may be inherited from the environment +backup_extension=.bak +debug= +orig_pwd="`pwd`" +verbose= +texindex="${TEXINDEX-texindex}" +tex="${TEX-tex}" # Save this so we can construct a new TEXINPUTS path for each file to be # processed. -TEXINPUTS_orig="${TEXINPUTS}" +TEXINPUTS_orig="$TEXINPUTS" export TEXINPUTS -# Parse command line options - -# "unset" option variables to make sure they weren't accidentally -# exported -debug="" - -# If you add new commands be sure to change the wildcards below to make -# sure they are unambiguous (i.e. only match one possible long option) -# Be sure to show at least one instance of the full long option name to -# document what the long option is canonically called. -while test $# -gt 0 ; do - case z$1 in - z-D | z--debug | z--d* ) - debug="t" - shift - ;; - z-h | z--help | z--h* ) - echo "${usage}" 1>&2 - exit 1 - ;; - z-- ) - shift - break - ;; - z-* ) - echo "${progname}: ${bq}${1}${eq} is not a valid option." 1>&2 - echo "" 1>&2 - echo "${usage}" 1>&2 - exit 1 - ;; - * ) - break - ;; +# Parse command line arguments. +# Make sure that all wildcarded options are long enough to be unambiguous. +# It's a good idea to document the full long option name in each case. +# Long options which take arguments will need a `*' appended to the +# canonical name to match the value appended after the `=' character. +while : ; do + case $# in 0) break ;; esac + case "$1" in + -D | --debug | --d* ) + debug=t + shift + ;; + -h | --help | --h* ) + echo "$usage" 1>&2 + exit 0 + ;; + -v | --version | --v* ) + echo "texi2dvi version $version" 1>&2 + exit 0 + ;; + -- ) # Stop option processing + shift + break + ;; + -* ) + case "$1" in + --*=* ) arg=`echo "$1" | sed -e 's/=.*//'` ;; + * ) arg="$1" ;; + esac + exec 1>&2 + echo "$progname: unknown or ambiguous option $bq$arg$eq" + echo "$progname: Use $bq--help$eq for a list of options." + exit 1 + ;; + * ) + break + ;; esac done # See if there are any command line args left (which will be interpreted as # filename arguments) -if test $# -eq 0 ; then - echo "${progname}: at least one file name is required as an argument." 1>&2 - echo "" 1>&2 - echo "${usage}" 1>&2 - exit 1 -fi +case $# in + 0 ) + exec 1>&2 + echo "$progname: at least one file name is required as an argument." + echo "$progname: Use $bq--help$eq for a description of command syntax." + exit 2 + ;; +esac -test "z${debug}" = "zt" && set -x +case "$debug" in t ) set -x ;; esac # Texify files for command_line_filename in ${1+"$@"} ; do @@ -137,7 +151,7 @@ for command_line_filename in ${1+"$@"} ; do # Source file might @include additional texinfo sources. Put `.' and # directory where source file(s) reside in TEXINPUTS before anything # else. `.' goes first to ensure that any old .aux, .cps, etc. files in - # ${directory} don't get used in preference to fresher files in `.'. + # ${directory} don't get used in preference to fresher files in `.'. TEXINPUTS=".:${directory}:${TEXINPUTS_orig}" # "Unset" variables that might have values from previous iterations and @@ -150,7 +164,7 @@ for command_line_filename in ${1+"$@"} ; do # able to find the right index files and so forth. if test ! -r "${command_line_filename}" ; then echo "${progname}: ${command_line_filename}: No such file or permission denied." 1>&2 - continue; + continue; fi # Find all files having root filename with a two-letter extension, @@ -159,7 +173,7 @@ for command_line_filename in ${1+"$@"} ; do # that too. possible_index_files="`eval echo ${filename_noext}.?? ${filename_noext}.aux`" for this_file in ${possible_index_files} ; do - # If file is empty, forget it. + # If file is empty, forget it. if test ! -s "${this_file}" ; then continue; fi @@ -177,7 +191,7 @@ for command_line_filename in ${1+"$@"} ; do s/^[ ]*//;s/[ ]*$//;'`" # Now save copies of original index files so we have some means of - # comparison later. + # comparison later. for index_file_to_save in ${orig_index_files} ; do cp "${index_file_to_save}" "${index_file_to_save}${backup_extension}" done @@ -213,20 +227,20 @@ for command_line_filename in ${1+"$@"} ; do s/^[ ]*//;s/[ ]*$//;'`" # If old and new list don't at least have the same file list, then one - # file or another has definitely changed. + # file or another has definitely changed. if test "${orig_index_files}" != "${new_index_files}" ; then index_files_changed_p=t else # File list is the same. We must compare each file until we find a - # difference. + # difference. index_files_changed_p="" for this_file in ${new_index_files} ; do - # cmp -s will return nonzero exit status if files differ. + # cmp -s will return nonzero exit status if files differ. cmp -s "${this_file}" "${this_file}${backup_extension}" if test $? -ne 0 ; then # We only need to keep comparing until we find *one* that # differs, because we'll have to run texindex & tex no - # matter what. + # matter what. index_files_changed_p=t break fi @@ -238,7 +252,7 @@ for command_line_filename in ${1+"$@"} ; do if test "${index_files_changed_p}" ; then retval=0 if test "${new_index_files_sans_aux}" ; then - ${texindex} ${new_index_files_sans_aux} + ${texindex} ${new_index_files_sans_aux} retval=$? fi if test ${retval} -eq 0 ; then @@ -248,7 +262,7 @@ for command_line_filename in ${1+"$@"} ; do fi # Generate list of files to delete, then call rm once with the entire - # list. This is significantly faster than multiple executions of rm. + # list. This is significantly faster than multiple executions of rm. file_list="" for file in ${orig_index_files} ; do file_list="${file_list} ${file}${backup_extension}" @@ -258,6 +272,4 @@ for command_line_filename in ${1+"$@"} ; do fi done -# -# eof -# +# texi2dvi ends here diff --git a/support/texi2html b/support/texi2html new file mode 100755 index 0000000..2c61aa9 --- /dev/null +++ b/support/texi2html @@ -0,0 +1,2021 @@ +#!/usr/local/bin/perl +'di '; +'ig 00 '; +#+############################################################################## +# # +# File: texi2html # +# # +# Description: Program to transform most Texinfo documents to HTML # +# # +#-############################################################################## + +# @(#)texi2html 1.51 09/10/96 Written (mainly) by Lionel Cons, Lionel.Cons@cern.ch + +# The man page for this program is included at the end of this file and can be +# viewed using the command 'nroff -man texi2html'. +# Please read the copyright at the end of the man page. + +#+++############################################################################ +# # +# Constants # +# # +#---############################################################################ + +$DEBUG_TOC = 1; +$DEBUG_INDEX = 2; +$DEBUG_BIB = 4; +$DEBUG_GLOSS = 8; +$DEBUG_DEF = 16; +$DEBUG_HTML = 32; +$DEBUG_USER = 64; + +$BIBRE = '\[[\w\/]+\]'; # RE for a bibliography reference +$FILERE = '[\/\w.+-]+'; # RE for a file name +$VARRE = '[^\s\{\}]+'; # RE for a variable name +$NODERE = '[^@{}:\'`",]+'; # RE for a node name +$NODESRE = '[^@{}:\'`"]+'; # RE for a list of node names +$XREFRE = '[^@{}]+'; # RE for a xref (should use NODERE) + +$ERROR = "***"; # prefix for errors and warnings +$THISPROG = "texi2html 1.51"; # program name and version +$HOMEPAGE = "http://wwwcn.cern.ch/dci/texi2html/"; # program home page +$TODAY = &pretty_date; # like "20 September 1993" +$SPLITTAG = "\n"; # tag to know where to split +$PROTECTTAG = "_ThisIsProtected_"; # tag to recognize protected sections +$html2_doctype = ''; + +# +# language dependent constants +# +#$LDC_SEE = 'see'; +#$LDC_SECTION = 'section'; +#$LDC_IN = 'in'; +#$LDC_TOC = 'Table of Contents'; +#$LDC_GOTO = 'Go to the'; +#$LDC_FOOT = 'Footnotes'; +# TODO: @def* shortcuts + +# +# pre-defined indices +# +%predefined_index = ( + 'cp', 'c', + 'fn', 'f', + 'vr', 'v', + 'ky', 'k', + 'pg', 'p', + 'tp', 't', + ); + +# +# valid indices +# +%valid_index = ( + 'c', 1, + 'f', 1, + 'v', 1, + 'k', 1, + 'p', 1, + 't', 1, + ); + +# +# texinfo section names to level +# +%sec2level = ( + 'top', 0, + 'chapter', 1, + 'unnumbered', 1, + 'majorheading', 1, + 'chapheading', 1, + 'appendix', 1, + 'section', 2, + 'unnumberedsec', 2, + 'heading', 2, + 'appendixsec', 2, + 'appendixsection', 2, + 'subsection', 3, + 'unnumberedsubsec', 3, + 'subheading', 3, + 'appendixsubsec', 3, + 'subsubsection', 4, + 'unnumberedsubsubsec', 4, + 'subsubheading', 4, + 'appendixsubsubsec', 4, + ); + +# +# accent map, TeX command to ISO name +# +%accent_map = ( + '"', 'uml', + '~', 'tilde', + '^', 'circ', + '`', 'grave', + '\'', 'acute', + ); + +# +# texinfo "simple things" (@foo) to HTML ones +# +%simple_map = ( + # cf. makeinfo.c + "*", "
", # HTML+ + " ", " ", + "\n", "\n", + "|", "", + # spacing commands + ":", "", + "!", "!", + "?", "?", + ".", ".", + ); + +# +# texinfo "things" (@foo{}) to HTML ones +# +%things_map = ( + 'TeX', 'TeX', + 'br', '

', # paragraph break + 'bullet', '*', + 'copyright', '(C)', + 'dots', '...', + 'equiv', '==', + 'error', 'error-->', + 'expansion', '==>', + 'minus', '-', + 'point', '-!-', + 'print', '-|', + 'result', '=>', + 'today', $TODAY, + ); + +# +# texinfo styles (@foo{bar}) to HTML ones +# +%style_map = ( + 'asis', '', + 'b', 'B', + 'cite', 'CITE', + 'code', 'CODE', + 'ctrl', '&do_ctrl', # special case + 'dfn', 'STRONG', # DFN tag is illegal in the standard + 'dmn', '', # useless + 'emph', 'EM', + 'file', '"TT', # will put quotes, cf. &apply_style + 'i', 'I', + 'kbd', 'KBD', + 'key', 'KBD', + 'r', '', # unsupported + 'samp', '"SAMP', # will put quotes, cf. &apply_style + 'sc', '&do_sc', # special case + 'strong', 'STRONG', + 't', 'TT', + 'titlefont', '', # useless + 'var', 'VAR', + 'w', '', # unsupported + ); + +# +# texinfo format (@foo/@end foo) to HTML ones +# +%format_map = ( + 'display', 'PRE', + 'example', 'PRE', + 'format', 'PRE', + 'lisp', 'PRE', + 'quotation', 'BLOCKQUOTE', + 'smallexample', 'PRE', + 'smalllisp', 'PRE', + # lists + 'itemize', 'UL', + 'enumerate', 'OL', + # poorly supported + 'flushleft', 'PRE', + 'flushright', 'PRE', + ); + +# +# texinfo definition shortcuts to real ones +# +%def_map = ( + # basic commands + 'deffn', 0, + 'defvr', 0, + 'deftypefn', 0, + 'deftypevr', 0, + 'defcv', 0, + 'defop', 0, + 'deftp', 0, + # basic x commands + 'deffnx', 0, + 'defvrx', 0, + 'deftypefnx', 0, + 'deftypevrx', 0, + 'defcvx', 0, + 'defopx', 0, + 'deftpx', 0, + # shortcuts + 'defun', 'deffn Function', + 'defmac', 'deffn Macro', + 'defspec', 'deffn {Special Form}', + 'defvar', 'defvr Variable', + 'defopt', 'defvr {User Option}', + 'deftypefun', 'deftypefn Function', + 'deftypevar', 'deftypevr Variable', + 'defivar', 'defcv {Instance Variable}', + 'defmethod', 'defop Method', + # x shortcuts + 'defunx', 'deffnx Function', + 'defmacx', 'deffnx Macro', + 'defspecx', 'deffnx {Special Form}', + 'defvarx', 'defvrx Variable', + 'defoptx', 'defvrx {User Option}', + 'deftypefunx', 'deftypefnx Function', + 'deftypevarx', 'deftypevrx Variable', + 'defivarx', 'defcvx {Instance Variable}', + 'defmethodx', 'defopx Method', + ); + +# +# things to skip +# +%to_skip = ( + # comments + 'c', 1, + 'comment', 1, + # useless + 'contents', 1, + 'shortcontents', 1, + 'summarycontents', 1, + 'footnotestyle', 1, + 'end ifclear', 1, + 'end ifset', 1, + 'titlepage', 1, + 'end titlepage', 1, + # unsupported commands (formatting) + 'afourpaper', 1, + 'cropmarks', 1, + 'finalout', 1, + 'headings', 1, + 'need', 1, + 'page', 1, + 'setchapternewpage', 1, + 'everyheading', 1, + 'everyfooting', 1, + 'evenheading', 1, + 'evenfooting', 1, + 'oddheading', 1, + 'oddfooting', 1, + 'smallbook', 1, + 'vskip', 1, + 'filbreak', 1, + # unsupported formats + 'cartouche', 1, + 'end cartouche', 1, + 'group', 1, + 'end group', 1, + ); + +#+++############################################################################ +# # +# Argument parsing, initialisation # +# # +#---############################################################################ + +$use_bibliography = 1; +$use_acc = 0; +$debug = 0; +$doctype = ''; +$check = 0; +$expandinfo = 0; +$use_glossary = 0; +$invisible_mark = ''; +$use_iso = 0; +@include_dirs = (); +$show_menu = 0; +$number_sections = 0; +$split_node = 0; +$split_chapter = 0; +$monolithic = 0; +$verbose = 0; +$usage = <= 0 && $ARGV[0] =~ /^-/) { + $_ = shift(@ARGV); + if (/^-acc$/) { $use_acc = 1; next; } + if (/^-d(ebug)?(\d+)?$/) { $debug = $2 || shift(@ARGV); next; } + if (/^-doctype$/) { $doctype = shift(@ARGV); next; } + if (/^-c(heck)?$/) { $check = 1; next; } + if (/^-e(xpandinfo)?$/) { $expandinfo = 1; next; } + if (/^-g(lossary)?$/) { $use_glossary = 1; next; } + if (/^-i(nvisible)?$/) { $invisible_mark = shift(@ARGV); next; } + if (/^-iso$/) { $use_iso = 1; next; } + if (/^-I(.+)?$/) { push(@include_dirs, $1 || shift(@ARGV)); next; } + if (/^-m(enu)?$/) { $show_menu = 1; next; } + if (/^-mono(lithic)?$/) { $monolithic = 1; next; } + if (/^-n(umber)?$/) { $number_sections = 1; next; } + if (/^-s(plit)?_?(n(ode)?|c(hapter)?)?$/) { + if ($2 =~ /^n/) { + $split_node = 1; + } else { + $split_chapter = 1; + } + next; + } + if (/^-v(erbose)?$/) { $verbose = 1; next; } + die $usage; +} +if ($check) { + die $usage unless @ARGV > 0; + ✓ + exit; +} + +if (($split_node || $split_chapter) && $monolithic) { + warn "Can't use -monolithic with -split, -monolithic ignored.\n"; + $monolithic = 0; +} +if ($expandinfo) { + $to_skip{'ifinfo'}++; + $to_skip{'end ifinfo'}++; +} else { + $to_skip{'iftex'}++; + $to_skip{'end iftex'}++; +} +$invisible_mark = '' if $invisible_mark eq 'xbm'; +die $usage unless @ARGV == 1; +$docu = shift(@ARGV); +if ($docu =~ /.*\//) { + chop($docu_dir = $&); + $docu_name = $'; +} else { + $docu_dir = '.'; + $docu_name = $docu; +} +unshift(@include_dirs, $docu_dir); +$docu_name =~ s/\.te?x(i|info)?$//; # basename of the document + +$docu_doc = "$docu_name.html"; # document's contents +if ($monolithic) { + $docu_toc = $docu_foot = $docu_doc; +} else { + $docu_toc = "${docu_name}_toc.html"; # document's table of contents + $docu_foot = "${docu_name}_foot.html"; # document's footnotes +} + +# +# variables +# +%value = (); # hold texinfo variables +$value{'html'} = 1; # predefine html (the output format) +$value{'texi2html'} = '1.51'; # predefine texi2html (the translator) +# _foo: internal to track @foo +foreach ('_author', '_title', '_subtitle', + '_settitle', '_setfilename') { + $value{$_} = ''; # prevent -w warnings +} +%node2sec = (); # node to section name +%node2href = (); # node to HREF +%bib2href = (); # bibliography reference to HREF +%gloss2href = (); # glossary term to HREF +@sections = (); # list of sections +%tag2pro = (); # protected sections + +# +# initial indexes +# +$bib_num = 0; +$foot_num = 0; +$gloss_num = 0; +$idx_num = 0; +$sec_num = 0; +$doc_num = 0; +$html_num = 0; + +# +# can I use ISO8879 characters? (HTML+) +# +if ($use_iso) { + $things_map{'bullet'} = "•"; + $things_map{'copyright'} = "©"; + $things_map{'dots'} = "…"; + $things_map{'equiv'} = "≡"; + $things_map{'expansion'} = "→"; + $things_map{'point'} = "∗"; + $things_map{'result'} = "⇒"; +} + +# +# read texi2html extensions (if any) +# +$extensions = 'texi2html.ext'; # extensions in working directory +if (-f $extensions) { + print "# reading extensions from $extensions\n" if $verbose; + require($extensions); +} +($progdir = $0) =~ s/[^\/]+$//; +if ($progdir && ($progdir ne './')) { + $extensions = "${progdir}texi2html.ext"; # extensions in texi2html directory + if (-f $extensions) { + print "# reading extensions from $extensions\n" if $verbose; + require($extensions); + } +} + +print "# reading from $docu\n" if $verbose; + +#+++############################################################################ +# # +# Pass 1: read source, handle command, variable, simple substitution # +# # +#---############################################################################ + +@lines = (); # whole document +@toc_lines = (); # table of contents +$toplevel = 0; # top level seen in hierarchy +$curlevel = 0; # current level in TOC +$node = ''; # current node name +$in_table = 0; # am I inside a table +$table_type = ''; # type of table ('', 'f', 'v') +@tables = (); # nested table support +$in_bibliography = 0; # am I inside a bibliography +$in_glossary = 0; # am I inside a glossary +$in_top = 0; # am I inside the top node +$in_pre = 0; # am I inside a preformatted section +$in_list = 0; # am I inside a list +$in_html = 0; # am I inside an HTML section +$first_line = 1; # is it the first line +$dont_html = 0; # don't protect HTML on this line +$split_num = 0; # split index +$deferred_ref = ''; # deferred reference for indexes +@html_stack = (); # HTML elements stack +$html_element = ''; # current HTML element +&html_reset; + +# build code for simple substitutions +# the maps used (%simple_map and %things_map) MUST be aware of this +# watch out for regexps, / and escaped characters! +$subst_code = ''; +foreach (keys(%simple_map)) { + ($re = $_) =~ s/(\W)/\\$1/g; # protect regexp chars + $subst_code .= "s/\\\@$re/$simple_map{$_}/g;\n"; +} +foreach (keys(%things_map)) { + $subst_code .= "s/\\\@$_\\{\\}/$things_map{$_}/g;\n"; +} +if ($use_acc) { + # accentuated characters + foreach (keys(%accent_map)) { + if ($_ eq "`") { + $subst_code .= "s/$;3"; + } elsif ($_ eq "'") { + $subst_code .= "s/$;4"; + } else { + $subst_code .= "s/\\\@\\$_"; + } + $subst_code .= "([aeiou])/&\${1}$accent_map{$_};/gi;\n"; + } +} +eval("sub simple_substitutions { $subst_code }"); + +&init_input; +while ($_ = &next_line) { + # + # remove \input on the first lines only + # + if ($first_line) { + next if /^\\input/; + $first_line = 0; + } + # + # parse texinfo tags + # + $tag = ''; + $end_tag = ''; + if (/^\@end\s+(\w+)\b/) { + $end_tag = $1; + } elsif (/^\@(\w+)\b/) { + $tag = $1; + } + # + # handle @ifhtml / @end ifhtml + # + if ($in_html) { + if ($end_tag eq 'ifhtml') { + $in_html = 0; + } else { + $tag2pro{$in_html} .= $_; + } + next; + } elsif ($tag eq 'ifhtml') { + $in_html = $PROTECTTAG . ++$html_num; + push(@lines, $in_html); + next; + } + # + # try to skip the line + # + if ($end_tag) { + next if $to_skip{"end $end_tag"}; + } elsif ($tag) { + next if $to_skip{$tag}; + last if $tag eq 'bye'; + } + if ($in_top) { + # parsing the top node + if ($tag eq 'node' || $tag eq 'include' || $sec2level{$tag}) { + # no more in top + $in_top = 0; + } else { + # skip it + next; + } + } + # + # try to remove inlined comments + # syntax from tex-mode.el comment-start-skip + # + s/((^|[^\@])(\@\@)*)\@c(omment)? .*/$1/; + # non-@ substitutions cf. texinfmt.el + s/``/\"/g; + s/''/\"/g; + s/([\w ])---([\w ])/$1--$2/g; + # + # analyze the tag + # + if ($tag) { + # skip lines + &skip_until($tag), next if $tag eq 'ignore'; + if ($expandinfo) { + &skip_until($tag), next if $tag eq 'iftex'; + } else { + &skip_until($tag), next if $tag eq 'ifinfo'; + } + &skip_until($tag), next if $tag eq 'tex'; + # handle special tables + if ($tag eq 'table') { + $table_type = ''; + } elsif ($tag eq 'ftable') { + $tag = 'table'; + $table_type = 'f'; + } elsif ($tag eq 'vtable') { + $tag = 'table'; + $table_type = 'v'; + } + # special cases + if ($tag eq 'top' || ($tag eq 'node' && /^\@node\s+top\s*,/i)) { + $in_top = 1; + @lines = (); # ignore all lines before top (title page garbage) + next; + } elsif ($tag eq 'node') { + $in_top = 0; + warn "$ERROR Bad node line: $_" unless $_ =~ /^\@node\s$NODESRE$/o; + $_ = &protect_html($_); # if node contains '&' for instance + s/^\@node\s+//; + ($node) = split(/,/); + &normalise_node($node); + if ($split_node) { + &next_doc; + push(@lines, $SPLITTAG) if $split_num++; + push(@sections, $node); + } + next; + } elsif ($tag eq 'include') { + if (/^\@include\s+($FILERE)\s*$/o) { + $file = $1; + unless (-e $file) { + foreach $dir (@include_dirs) { + $file = "$dir/$1"; + last if -e $file; + } + } + if (-e $file) { + &open($file); + print "# including $file\n" if $verbose; + } else { + warn "$ERROR Can't find $file, skipping"; + } + } else { + warn "$ERROR Bad include line: $_"; + } + next; + } elsif ($tag eq 'ifclear') { + if (/^\@ifclear\s+($VARRE)\s*$/o) { + next unless defined($value{$1}); + &skip_until($tag); + } else { + warn "$ERROR Bad ifclear line: $_"; + } + next; + } elsif ($tag eq 'ifset') { + if (/^\@ifset\s+($VARRE)\s*$/o) { + next if defined($value{$1}); + &skip_until($tag); + } else { + warn "$ERROR Bad ifset line: $_"; + } + next; + } elsif ($tag eq 'menu') { + unless ($show_menu) { + &skip_until($tag); + next; + } + &html_push_if($tag); + push(@lines, &html_debug("\n", __LINE__)); + } elsif ($format_map{$tag}) { + $in_pre = 1 if $format_map{$tag} eq 'PRE'; + &html_push_if($format_map{$tag}); + push(@lines, &html_debug("\n", __LINE__)); + $in_list++ if $format_map{$tag} eq 'UL' || $format_map{$tag} eq 'OL' ; + push(@lines, &debug("<$format_map{$tag}>\n", __LINE__)); + next; + } elsif ($tag eq 'table') { + if (/^\@[fv]?table\s+\@(\w+)\s*$/) { + $in_table = $1; + unshift(@tables, join($;, $table_type, $in_table)); + push(@lines, &debug("

\n", __LINE__)); + &html_push_if('DL'); + push(@lines, &html_debug("\n", __LINE__)); + } else { + warn "$ERROR Bad table line: $_"; + } + next; + } elsif ($tag eq 'synindex' || $tag eq 'syncodeindex') { + if (/^\@$tag\s+(\w)\w\s+(\w)\w\s*$/) { + eval("*${1}index = *${2}index"); + } else { + warn "$ERROR Bad syn*index line: $_"; + } + next; + } elsif ($tag eq 'sp') { + push(@lines, &debug("

\n", __LINE__)); + next; + } elsif ($tag eq 'setref') { + &protect_html; # if setref contains '&' for instance + if (/^\@$tag\s*{($NODERE)}\s*$/) { + $setref = $1; + $setref =~ s/\s+/ /g; # normalize + $setref =~ s/ $//; + $node2sec{$setref} = $name; + $node2href{$setref} = "$docu_doc#$docid"; + } else { + warn "$ERROR Bad setref line: $_"; + } + next; + } elsif ($tag eq 'defindex' || $tag eq 'defcodeindex') { + if (/^\@$tag\s+(\w\w)\s*$/) { + $valid_index{$1} = 1; + } else { + warn "$ERROR Bad defindex line: $_"; + } + next; + } elsif (defined($def_map{$tag})) { + if ($def_map{$tag}) { + s/^\@$tag\s+//; + $tag = $def_map{$tag}; + $_ = "\@$tag $_"; + $tag =~ s/\s.*//; + } + } elsif (defined($user_sub{$tag})) { + s/^\@$tag\s+//; + $sub = $user_sub{$tag}; + print "# user $tag = $sub, arg: $_" if $debug & $DEBUG_USER; + if (defined(&$sub)) { + chop($_); + &$sub($_); + } else { + warn "$ERROR Bad user sub for $tag: $sub\n"; + } + next; + } + if (defined($def_map{$tag})) { + s/^\@$tag\s+//; + if ($tag =~ /x$/) { + # extra definition line + $tag = $`; + $is_extra = 1; + } else { + $is_extra = 0; + } + while (/\{([^\{\}]*)\}/) { + # this is a {} construct + ($before, $contents, $after) = ($`, $1, $'); + # protect spaces + $contents =~ s/\s+/$;9/g; + # restore $_ protecting {} + $_ = "$before$;7$contents$;8$after"; + } + @args = split(/\s+/, &protect_html($_)); + foreach (@args) { + s/$;9/ /g; # unprotect spaces + s/$;7/\{/g; # ... { + s/$;8/\}/g; # ... } + } + $type = shift(@args); + $type =~ s/^\{(.*)\}$/$1/; + print "# def ($tag): {$type} ", join(', ', @args), "\n" + if $debug & $DEBUG_DEF; + $type .= ':'; # it's nicer like this + $name = shift(@args); + $name =~ s/^\{(.*)\}$/$1/; + if ($is_extra) { + $_ = &debug("

", __LINE__); + } else { + $_ = &debug("
\n
", __LINE__); + } + if ($tag eq 'deffn' || $tag eq 'defvr' || $tag eq 'deftp') { + $_ .= "$type $name"; + $_ .= " @args" if @args; + } elsif ($tag eq 'deftypefn' || $tag eq 'deftypevr' + || $tag eq 'defcv' || $tag eq 'defop') { + $ftype = $name; + $name = shift(@args); + $name =~ s/^\{(.*)\}$/$1/; + $_ .= "$type $ftype $name"; + $_ .= " @args" if @args; + } else { + warn "$ERROR Unknown definition type: $tag\n"; + $_ .= "$type $name"; + $_ .= " @args" if @args; + } + $_ .= &debug("\n
", __LINE__); + $name = &unprotect_html($name); + if ($tag eq 'deffn' || $tag eq 'deftypefn') { + unshift(@input_spool, "\@findex $name\n"); + } elsif ($tag eq 'defop') { + unshift(@input_spool, "\@findex $name on $ftype\n"); + } elsif ($tag eq 'defvr' || $tag eq 'deftypevr' || $tag eq 'defcv') { + unshift(@input_spool, "\@vindex $name\n"); + } else { + unshift(@input_spool, "\@tindex $name\n"); + } + $dont_html = 1; + } + } elsif ($end_tag) { + if ($format_map{$end_tag}) { + $in_pre = 0 if $format_map{$end_tag} eq 'PRE'; + $in_list-- if $format_map{$end_tag} eq 'UL' || $format_map{$end_tag} eq 'OL' ; + &html_pop_if('LI', 'P'); + &html_pop_if(); + push(@lines, &debug("\n", __LINE__)); + push(@lines, &html_debug("\n", __LINE__)); + } elsif ($end_tag eq 'table' || + $end_tag eq 'ftable' || + $end_tag eq 'vtable') { + shift(@tables); + if (@tables) { + ($table_type, $in_table) = split($;, $tables[0]); + } else { + $in_table = 0; + } + push(@lines, "
\n"); + &html_pop_if('DD'); + &html_pop_if(); + } elsif (defined($def_map{$end_tag})) { + push(@lines, &debug("
\n", __LINE__)); + } elsif ($end_tag eq 'menu') { + &html_pop_if(); + push(@lines, $_); # must keep it for pass 2 + } + next; + } + # + # misc things + # + # protect texi and HTML things + &protect_texi; + $_ = &protect_html($_) unless $dont_html; + $dont_html = 0; + # substitution (unsupported things) + s/^\@center\s+//g; + s/^\@exdent\s+//g; + s/\@noindent\s+//g; + s/\@refill\s+//g; + # other substitutions + &simple_substitutions; + s/\@value{($VARRE)}/$value{$1}/eg; + s/\@footnote\{/\@footnote$docu_doc\{/g; # mark footnotes, cf. pass 4 + # + # analyze the tag again + # + if ($tag) { + if (defined($sec2level{$tag}) && $sec2level{$tag} > 0) { + if (/^\@$tag\s+(.+)$/) { + $name = $1; + $name =~ s/\s+$//; + $level = $sec2level{$tag}; + $name = &update_sec_num($tag, $level) . " $name" + if $number_sections && $tag !~ /^unnumbered/; + if ($tag =~ /heading$/) { + push(@lines, &html_debug("\n", __LINE__)); + if ($html_element ne 'body') { + # We are in a nice pickle here. We are trying to get a H? heading + # even though we are not in the body level. So, we convert it to a + # nice, bold, line by itself. + $_ = &debug("\n\n

$name

\n\n", __LINE__); + } else { + $_ = &debug("$name\n", __LINE__); + &html_push_if('body'); + } + print "# heading, section $name, level $level\n" + if $debug & $DEBUG_TOC; + } else { + if ($split_chapter) { + unless ($toplevel) { + # first time we see a "section" + unless ($level == 1) { + warn "$ERROR The first section found is not of level 1: $_"; + warn "$ERROR I'll split on sections of level $level...\n"; + } + $toplevel = $level; + } + if ($level == $toplevel) { + &next_doc; + push(@lines, $SPLITTAG) if $split_num++; + push(@sections, $name); + } + } + $sec_num++; + $docid = "SEC$sec_num"; + $tocid = "TOC$sec_num"; + # check biblio and glossary + $in_bibliography = ($name =~ /^([A-Z]|\d+)?(\.\d+)*\s*bibliography$/i); + $in_glossary = ($name =~ /^([A-Z]|\d+)?(\.\d+)*\s*glossary$/i); + # check node + if ($node) { + if ($node2sec{$node}) { + warn "$ERROR Duplicate node found: $node\n"; + } else { + $node2sec{$node} = $name; + $node2href{$node} = "$docu_doc#$docid"; + print "# node $node, section $name, level $level\n" + if $debug & $DEBUG_TOC; + } + $node = ''; + } else { + print "# no node, section $name, level $level\n" + if $debug & $DEBUG_TOC; + } + # update TOC + while ($level > $curlevel) { + $curlevel++; + push(@toc_lines, "
    \n"); + } + while ($level < $curlevel) { + $curlevel--; + push(@toc_lines, "
\n"); + } + $_ = "
  • " . &anchor($tocid, "$docu_doc#$docid", $name, 1); + push(@toc_lines, &substitute_style($_)); + # update DOC + push(@lines, &html_debug("\n", __LINE__)); + &html_reset; + $_ = "".&anchor($docid, "$docu_toc#$tocid", $name)."\n"; + $_ = &debug($_, __LINE__); + push(@lines, &html_debug("\n", __LINE__)); + } + # update DOC + foreach $line (split(/\n+/, $_)) { + push(@lines, "$line\n"); + } + next; + } else { + warn "$ERROR Bad section line: $_"; + } + } else { + # track variables + $value{$1} = $2, next if /^\@set\s+($VARRE)\s+(.*)$/o; + delete $value{$1}, next if /^\@clear\s+($VARRE)\s*$/o; + # store things + $value{'_setfilename'} = $1, next if /^\@setfilename\s+(.*)$/; + $value{'_settitle'} = $1, next if /^\@settitle\s+(.*)$/; + $value{'_author'} .= "$1\n", next if /^\@author\s+(.*)$/; + $value{'_subtitle'} .= "$1\n", next if /^\@subtitle\s+(.*)$/; + $value{'_title'} .= "$1\n", next if /^\@title\s+(.*)$/; + # index + if (/^\@(..?)index\s+/) { + unless ($valid_index{$1}) { + warn "$ERROR Undefined index command: $_"; + next; + } + $id = 'IDX' . ++$idx_num; + $index = $1 . 'index'; + $what = &substitute_style($'); + $what =~ s/\s+$//; + print "# found $index for '$what' id $id\n" + if $debug & $DEBUG_INDEX; + eval(<\n", __LINE__)); + push(@lines, &anchor($id, '', $invisible_mark, !$in_pre)); + &html_push('P'); + } elsif ($html_element eq 'DL' || + $html_element eq 'UL' || + $html_element eq 'OL' ) { + $deferred_ref .= &anchor($id, '', $invisible_mark, !$in_pre) . " "; + } + next; + } + # list item + if (/^\@itemx?\s+/) { + $what = $'; + $what =~ s/\s+$//; + if ($in_bibliography && $use_bibliography) { + if ($what =~ /^$BIBRE$/o) { + $id = 'BIB' . ++$bib_num; + $bib2href{$what} = "$docu_doc#$id"; + print "# found bibliography for '$what' id $id\n" + if $debug & $DEBUG_BIB; + $what = &anchor($id, '', $what); + } + } elsif ($in_glossary && $use_glossary) { + $id = 'GLOSS' . ++$gloss_num; + $entry = $what; + $entry =~ tr/A-Z/a-z/ unless $entry =~ /^[A-Z\s]+$/; + $gloss2href{$entry} = "$docu_doc#$id"; + print "# found glossary for '$entry' id $id\n" + if $debug & $DEBUG_GLOSS; + $what = &anchor($id, '', $what); + } + &html_pop_if('P'); + if ($html_element eq 'DL' || $html_element eq 'DD') { + if ($things_map{$in_table} && !$what) { + # special case to allow @table @bullet for instance + push(@lines, &debug("
    $things_map{$in_table}\n", __LINE__)); + } else { + push(@lines, &debug("
    \@$in_table\{$what\}\n", __LINE__)); + } + push(@lines, "
    "); + &html_push('DD') unless $html_element eq 'DD'; + if ($table_type) { # add also an index + unshift(@input_spool, "\@${table_type}index $what\n"); + } + } else { + push(@lines, &debug("
  • $what\n", __LINE__)); + &html_push('LI') unless $html_element eq 'LI'; + } + push(@lines, &html_debug("\n", __LINE__)); + if ($deferred_ref) { + push(@lines, &debug("$deferred_ref\n", __LINE__)); + $deferred_ref = ''; + } + next; + } + } + } + # paragraph separator + if ($_ eq "\n") { + next if $#lines >= 0 && $lines[$#lines] eq "\n"; + if ($html_element eq 'P') { + push(@lines, "\n"); + $_ = &debug("

    \n", __LINE__); + &html_pop; + } + } elsif ($html_element eq 'body' || $html_element eq 'BLOCKQUOTE') { + push(@lines, "

    \n"); + &html_push('P'); + $_ = &debug($_, __LINE__); + } + # otherwise + push(@lines, $_); +} + +# finish TOC +$level = 0; +while ($level < $curlevel) { + $curlevel--; + push(@toc_lines, "\n"); +} + +print "# end of pass 1\n" if $verbose; + +#+++############################################################################ +# # +# Pass 2/3: handle style, menu, index, cross-reference # +# # +#---############################################################################ + +@lines2 = (); # whole document (2nd pass) +@lines3 = (); # whole document (3rd pass) +$in_menu = 0; # am I inside a menu + +while (@lines) { + $_ = shift(@lines); + # + # special case (protected sections) + # + if (/^$PROTECTTAG/o) { + push(@lines2, $_); + next; + } + # + # menu + # + $in_menu = 1, push(@lines2, &debug("

      \n", __LINE__)), next if /^\@menu\b/; + $in_menu = 0, push(@lines2, &debug("
    \n", __LINE__)), next if /^\@end\s+menu\b/; + if ($in_menu) { + if (/^\*\s+($NODERE)::/o) { + $descr = $'; + chop($descr); + &menu_entry($1, $1, $descr); + } elsif (/^\*\s+(.+):\s+([^\t,\.\n]+)[\t,\.\n]/) { + $descr = $'; + chop($descr); + &menu_entry($1, $2, $descr); + } elsif (/^\*/) { + warn "$ERROR Bad menu line: $_"; + } else { # description continued? + push(@lines2, $_); + } + next; + } + # + # printindex + # + if (/^\@printindex\s+(\w\w)\b/) { + local($index, *ary, @keys, $key, $letter, $last_letter, @refs); + if ($predefined_index{$1}) { + $index = $predefined_index{$1} . 'index'; + } else { + $index = $1 . 'index'; + } + eval("*ary = *$index"); + @keys = keys(%ary); + foreach $key (@keys) { + $_ = $key; + 1 while s/<(\w+)>\`(.*)\'<\/\1>/$2/; # remove HTML tags with quotes + 1 while s/<(\w+)>(.*)<\/\1>/$2/; # remove HTML tags + $_ = &unprotect_html($_); + &unprotect_texi; + tr/A-Z/a-z/; # lowercase + $key2alpha{$key} = $_; + print "# index $key sorted as $_\n" + if $key ne $_ && $debug & $DEBUG_INDEX; + } + $last_letter = undef; + foreach $key (sort byalpha @keys) { + $letter = substr($key2alpha{$key}, 0, 1); + $letter = substr($key2alpha{$key}, 0, 2) if $letter eq $;; + if (!defined($last_letter) || $letter ne $last_letter) { + push(@lines2, "\n") if defined($last_letter); + push(@lines2, "

    " . &protect_html($letter) . "

    \n"); + push(@lines2, "\n"); + $last_letter = $letter; + } + @refs = (); + foreach (split(/$;/, $ary{$key})) { + push(@refs, &anchor('', $_, $key, 0)); + } + push(@lines2, "
  • " . join(", ", @refs) . "\n"); + } + push(@lines2, "
  • \n") if defined($last_letter); + next; + } + # + # simple style substitutions + # + $_ = &substitute_style($_); + # + # xref + # + while (/\@(x|px|info|)ref{($XREFRE)(}?)/o) { + # note: Texinfo may accept other characters + ($type, $nodes, $full) = ($1, $2, $3); + ($before, $after) = ($`, $'); + if (! $full && $after) { + warn "$ERROR Bad xref (no ending } on line): $_"; + $_ = "$before$;0${type}ref\{$nodes$after"; + next; # while xref + } + if ($type eq 'x') { + $type = 'See '; + } elsif ($type eq 'px') { + $type = 'see '; + } elsif ($type eq 'info') { + $type = 'See Info'; + } else { + $type = ''; + } + unless ($full) { + $next = shift(@lines); + $next = &substitute_style($next); + chop($nodes); # remove final newline + if ($next =~ /\}/) { # split on 2 lines + $nodes .= " $`"; + $after = $'; + } else { + $nodes .= " $next"; + $next = shift(@lines); + $next = &substitute_style($next); + chop($nodes); + if ($next =~ /\}/) { # split on 3 lines + $nodes .= " $`"; + $after = $'; + } else { + warn "$ERROR Bad xref (no ending }): $_"; + $_ = "$before$;0xref\{$nodes$after"; + unshift(@lines, $next); + next; # while xref + } + } + } + $nodes =~ s/\s+/ /g; # remove useless spaces + @args = split(/\s*,\s*/, $nodes); + $node = $args[0]; # the node is always the first arg + &normalise_node($node); + $sec = $node2sec{$node}; + if (@args == 5) { # reference to another manual + $sec = $args[2] || $node; + $man = $args[4] || $args[3]; + $_ = "${before}${type}section `$sec' in \@cite{$man}$after"; + } elsif ($type =~ /Info/) { # inforef + warn "$ERROR Wrong number of arguments: $_" unless @args == 3; + ($nn, $_, $in) = @args; + $_ = "${before}${type} file `$in', node `$nn'$after"; + } elsif ($sec) { + $href = $node2href{$node}; + $_ = "${before}${type}section " . &anchor('', $href, $sec) . $after; + } else { + warn "$ERROR Undefined node ($node): $_"; + $_ = "$before$;0xref{$nodes}$after"; + } + } + # + # try to guess bibliography references or glossary terms + # + unless (/^/) { + $done .= $pre . &anchor('', $href, $what); + } else { + $done .= "$pre$what"; + } + $_ = $post; + } + $_ = $done . $_; + } + if ($use_glossary) { + $done = ''; + while (/\b\w+\b/) { + ($pre, $what, $post) = ($`, $&, $'); + $entry = $what; + $entry =~ tr/A-Z/a-z/ unless $entry =~ /^[A-Z\s]+$/; + $href = $gloss2href{$entry}; + if (defined($href) && $post !~ /^[^<]*<\/A>/) { + $done .= $pre . &anchor('', $href, $what); + } else { + $done .= "$pre$what"; + } + $_ = $post; + } + $_ = $done . $_; + } + } + # otherwise + push(@lines2, $_); +} +print "# end of pass 2\n" if $verbose; + +# +# split style substitutions +# +while (@lines2) { + $_ = shift(@lines2); + # + # special case (protected sections) + # + if (/^$PROTECTTAG/o) { + push(@lines3, $_); + next; + } + # + # split style substitutions + # + $old = ''; + while ($old ne $_) { + $old = $_; + if (/\@(\w+)\{/) { + ($before, $style, $after) = ($`, $1, $'); + if (defined($style_map{$style})) { + $_ = $after; + $text = ''; + $after = ''; + $failed = 1; + while (@lines2) { + if (/\}/) { + $text .= $`; + $after = $'; + $failed = 0; + last; + } else { + $text .= $_; + $_ = shift(@lines2); + } + } + if ($failed) { + die "* Bad syntax (\@$style) after: $before\n"; + } else { + $text = &apply_style($style, $text); + $_ = "$before$text$after"; + } + } + } + } + # otherwise + push(@lines3, $_); +} +print "# end of pass 3\n" if $verbose; + +#+++############################################################################ +# # +# Pass 4: foot notes, final cleanup # +# # +#---############################################################################ + +@foot_lines = (); # footnotes +@doc_lines = (); # final document +$end_of_para = 0; # true if last line is

    + +while (@lines3) { + $_ = shift(@lines3); + # + # special case (protected sections) + # + if (/^$PROTECTTAG/o) { + push(@doc_lines, $_); + $end_of_para = 0; + next; + } + # + # footnotes + # + while (/\@footnote([^\{\s]+)\{/) { + ($before, $d, $after) = ($`, $1, $'); + $_ = $after; + $text = ''; + $after = ''; + $failed = 1; + while (@lines3) { + if (/\}/) { + $text .= $`; + $after = $'; + $failed = 0; + last; + } else { + $text .= $_; + $_ = shift(@lines3); + } + } + if ($failed) { + die "* Bad syntax (\@footnote) after: $before\n"; + } else { + $foot_num++; + $docid = "DOCF$foot_num"; + $footid = "FOOT$foot_num"; + $foot = "($foot_num)"; + push(@foot_lines, "

    " . &anchor($footid, "$d#$docid", $foot) . "

    \n"); + $text = "

    $text" unless $text =~ /^\s*

    /; + push(@foot_lines, "$text\n"); + $_ = $before . &anchor($docid, "$docu_foot#$footid", $foot) . $after; + } + } + # + # remove unnecessary

    + # + if (/^\s*

    \s*$/) { + next if $end_of_para++; + } else { + $end_of_para = 0; + } + # otherwise + push(@doc_lines, $_); +} +print "# end of pass 4\n" if $verbose; + +#+++############################################################################ +# # +# Pass 5: print things # +# # +#---############################################################################ + +$header = < +EOT + +$full_title = $value{'_title'} || $value{'_settitle'} || "Untitled Document"; +$title = $value{'_settitle'} || $full_title; +$_ = &substitute_style($full_title); +&unprotect_texi; +s/\n$//; # rmv last \n (if any) +$full_title = "

    " . join("

    \n

    ", split(/\n/, $_)) . "

    \n"; + +# +# print ToC +# +if (!$monolithic && @toc_lines) { + if (open(FILE, "> $docu_toc")) { + print "# creating $docu_toc...\n" if $verbose; + &print_toplevel_header("$title - Table of Contents"); + &print_ruler; + &print(*toc_lines, FILE); + &print_toplevel_footer; + close(FILE); + } else { + warn "$ERROR Can't write to $docu_toc: $!\n"; + } +} + +# +# print footnotes +# +if (!$monolithic && @foot_lines) { + if (open(FILE, "> $docu_foot")) { + print "# creating $docu_foot...\n" if $verbose; + &print_toplevel_header("$title - Footnotes"); + &print_ruler; + &print(*foot_lines, FILE); + &print_toplevel_footer; + close(FILE); + } else { + warn "$ERROR Can't write to $docu_foot: $!\n"; + } +} + +# +# print document +# +if ($split_chapter || $split_node) { # split + $doc_num = 0; + $last_num = scalar(@sections); + $first_doc = &doc_name(1); + $last_doc = &doc_name($last_num); + while (@sections) { + $section = shift(@sections); + &next_doc; + if (open(FILE, "> $docu_doc")) { + print "# creating $docu_doc...\n" if $verbose; + &print_header("$title - $section"); + $prev_doc = ($doc_num == 1 ? undef : &doc_name($doc_num - 1)); + $next_doc = ($doc_num == $last_num ? undef : &doc_name($doc_num + 1)); + $navigation = "Go to the "; + $navigation .= ($prev_doc ? &anchor('', $first_doc, "first") : "first"); + $navigation .= ", "; + $navigation .= ($prev_doc ? &anchor('', $prev_doc, "previous") : "previous"); + $navigation .= ", "; + $navigation .= ($next_doc ? &anchor('', $next_doc, "next") : "next"); + $navigation .= ", "; + $navigation .= ($next_doc ? &anchor('', $last_doc, "last") : "last"); + $navigation .= " section, " . &anchor('', $docu_toc, "table of contents") . ".\n"; + print FILE $navigation; + &print_ruler; + # find corresponding lines + @tmp_lines = (); + while (@doc_lines) { + $_ = shift(@doc_lines); + last if ($_ eq $SPLITTAG); + push(@tmp_lines, $_); + } + &print(*tmp_lines, FILE); + &print_ruler; + print FILE $navigation; + &print_footer; + close(FILE); + } else { + warn "$ERROR Can't write to $docu_doc: $!\n"; + } + } +} else { # not split + if (open(FILE, "> $docu_doc")) { + print "# creating $docu_doc...\n" if $verbose; + if ($monolithic || !@toc_lines) { + &print_toplevel_header($title); + } else { + &print_header($title); + print FILE $full_title; + } + if ($monolithic && @toc_lines) { + &print_ruler; + print FILE "

    Table of Contents

    \n"; + &print(*toc_lines, FILE); + } + &print_ruler; + &print(*doc_lines, FILE); + if ($monolithic && @foot_lines) { + &print_ruler; + print FILE "

    Footnotes

    \n"; + &print(*foot_lines, FILE); + } + if ($monolithic || !@toc_lines) { + &print_toplevel_footer; + } else { + &print_footer; + } + close(FILE); + } else { + warn "$ERROR Can't write to $docu_doc: $!\n"; + } +} + +print "# that's all folks\n" if $verbose; + +#+++############################################################################ +# # +# Low level functions # +# # +#---############################################################################ + +sub update_sec_num { + local($name, $level) = @_; + + $level--; # here we start at 0 + if ($name =~ /^appendix/) { + # appendix style + if (defined(@appendix_sec_num)) { + &incr_sec_num($level, @appendix_sec_num); + } else { + @appendix_sec_num = ('A', 0, 0, 0); + } + return(join('.', @appendix_sec_num[0..$level])); + } else { + # normal style + if (defined(@normal_sec_num)) { + &incr_sec_num($level, @normal_sec_num); + } else { + @normal_sec_num = (1, 0, 0, 0); + } + return(join('.', @normal_sec_num[0..$level])); + } +} + +sub incr_sec_num { + local($level, $l); + $level = shift(@_); + $_[$level]++; + foreach $l ($level+1 .. 3) { + $_[$l] = 0; + } +} + +sub check { + local($_, %seen, %context, $before, $match, $after); + + while (<>) { + if (/\@(\*|\.|\:|\@|\{|\})/) { + $seen{$&}++; + $context{$&} .= "> $_" if $verbose; + $_ = "$`XX$'"; + redo; + } + if (/\@(\w+)/) { + ($before, $match, $after) = ($`, $&, $'); + if ($before =~ /\b[\w-]+$/ && $after =~ /^[\w-.]*\b/) { # e-mail address + $seen{'e-mail address'}++; + $context{'e-mail address'} .= "> $_" if $verbose; + } else { + $seen{$match}++; + $context{$match} .= "> $_" if $verbose; + } + $match =~ s/^\@/X/; + $_ = "$before$match$after"; + redo; + } + } + + foreach (sort(keys(%seen))) { + if ($verbose) { + print "$_\n"; + print $context{$_}; + } else { + print "$_ ($seen{$_})\n"; + } + } +} + +sub open { + local($name) = @_; + + ++$fh_name; + if (open($fh_name, $name)) { + unshift(@fhs, $fh_name); + } else { + warn "$ERROR Can't read file $name: $!\n"; + } +} + +sub init_input { + @fhs = (); # hold the file handles to read + @input_spool = (); # spooled lines to read + $fh_name = 'FH000'; + &open($docu); +} + +sub next_line { + local($fh, $line); + + if (@input_spool) { + $line = shift(@input_spool); + return($line); + } + while (@fhs) { + $fh = $fhs[0]; + $line = <$fh>; + return($line) if $line; + close($fh); + shift(@fhs); + } + return(undef); +} + +# used in pass 1, use &next_line +sub skip_until { + local($tag) = @_; + local($_); + + while ($_ = &next_line) { + return if /^\@end\s+$tag\s*$/; + } + die "* Failed to find '$tag' after: " . $lines[$#lines]; +} + +# +# HTML stacking to have a better HTML output +# + +sub html_reset { + @html_stack = ('html'); + $html_element = 'body'; +} + +sub html_push { + local($what) = @_; + push(@html_stack, $html_element); + $html_element = $what; +} + +sub html_push_if { + local($what) = @_; + push(@html_stack, $html_element) + if ($html_element && $html_element ne 'P'); + $html_element = $what; +} + +sub html_pop { + $html_element = pop(@html_stack); +} + +sub html_pop_if { + local($elt); + + if (@_) { + foreach $elt (@_) { + if ($elt eq $html_element) { + $html_element = pop(@html_stack) if @html_stack; + last; + } + } + } else { + $html_element = pop(@html_stack) if @html_stack; + } +} + +sub html_debug { + local($what, $line) = @_; + return("$what") + if $debug & $DEBUG_HTML; + return($what); +} + +# to debug the output... +sub debug { + local($what, $line) = @_; + return("$what") + if $debug & $DEBUG_HTML; + return($what); +} + +sub normalise_node { + $_[0] =~ s/\s+/ /g; + $_[0] =~ s/ $//; + $_[0] =~ s/^ //; +} + +sub menu_entry { + local($entry, $node, $descr) = @_; + local($href); + + &normalise_node($node); + $href = $node2href{$node}; + if ($href) { + $descr =~ s/^\s+//; + $descr = ": $descr" if $descr; + push(@lines2, "
  • " . &anchor('', $href, $entry) . "$descr\n"); + } else { + warn "$ERROR Undefined node ($node): $_"; + } +} + +sub do_ctrl { "^$_[0]" } + +sub do_sc { "\U$_[0]\E" } + +sub apply_style { + local($texi_style, $text) = @_; + local($style); + + $style = $style_map{$texi_style}; + if (defined($style)) { # known style + if ($style =~ /^\"/) { # add quotes + $style = $'; + $text = "\`$text\'"; + } + if ($style =~ /^\&/) { # custom + $style = $'; + $text = &$style($text); + } elsif ($style) { # good style + $text = "<$style>$text"; + } else { # no style + } + } else { # unknown style + $text = undef; + } + return($text); +} + +# remove Texinfo styles +sub remove_style { + local($_) = @_; + s/\@\w+{([^\{\}]+)}/$1/g; + return($_); +} + +sub substitute_style { + local($_) = @_; + local($changed, $done, $style, $text); + + $changed = 1; + while ($changed) { + $changed = 0; + $done = ''; + while (/\@(\w+){([^\{\}]+)}/) { + $text = &apply_style($1, $2); + if ($text) { + $_ = "$`$text$'"; + $changed = 1; + } else { + $done .= "$`\@$1"; + $_ = "{$2}$'"; + } + } + $_ = $done . $_; + } + return($_); +} + +sub anchor { + local($name, $href, $text, $newline) = @_; + local($result); + + $result = "

    \n"; +} + +sub print_header { + local($_); + + # clean the title + $_ = &remove_style($_[0]); + &unprotect_texi; + # print the header + if ($doctype eq 'html2') { + print FILE $html2_doctype; + } elsif ($doctype) { + print FILE $doctype; + } + print FILE < + +$header +$_ + + +EOT +} + +sub print_toplevel_header { + local($_); + + &print_header; # pass given arg... + print FILE $full_title; + if ($value{'_subtitle'}) { + $value{'_subtitle'} =~ s/\n+$//; + foreach (split(/\n/, $value{'_subtitle'})) { + $_ = &substitute_style($_); + &unprotect_texi; + print FILE "

    $_

    \n"; + } + } + if ($value{'_author'}) { + $value{'_author'} =~ s/\n+$//; + foreach (split(/\n/, $value{'_author'})) { + $_ = &substitute_style($_); + &unprotect_texi; + s/[\w.-]+\@[\w.-]+/
    $&<\/A>/g; + print FILE "
    $_
    \n"; + } + } + print FILE "

    \n"; +} + +sub print_footer { + print FILE < + +EOT +} + +sub print_toplevel_footer { + &print_ruler; + print FILE <texi2html +translator version 1.51.

    +EOT + &print_footer; +} + +sub protect_texi { + # protect @ { } ` ' + s/\@\@/$;0/go; + s/\@\{/$;1/go; + s/\@\}/$;2/go; + s/\@\`/$;3/go; + s/\@\'/$;4/go; +} + +sub protect_html { + local($what) = @_; + # protect & < > + $what =~ s/\&/\&\#38;/g; + $what =~ s/\/\&\#62;/g; + # but recognize some HTML things + $what =~ s/\&\#60;\/A\&\#62;/<\/A>/g; # + $what =~ s/\&\#60;A ([^\&]+)\&\#62;//g; # + $what =~ s/\&\#60;IMG ([^\&]+)\&\#62;//g; # + return($what); +} + +sub unprotect_texi { + s/$;0/\@/go; + s/$;1/\{/go; + s/$;2/\}/go; + s/$;3/\`/go; + s/$;4/\'/go; +} + +sub unprotect_html { + local($what) = @_; + $what =~ s/\&\#38;/\&/g; + $what =~ s/\&\#60;/\/g; + return($what); +} + +sub byalpha { + $key2alpha{$a} cmp $key2alpha{$b}; +} + +############################################################################## + + # These next few lines are legal in both Perl and nroff. + +.00 ; # finish .ig + +'di \" finish diversion--previous line must be blank +.nr nl 0-1 \" fake up transition to first page again +.nr % 0 \" start at page 1 +'; __END__ ############# From here on it's a standard manual page ############ +.TH TEXI2HTML 1 "09/10/96" +.AT 3 +.SH NAME +texi2html \- a Texinfo to HTML converter +.SH SYNOPSIS +.B texi2html [options] file +.PP +.B texi2html -check [-verbose] files +.SH DESCRIPTION +.I Texi2html +converts the given Texinfo file to a set of HTML files. It tries to handle +most of the Texinfo commands. It creates hypertext links for cross-references, +footnotes... +.PP +It also tries to add links from a reference to its corresponding entry in the +bibliography (if any). It may also handle a glossary (see the +.B \-glossary +option). +.PP +.I Texi2html +creates several files depending on the contents of the Texinfo file and on +the chosen options (see FILES). +.PP +The HTML files created by +.I texi2html +are closer to TeX than to Info, that's why +.I texi2html +converts @iftex sections and not @ifinfo ones by default. You can reverse +this with the \-expandinfo option. +.SH OPTIONS +.TP 12 +.B \-check +Check the given file and give the list of all things that may be Texinfo commands. +This may be used to check the output of +.I texi2html +to find the Texinfo commands that have been left in the HTML file. +.TP +.B \-expandinfo +Expand @ifinfo sections, not @iftex ones. +.TP +.B \-glossary +Use the section named 'Glossary' to build a list of terms and put links in the HTML +document from each term toward its definition. +.TP +.B \-invisible \fIname\fP +Use \fIname\fP to create invisible destination anchors for index links. This is a workaround +for a known bug of many WWW browsers, including xmosaic. +.TP +.B \-I \fIdir\fP +Look also in \fIdir\fP to find included files. +.TP +.B \-menu +Show the Texinfo menus; by default they are ignored. +.TP +.B \-monolithic +Output only one file, including the table of contents and footnotes. +.TP +.B \-number +Number the sections. +.TP +.B \-split_chapter +Split the output into several HTML files (one per main section: +chapter, appendix...). +.TP +.B \-split_node +Split the output into several HTML files (one per node). +.TP +.B \-usage +Print usage instructions, listing the current available command-line options. +.TP +.B \-verbose +Give a verbose output. Can be used with the +.B \-check +option. +.PP +.SH FILES +By default +.I texi2html +creates the following files (foo being the name of the Texinfo file): +.TP 16 +.B foo_toc.html +The table of contents. +.TP +.B foo.html +The document's contents. +.TP +.B foo_foot.html +The footnotes (if any). +.PP +When used with the +.B \-split +option, it creates several files (one per chapter or node), named +.B foo_n.html +(n being the indice of the chapter or node), instead of the single +.B foo.html +file. +.PP +When used with the +.B \-monolithic +option, it creates only one file: +.B foo.html +.SH VARIABLES +.I texi2html +predefines the following variables: \fBhtml\fP, \fBtexi2html\fP. +.SH ADDITIONAL COMMANDS +.I texi2html +implements the following non-Texinfo commands: +.TP 16 +.B @ifhtml +This indicates the start of an HTML section, this section will passed through +without any modofication. +.TP +.B @end ifhtml +This indcates the end of an HTML section. +.SH VERSION +This is \fItexi2html\fP version 1.51, 09/10/96. +.PP +The latest version of \fItexi2html\fP can be found in WWW, cf. URL +http://wwwcn.cern.ch/dci/texi2html/ +.SH AUTHOR +The main author is Lionel Cons, CERN CN/DCI/UWS, Lionel.Cons@cern.ch. +Many other people around the net contributed to this program. +.SH COPYRIGHT +This program is the intellectual property of the European +Laboratory for Particle Physics (known as CERN). No guarantee whatsoever is +provided by CERN. No liability whatsoever is accepted for any loss or damage +of any kind resulting from any defect or inaccuracy in this information or +code. +.PP +CERN, 1211 Geneva 23, Switzerland +.SH "SEE ALSO" +GNU Texinfo Documentation Format, +HyperText Markup Language (HTML), +World Wide Web (WWW). +.SH BUGS +This program does not understand all Texinfo commands (yet). +.PP +TeX specific commands (normally enclosed in @iftex) will be +passed unmodified. +.ex diff --git a/support/zecho.c b/support/zecho.c new file mode 100644 index 0000000..151fac3 --- /dev/null +++ b/support/zecho.c @@ -0,0 +1,20 @@ +/* zecho - bare-bones echo */ + +#include + +int +main(argc, argv) +int argc; +char **argv; +{ + argv++; + + while (*argv) { + (void)printf("%s", *argv); + if (*++argv) + putchar(' '); + } + + putchar('\n'); + exit(0); +} diff --git a/test.c b/test.c index d8356f1..dae19ac 100644 --- a/test.c +++ b/test.c @@ -20,22 +20,52 @@ with Bash; see the file COPYING. If not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ -/* Define STANDALONE to get the /bin/test version. Otherwise, you get +/* Define STANDALONE to get the /bin/test version. Otherwise, you get the shell builtin version. */ /* #define STANDALONE */ +/* Define PATTERN_MATCHING to get the csh-like =~ and !~ pattern-matching + binary operators. */ +/* #define PATTERN_MATCHING */ + +#if defined (HAVE_CONFIG_H) +# include +#endif + #include -#include "bashtypes.h" + +#if defined (STANDALONE) +# include +#else +# include "bashtypes.h" +#endif + +#if defined (HAVE_LIMITS_H) +# include +#else +# include +#endif + +#if defined (HAVE_UNISTD_H) +# include +#endif + +#if !defined (_POSIX_VERSION) +# include +#endif /* !_POSIX_VERSION */ +#include "posixstat.h" +#include "filecntl.h" #if !defined (STANDALONE) -# if !defined (_POSIX_VERSION) -# include -# endif /* !_POSIX_VERSION */ -# include "posixstat.h" -# include "filecntl.h" # include "shell.h" +# include "builtins/common.h" +# define main test_command +# define isint legal_number +# define getuid() current_user.uid +# define geteuid() current_user.euid +# define getgid() current_user.gid +# define getegid() current_user.egid #else /* STANDALONE */ -# include "system.h" # if !defined (S_IXUGO) # define S_IXUGO 0111 # endif @@ -65,33 +95,14 @@ extern int errno; #endif /* !member */ /* Make gid_t and uid_t mean something for non-posix systems. */ -#if !defined (_POSIX_VERSION) && !defined (HAVE_UID_T) +#if defined (STANDALONE) && !defined (_POSIX_VERSION) && !defined (HAVE_UID_T) # if !defined (gid_t) # define gid_t int # endif # if !defined (uid_t) # define uid_t int # endif -#endif /* !_POSIX_VERSION */ - -/* What type are the user and group ids? GID_T is actually the type of - the members of the array that getgroups(3) fills in from its second - argument. */ -#if defined (INT_GROUPS_ARRAY) -# define GID_T int -# define UID_T int -#else /* !INT_GROUPS_ARRAY */ -# define GID_T gid_t -# define UID_T uid_t -#endif /* !INT_GROUPS_ARRAY */ - -#if !defined (Linux) && !defined (USGr4_2) && !defined (SunOS5) -extern gid_t getegid (); -extern uid_t geteuid (); -# if !defined (sony) -extern gid_t getgid (); -# endif /* !sony */ -#endif /* !Linux && !USGr4_2 && !SunOS5 */ +#endif /* STANDALONE && !_POSIX_VERSION && !HAVE_UID_T */ #if !defined (R_OK) #define R_OK 4 @@ -100,24 +111,30 @@ extern gid_t getgid (); #define F_OK 0 #endif /* R_OK */ +#define EQ 0 +#define NE 1 +#define LT 2 +#define GT 3 +#define LE 4 +#define GE 5 + +#define NT 0 +#define OT 1 +#define EF 2 + /* The following few defines control the truth and false output of each stage. TRUE and FALSE are what we use to compute the final output value. SHELL_BOOLEAN is the form which returns truth or falseness in shell terms. - TRUTH_OR is how to do logical or with TRUE and FALSE. - TRUTH_AND is how to do logical and with TRUE and FALSE.. - Default is TRUE = 1, FALSE = 0, TRUTH_OR = a | b, TRUTH_AND = a & b, - SHELL_BOOLEAN = (!value). */ + Default is TRUE = 1, FALSE = 0, SHELL_BOOLEAN = (!value). */ #define TRUE 1 #define FALSE 0 #define SHELL_BOOLEAN(value) (!(value)) -#define TRUTH_OR(a, b) ((a) | (b)) -#define TRUTH_AND(a, b) ((a) & (b)) #if defined (STANDALONE) # define test_exit(val) exit (val) #else - static jmp_buf test_exit_buf; - static int test_error_return = 0; +static procenv_t test_exit_buf; +static int test_error_return; # define test_exit(val) \ do { test_error_return = val; longjmp (test_exit_buf, 1); } while (0) #endif /* STANDALONE */ @@ -128,7 +145,7 @@ extern gid_t getgid (); non-AFS files. I hate AFS. */ # define EACCESS(path, mode) access(path, mode) #else -# define EACCESS(path, mode) eaccess(path, mode) +# define EACCESS(path, mode) test_eaccess(path, mode) #endif /* AFS */ static int pos; /* The offset of the current argument in ARGV. */ @@ -136,7 +153,9 @@ static int argc; /* The number of arguments present in ARGV. */ static char **argv; /* The argument list. */ static int noeval; +#if defined (STANDALONE) static int isint (); +#endif static int unop (); static int binop (); static int unary_operator (); @@ -150,6 +169,8 @@ static int term (); static int and (); static int or (); +static void beyond (); + static void test_syntax_error (format, arg) char *format, *arg; @@ -157,11 +178,12 @@ test_syntax_error (format, arg) #if !defined (STANDALONE) extern int interactive_shell; extern char *get_name_for_error (); - if (!interactive_shell) + if (interactive_shell == 0) fprintf (stderr, "%s: ", get_name_for_error ()); #endif fprintf (stderr, "%s: ", argv[0]); fprintf (stderr, format, arg); + fprintf (stderr, "\n"); fflush (stderr); test_exit (SHELL_BOOLEAN (FALSE)); } @@ -178,19 +200,28 @@ test_stat (path, finfo) errno = ENOENT; return (-1); } -#if !defined (HAVE_DEV_FD) if (path[0] == '/' && path[1] == 'd' && strncmp (path, "/dev/fd/", 8) == 0) { - int fd; +#if !defined (HAVE_DEV_FD) + long fd; if (isint (path + 8, &fd)) - return (fstat (fd, finfo)); + return (fstat ((int)fd, finfo)); else { errno = EBADF; return (-1); } - } +#else + /* If HAVE_DEV_FD is defined, DEV_FD_PREFIX is defined also, and has a + trailing slash. Make sure /dev/fd/xx really uses DEV_FD_PREFIX/xx. + On most systems, with the notable exception of linux, this is + effectively a no-op. */ + char pbuf[32]; + strcpy (pbuf, DEV_FD_PREFIX); + strcat (pbuf, path + 8); + return (stat (pbuf, finfo)); #endif /* !HAVE_DEV_FD */ + } return (stat (path, finfo)); } @@ -198,7 +229,7 @@ test_stat (path, finfo) and don't make the mistake of telling root that any file is executable. */ static int -eaccess (path, mode) +test_eaccess (path, mode) char *path; int mode; { @@ -209,11 +240,7 @@ eaccess (path, mode) return (-1); if (euid == -1) -#if defined (SHELL) - euid = current_user.euid; -#else euid = geteuid (); -#endif if (euid == 0) { @@ -240,68 +267,67 @@ eaccess (path, mode) #if defined (HAVE_GETGROUPS) /* The number of groups that this user is a member of. */ -static int ngroups = 0; -static GID_T *group_array = (GID_T *)NULL; -static int default_group_array_size = 0; +static int ngroups, maxgroups; +static GETGROUPS_T *group_array = (GETGROUPS_T *)NULL; #endif /* HAVE_GETGROUPS */ #if !defined (NOGROUP) -# define NOGROUP (GID_T) -1 +# define NOGROUP (gid_t) -1 #endif +#if defined (HAVE_GETGROUPS) + +# if defined (NGROUPS_MAX) +# define getmaxgroups() NGROUPS_MAX +# else /* !NGROUPS_MAX */ +# if defined (NGROUPS) +# define getmaxgroups() NGROUPS +# else /* !NGROUPS */ +# define getmaxgroups() 64 +# endif /* !NGROUPS */ +# endif /* !NGROUPS_MAX */ + +#endif /* HAVE_GETGROUPS */ + /* Return non-zero if GID is one that we have in our groups list. */ int group_member (gid) - GID_T gid; + gid_t gid; { - static GID_T pgid = (GID_T)NOGROUP; - static GID_T egid = (GID_T)NOGROUP; - - if (pgid == (GID_T)NOGROUP) -#if defined (SHELL) - pgid = (GID_T) current_user.gid; -#else /* !SHELL */ - pgid = (GID_T) getgid (); -#endif /* !SHELL */ - - if (egid == (GID_T)NOGROUP) -#if defined (SHELL) - egid = (GID_T) current_user.egid; -#else /* !SHELL */ - egid = (GID_T) getegid (); -#endif /* !SHELL */ + static gid_t pgid = (gid_t)NOGROUP; + static gid_t egid = (gid_t)NOGROUP; +#if defined (HAVE_GETGROUPS) + register int i; +#endif + + if (pgid == (gid_t)NOGROUP) + pgid = (gid_t) getgid (); + + if (egid == (gid_t)NOGROUP) + egid = (gid_t) getegid (); if (gid == pgid || gid == egid) return (1); #if defined (HAVE_GETGROUPS) /* getgroups () returns the number of elements that it was able to - place into the array. We simply continue to call getgroups () - until the number of elements placed into the array is smaller than - the physical size of the array. */ - - while (ngroups == default_group_array_size) + place into the array. */ + if (ngroups == 0) { - default_group_array_size += 64; - - group_array = (GID_T *) - xrealloc (group_array, default_group_array_size * sizeof (GID_T)); - - ngroups = getgroups (default_group_array_size, group_array); + if (maxgroups == 0) + maxgroups = getmaxgroups (); + group_array = (GETGROUPS_T *)xrealloc (group_array, maxgroups * sizeof (GETGROUPS_T)); + ngroups = getgroups (maxgroups, group_array); } /* In case of error, the user loses. */ - if (ngroups < 0) + if (ngroups <= 0) return (0); /* Search through the list looking for GID. */ - { - register int i; - - for (i = 0; i < ngroups; i++) - if (gid == group_array[i]) - return (1); - } + for (i = 0; i < ngroups; i++) + if (gid == (gid_t)group_array[i]) + return (1); #endif /* HAVE_GETGROUPS */ return (0); @@ -310,32 +336,17 @@ group_member (gid) /* Increment our position in the argument list. Check that we're not past the end of the argument list. This check is supressed if the argument is FALSE. Made a macro for efficiency. */ -#if !defined (lint) #define advance(f) do { ++pos; if (f && pos >= argc) beyond (); } while (0) -#endif - -#if !defined (advance) -static int -advance (f) - int f; -{ - ++pos; - - if (f && pos >= argc) - beyond (); -} -#endif /* advance */ - #define unary_advance() do { advance (1); ++pos; } while (0) /* * beyond - call when we're beyond the end of the argument list (an * error condition) */ -static int +static void beyond () { - test_syntax_error ("argument expected\n", (char *)NULL); + test_syntax_error ("argument expected", (char *)NULL); } /* Syntax error for when an integer argument was expected, but @@ -344,9 +355,10 @@ static void integer_expected_error (pch) char *pch; { - test_syntax_error ("integer expression expected %s\n", pch); + test_syntax_error ("%s: integer expression expected", pch); } +#if defined (STANDALONE) /* Return non-zero if the characters pointed to by STRING constitute a valid number. Stuff the converted number into RESULT if RESULT is a non-null pointer to a long. */ @@ -406,41 +418,23 @@ isint (string, result) return (1); } - -/* Find the modification time of FILE, and stuff it into AGE, a pointer - to a long. Return non-zero if successful, else zero. */ -static int -age_of (filename, age) - char *filename; - long *age; -{ - struct stat finfo; - - if (test_stat (filename, &finfo) < 0) - return (0); - - if (age) - *age = finfo.st_mtime; - - return (1); -} +#endif /* STANDALONE */ /* * term - parse a term and return 1 or 0 depending on whether the term * evaluates to true or false, respectively. * * term ::= - * '-'('h'|'d'|'f'|'r'|'s'|'w'|'c'|'b'|'p'|'u'|'g'|'k') filename - * '-'('L'|'x') filename - * '-t' [ int ] + * '-'('a'|'b'|'c'|'d'|'e'|'f'|'g'|'h'|'p'|'r'|'s'|'u'|'w'|'x') filename + * '-'('G'|'L'|'O'|'S') filename + * '-t' [int] * '-'('z'|'n') string * string - * string ('!='|'=') string + * string ('!='|'='|'==') string * '-'(eq|ne|le|lt|ge|gt) * file '-'(nt|ot|ef) file * '(' ')' * int ::= - * '-l' string * positive and negative integers */ static int @@ -451,48 +445,47 @@ term () if (pos >= argc) beyond (); - /* Deal with leading "not"'s. */ - if ('!' == argv[pos][0] && '\000' == argv[pos][1]) + /* Deal with leading `not's. */ + if (argv[pos][0] == '!' && argv[pos][1] == '\0') { - value = FALSE; - while (pos < argc && '!' == argv[pos][0] && '\000' == argv[pos][1]) + value = 0; + while (pos < argc && argv[pos][0] == '!' && argv[pos][1] == '\0') { advance (1); - value ^= (TRUE); + value = 1 - value; } - return (value ^ (term ())); + return (value ? !term() : term()); } - /* A paren-bracketed argument. */ - if (argv[pos][0] == '(' && !argv[pos][1]) + /* A paren-bracketed argument. */ + if (argv[pos][0] == '(' && argv[pos][1] == '\0') { advance (1); value = expr (); if (argv[pos] == 0) - test_syntax_error ("`)' expected\n"); + test_syntax_error ("`)' expected", (char *)NULL); else if (argv[pos][0] != ')' || argv[pos][1]) - test_syntax_error ("`)' expected, found %s\n", argv[pos]); + test_syntax_error ("`)' expected, found %s", argv[pos]); advance (0); - return (TRUE == (value)); + return (value); } /* are there enough arguments left that this could be dyadic? */ - if (((pos + 3 <= argc) && binop (argv[pos + 1])) || - ((pos + 4 <= argc && STREQ (argv[pos], "-l") && binop (argv[pos + 2])))) + if ((pos + 3 <= argc) && binop (argv[pos + 1])) value = binary_operator (); /* Might be a switch type argument */ - else if ('-' == argv[pos][0] && 0 == argv[pos][2]) + else if (argv[pos][0] == '-' && argv[pos][2] == '\0') { if (unop (argv[pos][1])) value = unary_operator (); else - test_syntax_error ("%s: unary operator expected\n", argv[pos]); + test_syntax_error ("%s: unary operator expected", argv[pos]); } else { - value = (argv[pos][0] != '\0'); + value = argv[pos][0] != '\0'; advance (0); } @@ -500,248 +493,147 @@ term () } static int -binary_operator () +filecomp (s, t, op) + char *s, *t; + int op; { - register int op; - struct stat stat_buf, stat_spare; - long int l, r, value; - /* Are the left and right integer expressions of the form '-l string'? */ - int l_is_l, r_is_l; + struct stat st1, st2; - if (argv[pos][0] == '-' && argv[pos][1] == 'l' && !argv[pos][2]) + if (test_stat (s, &st1) < 0 || test_stat (t, &st2) < 0) + return (FALSE); + switch (op) { - l_is_l = 1; - op = pos + 2; + case OT: return (st1.st_mtime < st2.st_mtime); + case NT: return (st1.st_mtime > st2.st_mtime); + case EF: return ((st1.st_dev == st2.st_dev) && (st1.st_ino == st2.st_ino)); + } + return (FALSE); +} - /* Make sure that OP is still a valid binary operator. */ - if ((op >= argc - 1) || (binop (argv[op]) == 0)) - test_syntax_error ("%s: binary operator expected\n", argv[op]); +static int +arithcomp (s, t, op) + char *s, *t; + int op; +{ + long l, r; - advance (0); + if (isint (s, &l) == 0) + integer_expected_error (s); + if (isint (t, &r) == 0) + integer_expected_error (t); + switch (op) + { + case EQ: return (l == r); + case NE: return (l != r); + case LT: return (l < r); + case GT: return (l > r); + case LE: return (l <= r); + case GE: return (l >= r); } - else + return (FALSE); +} + +#if defined (PATTERN_MATCHING) +static int +patcomp (string, pat, op) + char *string, *pat; + int op; +{ + int m; + + m = fnmatch (pat, string, 0); + switch (op) { - l_is_l = 0; - op = pos + 1; + case EQ: return (m == 0); + case NE: return (m != 0); } +} +#endif /* PATTERN_MATCHING */ - if ((op < argc - 2) && - (argv[op + 1][0] == '-' && argv[op + 1][1] == 'l' && !argv[op + 1][2])) +static int +binary_operator () +{ + int value; + char *w; + + w = argv[pos + 1]; + if (w[0] == '=' && (w[1] == '\0' || (w[1] == '=' && w[2] == '\0'))) { - r_is_l = 1; - advance (0); + value = STREQ (argv[pos], argv[pos + 2]); + pos += 3; + return (value); + } + if ((w[0] == '>' || w[0] == '<') && w[1] == '\0') + { + value = (w[0] == '>') ? strcmp (argv[pos], argv[pos + 2]) > 0 + : strcmp (argv[pos], argv[pos + 2]) < 0; + pos += 3; + return (value); + } +#if defined (PATTERN_MATCHING) + if ((w[0] == '=' || w[0] == '!') && w[1] == '~' && w[2] == '\0') + { + value = patcomp (argv[pos], argv[pos + 2], w[0] == '=' ? EQ : NE); + pos += 3; + return (value); + } +#endif + if (w[0] == '!' && w[1] == '=' && w[2] == '\0') + { + value = STREQ (argv[pos], argv[pos + 2]) == 0; + pos += 3; + return (value); + } + + if (w[0] != '-' || w[3] != '\0') + { + test_syntax_error ("%s: binary operator expected", w); + /* NOTREACHED */ + return (FALSE); } - else - r_is_l = 0; - if (argv[op][0] == '-') + w++; + if (w[1] == 't') { - /* check for eq, nt, and stuff */ - switch (argv[op][1]) + switch (w[0]) { - default: - break; - - case 'l': - if (argv[op][2] == 't' && !argv[op][3]) - { - /* lt */ - if (l_is_l) - l = strlen (argv[op - 1]); - else - { - if (!isint (argv[op - 1], &l)) - integer_expected_error ("before -lt"); - } - - if (r_is_l) - r = strlen (argv[op + 2]); - else - { - if (!isint (argv[op + 1], &r)) - integer_expected_error ("after -lt"); - } - pos += 3; - return (TRUE == (l < r)); - } - - if (argv[op][2] == 'e' && !argv[op][3]) - { - /* le */ - if (l_is_l) - l = strlen (argv[op - 1]); - else - { - if (!isint (argv[op - 1], &l)) - integer_expected_error ("before -le"); - } - if (r_is_l) - r = strlen (argv[op + 2]); - else - { - if (!isint (argv[op + 1], &r)) - integer_expected_error ("after -le"); - } - pos += 3; - return (TRUE == (l <= r)); - } - break; - - case 'g': - if (argv[op][2] == 't' && !argv[op][3]) - { - /* gt integer greater than */ - if (l_is_l) - l = strlen (argv[op - 1]); - else - { - if (!isint (argv[op - 1], &l)) - integer_expected_error ("before -gt"); - } - if (r_is_l) - r = strlen (argv[op + 2]); - else - { - if (!isint (argv[op + 1], &r)) - integer_expected_error ("after -gt"); - } - pos += 3; - return (TRUE == (l > r)); - } - - if (argv[op][2] == 'e' && !argv[op][3]) - { - /* ge - integer greater than or equal to */ - if (l_is_l) - l = strlen (argv[op - 1]); - else - { - if (!isint (argv[op - 1], &l)) - integer_expected_error ("before -ge"); - } - if (r_is_l) - r = strlen (argv[op + 2]); - else - { - if (!isint (argv[op + 1], &r)) - integer_expected_error ("after -ge"); - } - pos += 3; - return (TRUE == (l >= r)); - } - break; - - case 'n': - if (argv[op][2] == 't' && !argv[op][3]) - { - /* nt - newer than */ - pos += 3; - if (l_is_l || r_is_l) - test_syntax_error ("-nt does not accept -l\n", (char *)NULL); - if (age_of (argv[op - 1], &l) && age_of (argv[op + 1], &r)) - return (TRUE == (l > r)); - else - return (FALSE); - } - - if (argv[op][2] == 'e' && !argv[op][3]) - { - /* ne - integer not equal */ - if (l_is_l) - l = strlen (argv[op - 1]); - else - { - if (!isint (argv[op - 1], &l)) - integer_expected_error ("before -ne"); - } - if (r_is_l) - r = strlen (argv[op + 2]); - else - { - if (!isint (argv[op + 1], &r)) - integer_expected_error ("after -ne"); - } - pos += 3; - return (TRUE == (l != r)); - } - break; - - case 'e': - if (argv[op][2] == 'q' && !argv[op][3]) - { - /* eq - integer equal */ - if (l_is_l) - l = strlen (argv[op - 1]); - else - { - if (!isint (argv[op - 1], &l)) - integer_expected_error ("before -eq"); - } - if (r_is_l) - r = strlen (argv[op + 2]); - else - { - if (!isint (argv[op + 1], &r)) - integer_expected_error ("after -eq"); - } - pos += 3; - return (TRUE == (l == r)); - } - - if (argv[op][2] == 'f' && !argv[op][3]) - { - /* ef - hard link? */ - pos += 3; - if (l_is_l || r_is_l) - test_syntax_error ("-ef does not accept -l\n", (char *)NULL); - if (test_stat (argv[op - 1], &stat_buf) < 0) - return (FALSE); - if (test_stat (argv[op + 1], &stat_spare) < 0) - return (FALSE); - return (TRUE == - (stat_buf.st_dev == stat_spare.st_dev && - stat_buf.st_ino == stat_spare.st_ino)); - } - break; - - case 'o': - if ('t' == argv[op][2] && '\000' == argv[op][3]) - { - /* ot - older than */ - pos += 3; - if (l_is_l || r_is_l) - test_syntax_error ("-nt does not accept -l\n", (char *)NULL); - if (age_of (argv[op - 1], &l) && age_of (argv[op + 1], &r)) - return (TRUE == (l < r)); - return (FALSE); - } - break; + case 'n': value = filecomp (argv[pos], argv[pos + 2], NT); break; + case 'o': value = filecomp (argv[pos], argv[pos + 2], OT); break; + case 'l': value = arithcomp (argv[pos], argv[pos + 2], LT); break; + case 'g': value = arithcomp (argv[pos], argv[pos + 2], GT); break; + default: test_syntax_error ("-%s: binary operator expected", w); } - test_syntax_error ("%s: unknown binary operator", argv[op]); } - - if (argv[op][0] == '=' && !argv[op][1]) + else if (w[0] == 'e') { - value = (argv[pos][0] == argv[pos+2][0]) && - (strcmp (argv[pos], argv[pos + 2]) == 0); - pos += 3; - return (TRUE == value); + switch (w[1]) + { + case 'q': value = arithcomp (argv[pos], argv[pos + 2], EQ); break; + case 'f': value = filecomp (argv[pos], argv[pos + 2], EF); break; + default: test_syntax_error ("-%s: binary operator expected", w); + } } - - if (argv[op][0] == '!' && argv[op][1] == '=' && !argv[op][2]) + else if (w[1] == 'e') { - value = (argv[pos][0] != argv[pos + 2][0]) || - (strcmp (argv[pos], argv[pos + 2]) != 0); - pos += 3; - return (TRUE == value); + switch (w[0]) + { + case 'n': value = arithcomp (argv[pos], argv[pos + 2], NE); break; + case 'g': value = arithcomp (argv[pos], argv[pos + 2], GE); break; + case 'l': value = arithcomp (argv[pos], argv[pos + 2], LE); break; + default: test_syntax_error ("-%s: binary operator expected", w); + } } - return (FALSE); + else + test_syntax_error ("-%s: binary operator expected", w); + + pos += 3; + return value; } static int unary_operator () { - long r, value; + long r; struct stat stat_buf; switch (argv[pos][1]) @@ -757,166 +649,136 @@ unary_operator () case 'a': /* file exists in the file system? */ case 'e': unary_advance (); - value = -1 != test_stat (argv[pos - 1], &stat_buf); - return (TRUE == value); + return (test_stat (argv[pos - 1], &stat_buf) == 0); case 'r': /* file is readable? */ unary_advance (); - value = -1 != EACCESS (argv[pos - 1], R_OK); - return (TRUE == value); + return (EACCESS (argv[pos - 1], R_OK) == 0); case 'w': /* File is writeable? */ unary_advance (); - value = -1 != EACCESS (argv[pos - 1], W_OK); - return (TRUE == value); + return (EACCESS (argv[pos - 1], W_OK) == 0); case 'x': /* File is executable? */ unary_advance (); - value = -1 != EACCESS (argv[pos - 1], X_OK); - return (TRUE == value); + return (EACCESS (argv[pos - 1], X_OK) == 0); case 'O': /* File is owned by you? */ unary_advance (); - if (test_stat (argv[pos - 1], &stat_buf) < 0) - return (FALSE); - -#if defined (SHELL) - return (TRUE == ((UID_T) current_user.euid == (UID_T) stat_buf.st_uid)); -#else - return (TRUE == ((UID_T) geteuid () == (UID_T) stat_buf.st_uid)); -#endif /* !SHEL */ + return (test_stat (argv[pos - 1], &stat_buf) == 0 && + (uid_t) geteuid () == (uid_t) stat_buf.st_uid); case 'G': /* File is owned by your group? */ unary_advance (); - if (test_stat (argv[pos - 1], &stat_buf) < 0) - return (FALSE); - - return (TRUE == ((GID_T) getegid () == (GID_T) stat_buf.st_gid)); + return (test_stat (argv[pos - 1], &stat_buf) == 0 && + (gid_t) getegid () == (gid_t) stat_buf.st_gid); case 'f': /* File is a file? */ unary_advance (); if (test_stat (argv[pos - 1], &stat_buf) < 0) return (FALSE); - /* Under POSIX, -f is true if the given file exists - and is a regular file. */ + /* -f is true if the given file exists and is a regular file. */ #if defined (S_IFMT) - return (TRUE == ((S_ISREG (stat_buf.st_mode)) || - (0 == (stat_buf.st_mode & S_IFMT)))); + return (S_ISREG (stat_buf.st_mode) || (stat_buf.st_mode & S_IFMT) == 0); #else - return (TRUE == (S_ISREG (stat_buf.st_mode))); + return (S_ISREG (stat_buf.st_mode)); #endif /* !S_IFMT */ case 'd': /* File is a directory? */ unary_advance (); - if (test_stat (argv[pos - 1], &stat_buf) < 0) - return (FALSE); - - return (TRUE == (S_ISDIR (stat_buf.st_mode))); + return (test_stat (argv[pos - 1], &stat_buf) == 0 && + (S_ISDIR (stat_buf.st_mode))); case 's': /* File has something in it? */ unary_advance (); - if (test_stat (argv[pos - 1], &stat_buf) < 0) - return (FALSE); - - return (TRUE == (stat_buf.st_size > (off_t) 0)); + return (test_stat (argv[pos - 1], &stat_buf) == 0 && + stat_buf.st_size > (off_t) 0); case 'S': /* File is a socket? */ #if !defined (S_ISSOCK) return (FALSE); #else unary_advance (); - - if (test_stat (argv[pos - 1], &stat_buf) < 0) - return (FALSE); - - return (TRUE == (S_ISSOCK (stat_buf.st_mode))); -#endif /* S_ISSOCK */ + return (test_stat (argv[pos - 1], &stat_buf) == 0 && + S_ISSOCK (stat_buf.st_mode)); +#endif /* S_ISSOCK */ case 'c': /* File is character special? */ unary_advance (); - if (test_stat (argv[pos - 1], &stat_buf) < 0) - return (FALSE); - - return (TRUE == (S_ISCHR (stat_buf.st_mode))); + return (test_stat (argv[pos - 1], &stat_buf) == 0 && + S_ISCHR (stat_buf.st_mode)); case 'b': /* File is block special? */ unary_advance (); - if (test_stat (argv[pos - 1], &stat_buf) < 0) - return (FALSE); - - return (TRUE == (S_ISBLK (stat_buf.st_mode))); + return (test_stat (argv[pos - 1], &stat_buf) == 0 && + S_ISBLK (stat_buf.st_mode)); case 'p': /* File is a named pipe? */ unary_advance (); #ifndef S_ISFIFO return (FALSE); #else - if (test_stat (argv[pos - 1], &stat_buf) < 0) - return (FALSE); - return (TRUE == (S_ISFIFO (stat_buf.st_mode))); -#endif /* S_ISFIFO */ + return (test_stat (argv[pos - 1], &stat_buf) == 0 && + S_ISFIFO (stat_buf.st_mode)); +#endif /* S_ISFIFO */ case 'L': /* Same as -h */ - /*FALLTHROUGH*/ - case 'h': /* File is a symbolic link? */ unary_advance (); -#ifndef S_ISLNK +#if !defined (S_ISLNK) || !defined (HAVE_LSTAT) return (FALSE); #else - /* An empty filename is not a valid pathname. */ - if ((argv[pos - 1][0] == '\0') || - (lstat (argv[pos - 1], &stat_buf) < 0)) - return (FALSE); - - return (TRUE == (S_ISLNK (stat_buf.st_mode))); -#endif /* S_IFLNK */ + return ((argv[pos - 1][0] != '\0') && + (lstat (argv[pos - 1], &stat_buf) == 0) && + S_ISLNK (stat_buf.st_mode)); +#endif /* S_IFLNK && HAVE_LSTAT */ case 'u': /* File is setuid? */ unary_advance (); - if (test_stat (argv[pos - 1], &stat_buf) < 0) - return (FALSE); - - return (TRUE == (0 != (stat_buf.st_mode & S_ISUID))); + return (test_stat (argv[pos - 1], &stat_buf) == 0 && + (stat_buf.st_mode & S_ISUID) != 0); case 'g': /* File is setgid? */ unary_advance (); - if (test_stat (argv[pos - 1], &stat_buf) < 0) - return (FALSE); - - return (TRUE == (0 != (stat_buf.st_mode & S_ISGID))); + return (test_stat (argv[pos - 1], &stat_buf) == 0 && + (stat_buf.st_mode & S_ISGID) != 0); case 'k': /* File has sticky bit set? */ unary_advance (); - if (test_stat (argv[pos - 1], &stat_buf) < 0) - return (FALSE); #if !defined (S_ISVTX) /* This is not Posix, and is not defined on some Posix systems. */ return (FALSE); #else - return (TRUE == (0 != (stat_buf.st_mode & S_ISVTX))); + return (test_stat (argv[pos - 1], &stat_buf) == 0 && + (stat_buf.st_mode & S_ISVTX) != 0); #endif - case 't': /* File (fd) is a terminal? (fd) defaults to stdout. */ + case 't': /* File fd is a terminal? fd defaults to stdout. */ advance (0); if (pos < argc && isint (argv[pos], &r)) { advance (0); - return (TRUE == (isatty ((int) r))); + return (isatty ((int)r)); } - return (TRUE == (isatty (1))); + return (isatty (1)); case 'n': /* True if arg has some length. */ unary_advance (); - return (TRUE == (argv[pos - 1][0] != 0)); + return (argv[pos - 1][0] != '\0'); case 'z': /* True if arg has no length. */ unary_advance (); - return (TRUE == (argv[pos - 1][0] == '\0')); + return (argv[pos - 1][0] == '\0'); + +#if !defined (STANDALONE) + case 'o': + unary_advance (); + return (minus_o_option_value (argv[pos - 1]) == 1); +#endif /* !STANDALONE */ } } - + /* * and: * term @@ -925,15 +787,16 @@ unary_operator () static int and () { - int value; + int value, v2; value = term (); while (pos < argc && argv[pos][0] == '-' && argv[pos][1] == 'a' && !argv[pos][2]) { advance (0); - value = TRUTH_AND (value, and ()); + v2 = and (); + return (value && v2); } - return (TRUE == value); + return (value); } /* @@ -944,17 +807,17 @@ and () static int or () { - int value; + int value, v2; value = and (); - while (pos < argc && argv[pos][0] == '-' && argv[pos][1] == 'o' && !argv[pos][2]) { advance (0); - value = TRUTH_OR (value, or ()); + v2 = or (); + return (value || v2); } - return (TRUE == value); + return (value); } /* @@ -967,7 +830,7 @@ expr () if (pos >= argc) beyond (); - return (FALSE ^ (or ())); /* Same with this. */ + return (FALSE ^ or ()); /* Same with this. */ } /* Return TRUE if S is one of the test command's binary operators. */ @@ -975,10 +838,56 @@ static int binop (s) char *s; { - return ((STREQ (s, "=")) || (STREQ (s, "!=")) || (STREQ (s, "-nt")) || - (STREQ (s, "-ot")) || (STREQ (s, "-ef")) || (STREQ (s, "-eq")) || - (STREQ (s, "-ne")) || (STREQ (s, "-lt")) || (STREQ (s, "-le")) || - (STREQ (s, "-gt")) || (STREQ (s, "-ge"))); + char *t; + + if (s[0] == '=' && s[1] == '\0') + return (1); /* '=' */ + else if (s[1] == '\0' && (s[0] == '<' || s[0] == '>')) /* string <, > */ + return (1); + else if (s[2] == '\0' && s[1] == '=' && (s[0] == '=' || s[0] == '!')) + return (1); /* `==' and `!=' */ +#if defined (PATTERN_MATCHING) + else if (s[2] == '\0' && s[1] == '~' && (s[0] == '=' || s[0] == '!')) + return (1); +#endif + else if (s[0] != '-' || s[2] == '\0' || s[3] != '\0') + return (0); + else + { + t = s + 1; + if (t[1] == 't') + switch (t[0]) + { + case 'n': /* -nt */ + case 'o': /* -ot */ + case 'l': /* -lt */ + case 'g': /* -gt */ + return (1); + default: + return (0); + } + else if (t[0] == 'e') + switch (t[1]) + { + case 'q': /* -eq */ + case 'f': /* -ef */ + return (1); + default: + return (0); + } + else if (t[1] == 'e') + switch (t[0]) + { + case 'n': /* -ne */ + case 'l': /* -le */ + case 'g': /* -ge */ + return (1); + default: + return (0); + } + else + return (0); + } } /* Return non-zero if OP is one of the test command's unary operators. */ @@ -986,51 +895,74 @@ static int unop (op) int op; { - return (member (op, "abcdefgkLhprsStuwxOGnz")); + switch (op) + { + case 'a': case 'b': case 'c': case 'd': case 'e': + case 'f': case 'g': case 'h': case 'k': case 'n': + case 'p': case 'r': case 's': case 't': case 'u': + case 'w': case 'x': case 'z': + case 'G': case 'L': case 'O': case 'S': +#if !defined (STANDALONE) + case 'o': +#endif + return (1); + } + return (0); } static int two_arguments () { - int value; - - if (argv[pos][0] == '!' && !argv[pos][1]) - value = argv[pos + 1][0] == '\0'; - else if ((argv[pos][0] == '-') && (argv[pos][2] == '\0')) + if (argv[pos][0] == '!' && argv[pos][1] == '\0') + return (argv[pos + 1][0] == '\0'); + else if (argv[pos][0] == '-' && argv[pos][2] == '\0') { if (unop (argv[pos][1])) - value = unary_operator (); + return (unary_operator ()); else - test_syntax_error ("%s: unary operator expected\n", argv[pos]); + test_syntax_error ("%s: unary operator expected", argv[pos]); } else - test_syntax_error ("%s: unary operator expected\n", argv[pos]); + test_syntax_error ("%s: unary operator expected", argv[pos]); - return (value); + return (0); } +#define ANDOR(s) (s[0] == '-' && !s[2] && (s[1] == 'a' || s[1] == 'o')) + +#define ONE_ARG_TEST(s) ((s)[0] != '\0') + static int three_arguments () { int value; - if (argv[pos][0] == '!' && !argv[pos][1]) + if (binop (argv[pos+1])) + { + value = binary_operator (); + pos = argc; + } + else if (ANDOR (argv[pos+1])) + { + if (argv[pos+1][1] == 'a') + value = ONE_ARG_TEST(argv[pos]) && ONE_ARG_TEST(argv[pos+2]); + else + value = ONE_ARG_TEST(argv[pos]) || ONE_ARG_TEST(argv[pos+2]); + pos = argc; + } + else if (argv[pos][0] == '!' && !argv[pos][1]) { advance (1); value = !two_arguments (); } - else if (binop (argv[pos+1])) + else if (argv[pos][0] == '(' && argv[pos+2][0] == ')') { - value = binary_operator (); + value = ONE_ARG_TEST(argv[pos+1]); pos = argc; } - /* Check for -a or -o or a parenthesized subexpression. */ - else if ((argv[pos+1][0] == '-' && !argv[pos+1][2] && - (argv[pos+1][1] == 'a' || argv[pos+1][1] == 'o')) || - (argv[pos][0] == '(')) - value = expr (); else - test_syntax_error ("%s: binary operator expected\n", argv[pos+1]); + test_syntax_error ("%s: binary operator expected", argv[pos+1]); + return (value); } @@ -1048,7 +980,7 @@ posixtest () break; case 1: - value = argv[1][0] != '\0'; + value = ONE_ARG_TEST(argv[1]); pos = argc; break; @@ -1062,14 +994,13 @@ posixtest () break; case 4: - if (STREQ (argv[pos], "!")) + if (argv[pos][0] == '!' && argv[pos][1] == '\0') { advance (1); value = !three_arguments (); break; } /* FALLTHROUGH */ - case 5: default: value = expr (); } @@ -1084,11 +1015,7 @@ posixtest () * test expr */ int -#if defined (STANDALONE) main (margc, margv) -#else -test_command (margc, margv) -#endif /* STANDALONE */ int margc; char **margv; { @@ -1101,11 +1028,11 @@ test_command (margc, margv) if (code) return (test_error_return); -#endif /* STANDALONE */ +#endif /* !STANDALONE */ argv = margv; - if (margv[0] && margv[0][0] == '[' && !margv[0][1]) + if (margv[0] && margv[0][0] == '[' && margv[0][1] == '\0') { --margc; @@ -1113,7 +1040,7 @@ test_command (margc, margv) test_exit (SHELL_BOOLEAN (FALSE)); if (margv[margc] && (margv[margc][0] != ']' || margv[margc][1])) - test_syntax_error ("missing `]'\n", (char *)NULL); + test_syntax_error ("missing `]'", (char *)NULL); } argc = margc; @@ -1126,7 +1053,7 @@ test_command (margc, margv) value = posixtest (); if (pos != argc) - test_syntax_error ("too many arguments\n", (char *)NULL); + test_syntax_error ("too many arguments", (char *)NULL); test_exit (SHELL_BOOLEAN (value)); } diff --git a/tests/arith.right b/tests/arith.right new file mode 100644 index 0000000..a369bd8 --- /dev/null +++ b/tests/arith.right @@ -0,0 +1,91 @@ +163 +166 +4 +16 +8 +2 +4 +2 +2 +1 +0 +0 +0 +1 +1 +2 +-3 +-2 +1 +0 +2 +131072 +29 +33 +49 +1 +1 +0 +0 +1 +1 +1 +2 +3 +1 +58 +2 +60 +1 +256 +16 +62 +4 +29 +5 +-4 +4 +1 +32 +32 +1 +1 +32 +20 +1,i+=2 +30 +1,j+=2 +20 +1,i+=2 +30 +1,j+=2 +./arith.tests: 1 ? 20 : x+=2: attempted assignment to non-variable (error token is "+=2") +20 +6 +6,5,3 +263 +255 +255 +127 +36 +40 +10 +10 +10 +10 +10 +10 +36 +36 +62 +63 +./arith.tests: 3425#56: illegal arithmetic base (error token is "3425#56") +0 +./arith.tests: 7 = 43 : attempted assignment to non-variable (error token is "= 43 ") +./arith.tests: 2#44: value too great for base (error token is "2#44") +./arith.tests: 44 / 0 : division by 0 (error token is " ") +./arith.tests: let: jv += $iv: syntax error: operand expected (error token is "$iv") +./arith.tests: jv += $iv : syntax error: operand expected (error token is "$iv ") +./arith.tests: let: rv = 7 + (43 * 6: missing `)' (error token is "6") +./arith.tests: 0#4: bad number (error token is "0#4") +./arith.tests: 2#110#11: bad number (error token is "2#110#11") diff --git a/tests/arith.tests b/tests/arith.tests new file mode 100644 index 0000000..6bad312 --- /dev/null +++ b/tests/arith.tests @@ -0,0 +1,158 @@ +declare -i iv jv + +iv=$(( 3 + 5 * 32 )) +echo $iv +iv=iv+3 +echo $iv +iv=2 +jv=iv + +let "jv *= 2" +echo $jv +jv=$(( $jv << 2 )) +echo $jv + +let jv="$jv / 2" +echo $jv +jv="jv >> 2" +echo $jv + +iv=$((iv+ $jv)) +echo $iv +echo $((iv -= jv)) +echo $iv +echo $(( iv == jv )) +echo $(( iv != $jv )) +echo $(( iv < jv )) +echo $(( $iv > $jv )) +echo $(( iv <= $jv )) +echo $(( $iv >= jv )) + +echo $jv +echo $(( ~$jv )) +echo $(( ~1 )) +echo $(( ! 0 )) + +echo $(( jv % 2 )) +echo $(( $iv % 4 )) + +echo $(( iv <<= 16 )) +echo $(( iv %= 33 )) + +echo $(( 33 & 55 )) +echo $(( 33 | 17 )) + +echo $(( iv && $jv )) +echo $(( $iv || jv )) + +echo $(( iv && 0 )) +echo $(( iv & 0 )) +echo $(( iv && 1 )) +echo $(( iv & 1 )) + +echo $(( $jv || 0 )) +echo $(( jv | 0 )) +echo $(( jv | 1 )) +echo $(( $jv || 1 )) + +let 'iv *= jv' +echo $iv +echo $jv +let "jv += $iv" +echo $jv + +echo $(( jv /= iv )) +echo $(( jv <<= 8 )) +echo $(( jv >>= 4 )) + +echo $(( iv |= 4 )) +echo $(( iv &= 4 )) + +echo $(( iv += (jv + 9))) +echo $(( (iv + 4) % 7 )) + +# unary plus, minus +echo $(( +4 - 8 )) +echo $(( -4 + 8 )) + +# conditional expressions +echo $(( 4<5 ? 1 : 32)) +echo $(( 4>5 ? 1 : 32)) +echo $(( 4>(2+3) ? 1 : 32)) +echo $(( 4<(2+3) ? 1 : 32)) +echo $(( (2+2)<(2+3) ? 1 : 32)) +echo $(( (2+2)>(2+3) ? 1 : 32)) + +# check that the unevaluated part of the ternary operator does not do +# evaluation or assignment +x=i+=2 +y=j+=2 +declare -i i=1 j=1 +echo $((1 ? 20 : (x+=2))) +echo $i,$x +echo $((0 ? (y+=2) : 30)) +echo $j,$y + +x=i+=2 +y=j+=2 +declare -i i=1 j=1 +echo $((1 ? 20 : (x+=2))) +echo $i,$x +echo $((0 ? (y+=2) : 30)) +echo $i,$y + +# check precedence of assignment vs. conditional operator +# should be an error +declare -i x=2 +y=$((1 ? 20 : x+=2)) + +# check precedence of assignment vs. conditional operator +declare -i x=2 +echo $((0 ? x+=2 : 20)) + +# associativity of assignment-operator operator +declare -i i=1 j=2 k=3 +echo $((i += j += k)) +echo $i,$j,$k + +# octal, hex +echo $(( 0x100 | 007 )) +echo $(( 0xff )) +echo $(( 16#ff )) +echo $(( 16#FF/2 )) +echo $(( 8#44 )) + +echo $(( 8 ^ 32 )) + +# other bases +echo $(( 16#a )) +echo $(( 32#a )) +echo $(( 56#a )) +echo $(( 64#a )) + +echo $(( 16#A )) +echo $(( 32#A )) +echo $(( 56#A )) +echo $(( 64#A )) + +echo $(( 64#_ )) +echo $(( 64#@ )) + +# weird bases +echo $(( 3425#56 )) + +# missing number after base +echo $(( 2# )) + +# these should generate errors +echo $(( 7 = 43 )) +echo $(( 2#44 )) +echo $(( 44 / 0 )) +let 'jv += $iv' +echo $(( jv += \$iv )) +let 'rv = 7 + (43 * 6' + +# more errors +declare -i i +i=0#4 +i=2#110#11 diff --git a/tests/array.right b/tests/array.right new file mode 100644 index 0000000..d4a3398 --- /dev/null +++ b/tests/array.right @@ -0,0 +1,78 @@ +abcde +abcde bdef +abcde bdef +declare -a DIRSTACK='()' +declare -a a='([0]="abcde" [1]="" [2]="bdef")' +declare -a b='()' +declare -ar c='()' +abcde bdef +abcde bdef +abcde +abcde +abcde + +bdef +hello world +11 +3 +bdef hello world test expression +./array.tests: readonly: `a[5]': not a valid identifier +declare -ar a='([1]="" [2]="bdef" [5]="hello world" [6]="test expression")' +declare -ar c='()' +declare -ar a='([1]="" [2]="bdef" [5]="hello world" [6]="test expression")' +declare -ar c='()' +./array.tests: declare: e: cannot assign to array variables in this way +a test +declare -a DIRSTACK='()' +declare -ar a='([1]="" [2]="bdef" [5]="hello world" [6]="test expression")' +declare -a b='([0]="this" [1]="is" [2]="a" [3]="test" [4]="" [5]="/etc/passwd")' +declare -ar c='()' +declare -a d='([1]="" [2]="bdef" [5]="hello world" [6]="test" [9]="ninth element")' +declare -a e='([0]="test")' +declare -a f='([0]="" [1]="bdef" [2]="hello world" [3]="test" [4]="ninth element")' +./array.tests: a: readonly variable +./array.tests: b[]: bad array subscript +./array.tests: b[*]: bad array subscript +./array.tests: ${b[ ]}: bad substitution +./array.tests: c[-2]: bad array subscript +./array.tests: c: bad array subscript + +./array.tests: d[7]: cannot assign list to array member +./array.tests: []=abcde: bad array subscript +./array.tests: [*]=last: cannot assign to non-numeric index +./array.tests: [-65]=negative: bad array subscript +declare -a DIRSTACK='()' +declare -ar a='([1]="" [2]="bdef" [5]="hello world" [6]="test expression")' +declare -a b='([0]="this" [1]="is" [2]="a" [3]="test" [4]="" [5]="/etc/passwd")' +declare -ar c='()' +declare -a d='([1]="test test" [2]="bdef" [5]="hello world" [6]="test" [9]="ninth element")' +declare -a f='([0]="" [1]="bdef" [2]="hello world" [3]="test" [4]="ninth element")' +./array.tests: unset: ps1: not an array variable +./array.tests: declare: c: cannot destroy array variables in this way +this of +this is a test of read using arrays +declare -a DIRSTACK='()' +declare -a rv='([0]="this" [1]="is" [2]="a" [3]="test" [4]="of" [5]="read" [6]="using" [7]="arrays")' +declare -ar a='([1]="" [2]="bdef" [5]="hello world" [6]="test expression")' +declare -a b='([0]="this" [1]="is" [2]="a" [3]="test" [4]="" [5]="/etc/passwd")' +declare -ar c='()' +declare -a d='([1]="test test" [2]="bdef" [5]="hello world" [6]="test" [9]="ninth element")' +declare -a f='([0]="" [1]="bdef" [2]="hello world" [3]="test" [4]="ninth element")' +abde +abde +bbb +efgh +wxyz +wxyz +./array.tests +a +b c +d +e f g +h +./array.tests +a +b c +d +e f g +h diff --git a/tests/array.tests b/tests/array.tests new file mode 100644 index 0000000..2ee376b --- /dev/null +++ b/tests/array.tests @@ -0,0 +1,131 @@ +set +a +# The calls to egrep -v are to filter out builtin array variables that are +# automatically set and possibly contain values that vary. +unset a +a=abcde +a[2]=bdef + +declare -a b[256] + +unset c[2] +unset c[*] + +a[1]= + +_ENV=/bin/true +x=${_ENV[(_$-=0)+(_=1)-_${-%%*i*}]} + +declare -r c[100] + +echo ${a[0]} ${a[4]} +echo ${a[@]} + +echo ${a[*]} + +# this should print out values, too +declare -a | egrep -v '(BASH_VERSINFO|PIPESTATUS)' + +unset a[7] +echo ${a[*]} + +unset a[4] +echo ${a[*]} + +echo ${a} +echo "${a}" +echo $a + +unset a[0] +echo ${a} + +echo ${a[@]} + +a[5]="hello world" +echo ${a[5]} +echo ${#a[5]} + +echo ${#a[@]} + +a[4+5/2]="test expression" +echo ${a[@]} + +readonly a[5] +readonly a +readonly -a | egrep -v '(BASH_VERSINFO|PIPESTATUS)' +declare -ar | egrep -v '(BASH_VERSINFO|PIPESTATUS)' + +declare -a d='([1]="" [2]="bdef" [5]="hello world" "test")' +d[9]="ninth element" + +declare -a e[10]=test +declare -a e[10]='(test)' + +pass=/etc/passwd +declare -a f='("${d[@]}")' +b=([0]=this [1]=is [2]=a [3]=test [4]="$PS1" [5]=$pass) + +echo ${b[@]:2:3} + +declare -a | egrep -v '(BASH_VERSINFO|PIPESTATUS)' + +a[3]="this is a test" + +b[]=bcde +b[*]=aaa +echo ${b[ ]} + +c[-2]=4 +echo ${c[-4]} + +d[7]=(abdedfegeee) + +d=([]=abcde [1]="test test" [*]=last [-65]=negative ) + +unset d[12] +unset e[*] + +declare -a | egrep -v '(BASH_VERSINFO|PIPESTATUS)' + +ps1='hello' +unset ps1[2] +unset ${ps1[2]} + +declare +a ps1 +declare +a c + +# the prompt should not print when using a here doc +read -p "array test: " -a rv <' recho '' # More tests of "$@" -expect '< abc> ' set abc def ghi jkl +expect '< abc> ' recho " $@ " +expect '< abc> ' +recho "${1+ $@ }" -expect '<--abc> ' set abc def ghi jkl +expect '<--abc> ' recho "--$@--" +set "a b" cd ef gh +expect ' ' +recho ${1+"$@"} +expect ' ' +recho ${foo:-"$@"} +expect ' ' +recho "${@}" + expect '< >' recho " " expect '< - >' @@ -324,3 +334,9 @@ recho '~' expect nothing recho $! + +# test word splitting of assignment statements not preceding a command +a="a b c d e" +declare b=$a +expect ' ' +recho $b diff --git a/tests/exp.right b/tests/exp.right index f34e88a..b1b1c2d 100644 --- a/tests/exp.right +++ b/tests/exp.right @@ -53,10 +53,26 @@ argv[1] = < abc> argv[2] = argv[3] = argv[4] = +argv[1] = < abc> +argv[2] = +argv[3] = +argv[4] = argv[1] = <--abc> argv[2] = argv[3] = argv[4] = +argv[1] = +argv[2] = +argv[3] = +argv[4] = +argv[1] = +argv[2] = +argv[3] = +argv[4] = +argv[1] = +argv[2] = +argv[3] = +argv[4] = argv[1] = < > argv[1] = < - > argv[1] = @@ -111,3 +127,8 @@ argv[1] = <42> argv[1] = <26> argv[1] = <\> argv[1] = <~> +argv[1] = +argv[2] = +argv[3] = +argv[4] = +argv[5] = diff --git a/tests/glob-test b/tests/glob-test index e8c1c70..00227a6 100644 --- a/tests/glob-test +++ b/tests/glob-test @@ -7,9 +7,9 @@ expect() } TESTDIR=/tmp/glob-test -rm -rf $TESTDIR mkdir $TESTDIR -builtin cd $TESTDIR +builtin cd $TESTDIR || { echo $0: cannot cd to $TESTDIR >&2 ; exit 1; } +rm -rf * touch a b c d abc abd abe bb bcd ca cb dd de mkdir bdir @@ -22,12 +22,12 @@ expect ' ' recho \a* # see if null glob expansion works -allow_null_glob_expansion= +shopt -s nullglob expect ' ' recho a* X* -unset allow_null_glob_expansion +shopt -u nullglob # see if the code that expands directories only works expect '' @@ -174,6 +174,111 @@ a["\b"]c) echo ok ;; esac +mkdir man +mkdir man/man1 +touch man/man1/bash.1 +expect '' +recho */man*/bash.* +expect '' +recho $(echo */man*/bash.*) +expect '' +recho "$(echo */man*/bash.*)" + +# tests with multiple `*'s +case abc in +a***c) echo ok 1;; +esac + +case abc in +a*****?c) echo ok 2;; +esac + +case abc in +?*****??) echo ok 3;; +esac + +case abc in +*****??) echo ok 4;; +esac + +case abc in +*****??c) echo ok 5;; +esac + +case abc in +?*****?c) echo ok 6;; +esac + +case abc in +?***?****c) echo ok 7;; +esac + +case abc in +?***?****?) echo ok 8;; +esac + +case abc in +?***?****) echo ok 9;; +esac + +case abc in +*******c) echo ok 10;; +esac + +case abc in +*******?) echo ok 11;; +esac + +case abcdecdhjk in +a*cd**?**??k) echo ok 20;; +esac + +case abcdecdhjk in +a**?**cd**?**??k) echo ok 21;; +esac + +case abcdecdhjk in +a**?**cd**?**??k***) echo ok 22;; +esac + +case abcdecdhjk in +a**?**cd**?**??***k) echo ok 23;; +esac + +case abcdecdhjk in +a**?**cd**?**??***k**) echo ok 24;; +esac + +case abcdecdhjk in +a****c**?**??*****) echo ok 25;; +esac + +# none of these should output anything + +case abc in +??**********?****?) echo bad ;; +esac + +case abc in +??**********?****c) echo bad ;; +esac + +case abc in +?************c****?****) echo bad;; +esac + +case abc in +*c*?**) echo bad;; +esac + +case abc in +a*****c*?**) echo bad;; +esac + +case abc in +a********???*******) echo bad;; +esac + builtin cd / rm -rf $TESTDIR exit 0 diff --git a/tests/glob.right b/tests/glob.right index 4f2acbb..2f1dac2 100644 --- a/tests/glob.right +++ b/tests/glob.right @@ -61,3 +61,23 @@ ok ok ok ok +argv[1] = +argv[1] = +argv[1] = +ok 1 +ok 2 +ok 3 +ok 4 +ok 5 +ok 6 +ok 7 +ok 8 +ok 9 +ok 10 +ok 11 +ok 20 +ok 21 +ok 22 +ok 23 +ok 24 +ok 25 diff --git a/tests/heredoc.right b/tests/heredoc.right new file mode 100644 index 0000000..bf02e2b --- /dev/null +++ b/tests/heredoc.right @@ -0,0 +1,12 @@ +there +hi\ +there$a +stuff +hi\ +there +EO\ +F +hi +hi +hi +there diff --git a/tests/heredoc.tests b/tests/heredoc.tests new file mode 100644 index 0000000..aa69496 --- /dev/null +++ b/tests/heredoc.tests @@ -0,0 +1,45 @@ +# check order and content of multiple here docs + +cat << EOF1 << EOF2 +hi +EOF1 +there +EOF2 + +# check quoted here-doc is protected + +a=foo +cat << 'EOF' +hi\ +there$a +stuff +EOF + +# check that quoted here-documents don't have \newline processing done + +cat << 'EOF' +hi\ +there +EO\ +F +EOF +true + +# check that \newline is removed at start of here-doc +cat << EO\ +F +hi +EOF + +# check that \newline removal works for here-doc delimiter +cat << EOF +hi +EO\ +F + +# check that end of file delimits a here-document +# THIS MUST BE LAST! + +cat << EOF +hi +there diff --git a/tests/input-line.sh b/tests/input-line.sh index 086d7e3..3f66c81 100644 --- a/tests/input-line.sh +++ b/tests/input-line.sh @@ -1,4 +1,4 @@ echo before calling input-line.sub -../bash ./input-line.sub +${THIS_SH} ./input-line.sub this line for input-line.sub echo finished with input-line.sub diff --git a/tests/misc/redir.t4.sh b/tests/misc/redir.t4.sh index 861acdd..78633dc 100644 --- a/tests/misc/redir.t4.sh +++ b/tests/misc/redir.t4.sh @@ -1,7 +1,7 @@ echo "Point 1" exec 3a -exec 5>b +exec 4>/tmp/a +exec 5>/tmp/b echo "Point 2" echo to a 1>&4 echo to b 1>&5 diff --git a/tests/more-exp.right b/tests/more-exp.right new file mode 100644 index 0000000..9e689cb --- /dev/null +++ b/tests/more-exp.right @@ -0,0 +1,146 @@ +argv[1] = +argv[1] = +argv[1] = +argv[1] = +argv[1] = +argv[1] = +argv[1] = +argv[1] = +argv[1] = +argv[1] = +argv[1] = +argv[1] = +argv[2] = +argv[3] = +argv[4] = +argv[5] = +argv[1] = +argv[1] = +argv[2] = +argv[1] = +argv[2] = +argv[3] = +argv[4] = +argv[5] = +argv[1] = +argv[2] = +argv[3] = +argv[4] = +argv[5] = +argv[1] = +argv[1] = +argv[1] = <~> +argv[1] = <\~> +argv[1] = <\ \~> +argv[1] = <\ \ \~> +argv[1] = +argv[1] = +argv[1] = +argv[1] = <$HOME> +argv[1] = <\ $HOME> +argv[1] = <\ \ $HOME> +argv[1] = <'bar'> +argv[1] = <'bar'> +argv[1] = <*@*> +argv[1] = <*@*> +argv[1] = <*@> +argv[1] = <*@> +argv[1] = <*@*> +argv[1] = <*@*> +argv[1] = <*@*> +argv[1] = <*@*> +argv[1] = +argv[1] = +argv[1] = <4> +argv[2] = <2> +argv[1] = <1> +argv[1] = +argv[1] = <2> +argv[1] = +argv[1] = <2> +argv[1] = <4> +argv[1] = <--\> +argv[2] = <--> +argv[1] = <--\^J--> +argv[1] = <--+\> +argv[2] = <+--> +argv[1] = <--+\^J+--> +argv[1] = <-+\> +argv[2] = <+-\> +argv[3] = <-> +argv[1] = +argv[1] = +argv[1] = +argv[1] = <> +argv[1] = <> +argv[1] = +argv[1] = +argv[1] = <> +argv[1] = +argv[1] = +argv[1] = +argv[1] = +argv[1] = <^?> +argv[1] = <^?> +argv[1] = +argv[1] = +argv[1] = <> +argv[2] = +argv[3] = +argv[1] = <> +argv[2] = +argv[3] = <> +argv[1] = +argv[1] = +argv[2] = +argv[3] = +argv[4] = +argv[5] = +argv[6] = +./more-exp.tests: abc=def: command not found +argv[1] = +argv[1] = +argv[2] = +argv[3] = +argv[4] = +argv[5] = +argv[1] = +argv[1] = +argv[1] = <\a> +argv[1] = <\a> +argv[1] = <\a> +argv[1] = <\a> +argv[1] = <\\a> +argv[1] = +argv[1] = <\a> +argv[1] = <\a> +argv[1] = <\a> +argv[1] = <\a> +argv[1] = <\\a> +argv[1] = +argv[1] = +argv[1] = <\a> +argv[1] = <\a> +argv[1] = <\a> +argv[1] = <\a> +argv[1] = <$a> +argv[1] = <\foo> +argv[1] = <$a> +argv[1] = <\foo> +argv[1] = <\$a> +argv[1] = <\\$a> +argv[1] = +argv[1] = +argv[1] = <\a> +argv[1] = <\a> +argv[1] = <\a> +argv[1] = <\a> +argv[1] = +argv[2] = <{> +argv[3] = +argv[4] = +argv[5] = <}> +argv[1] = +argv[2] = +argv[3] = <}> +argv[1] = diff --git a/tests/more-exp.tests b/tests/more-exp.tests new file mode 100644 index 0000000..7f8ae50 --- /dev/null +++ b/tests/more-exp.tests @@ -0,0 +1,303 @@ +expect() +{ + echo expect "$@" +} + +tool_var() { + eval $1=\"\${$1:-$2}\" + export $1 +} + +A="aaa bbb ccc" + +unset B + +tool_var B ${B:-"$A"} + +expect '' +recho "$A" +expect '' +recho "$B" + +eto_prepend() { + eval $1=\'$2\''${'$1':+":"${'$1'}}'; export $1 +} + +foo=bar; export foo +eto_prepend foo baz +expect '' +recho $foo +expect '' +recho ${foo-"bar"} + +aa='aaa bbb ccc' + +expect '' +recho ${zzz-"$aa"} +expect '' +recho ${zzz:-"bar"} +expect '' +recho "${zzz:-bar}" +expect '' +recho "${zzz:-"bar"}" + +var=abcde +expect '' +recho "${var:-xyz}" +expect '' +recho "${var:=xyz}" +expect '' +recho "${var:+xyz}" + +set 'a b' c d e f +expect ' ' +recho ${1+"$@"} +expect '' +recho "${1-"$@"}" +expect ' ' +recho ${1-"$@"} +expect ' ' +recho "${1+$@}" +expect ' ' +recho "${1+"$@"}" + +HOME=/usr/homes/chet +somevar= +expect "<$HOME>" +recho ${somevar:-~} +expect "<$HOME>" +recho "${somevar:-~}" +expect '<~>' +recho "${somevar:-"~"}" +expect '<\~>' +recho "${somevar:-\~}" +expect '<\ \~>' +recho "${somevar:-\ \~}" +expect '<\ \ \~>' +recho "${somevar:-\ \ \~}" + +expect "<$HOME>" +recho ${somevar:-$HOME} +expect "<$HOME>" +recho "${somevar:-$HOME}" +expect "<$HOME>" +recho "${somevar:-"$HOME"}" +expect '<$HOME>' +recho "${somevar:-\$HOME}" +expect '<\ $HOME>' +recho "${somevar:-\ \$HOME}" +expect '<\ \ $HOME>' +recho "${somevar:-\ \ \$HOME}" + +foo=bar +expect "<'bar'>" +recho "${foo+'$foo'}" +expect "<'bar'>" +recho "${fox='$foo'}" + +P='*@*' +expect '<*@*>' +recho "${P%"*"}" +expect '<*@*>' +recho "${P%'*'}" + +expect '<*@>' +recho ${P%"*"} +expect '<*@>' +recho ${P%'*'} + +expect '<*@*>' +recho ${P%""} +expect '<*@*>' +recho ${P#""} + +expect '<*@*>' +recho ${P#"$foobar"} +expect '<*@*>' +recho ${P%"$foobar"} + +s1=abcdefghijkl +s2=efgh + +first=${s1/$s2*/} +expect '' +recho $first + +last=${s1##$first} +expect '' +recho $last + +shift $# +UNAME_RELEASE=${1:-4.2MP} + +RELEASE=`expr "$UNAME_RELEASE" : '[^0-9]*\([0-9]*\)'` # 4 +case "$RELEASE" in +"") RELEASE=0 ;; +*) RELEASE=`expr "$RELEASE" + 0` ;; +esac +REL_LEVEL=`expr "$UNAME_RELEASE" : '[^0-9]*[0-9]*.\([0-9]*\)'` # 1 +REL_SUBLEVEL=`expr "$UNAME_RELEASE" : '[^0-9]*[0-9]*.[0-9]*.\([0-9]*\)'` # 2 + +expect '<4> <2>' +recho $RELEASE $REL_LEVEL $REL_SUBLEVEL + +b1() +{ + b2 ${1+"$@"} +} + +b2() +{ + recho $* + recho $# +} + +expect '<1>' +b1 '' + +expect ' <2>' +b1 bar '' + +expect ' <2>' +b1 '' bar + +expect '<4>' +b1 '' '' '' '' + +NL="\\ +" + +NNL="+$NL+" + +expect '<--\> <-->' +recho --$NL-- +expect '<--\^J-->' +recho "--$NL--" + +expect '<--+\> <+-->' +recho --$NNL-- +expect '<--+\^J+-->' +recho "--$NNL--" + +expect '<-+\> <+-\> <->' +recho -$NNL-$NL- + +set '' +expect '' +recho "$*xy" +expect '' +recho "x$*y" +expect '' +recho "xy$*" +expect '<>' +recho "$*" +expect nothing +recho $* + +unset undef ; set "" + +recho ${undef-"$zzz"} +recho x${undef-"$zzz"} +recho x${undef-"$@"} +recho ${undef-"$@"} +recho ${undef-"$zzz"}x +recho ${undef-"$@"}x +recho "$@"x +recho "$zzz"x +recho ${undef-} +recho ${undef-""} + +yyy="" +recho "$xxx"x +recho "$yyy"x + +set "" "abd" "" +recho "$@"x +recho "$@"$xxx + +OIFS="$IFS" + +arg=a,b,c,d,e,f + +IFS=, + +export z=$arg + +eval z1=\"$arg\" + +IFS="$OIFS" + +recho $z +recho $z1 + +# should give an error +abc\=def + +zz="a b c d e" +declare a=$zz + +recho "$a" +recho $a + +recho $(echo "foo$(echo ")")") + +# test backslash escapes + +recho \a +recho \\a + +recho "\a" +recho "\\a" + +recho '\a' +recho '\\a' + +recho $(zecho \a) +recho $(zecho \\a) + +recho $(zecho "\a") +recho $(zecho "\\a") + +recho $(zecho '\a') +recho $(zecho '\\a') + +recho `zecho \a` +recho `zecho \\a` + +recho `zecho "\a"` +recho `zecho "\\a"` + +recho `zecho '\a'` +recho `zecho '\\a'` + +a=foo + +recho \$a +recho \\$a + +recho "\$a" +recho "\\$a" + +recho '\$a' +recho '\\$a' + +recho $(zecho `zecho \a`) +recho $(zecho `zecho \\a`) + +recho $(zecho `zecho "\a"`) +recho $(zecho `zecho "\\a"`) + +recho $(zecho `zecho '\a'`) +recho $(zecho `zecho '\\a'`) + +# should echo G { I K } +recho ${abc:-G { I } K } + +abc=hi + +# should echo hi K } +recho ${abc:-G { I } K } + +# should echo a* +unset foo +recho "${foo:-"a"}*" diff --git a/tests/new-exp.right b/tests/new-exp.right index 07e2e9c..ea4d327 100644 --- a/tests/new-exp.right +++ b/tests/new-exp.right @@ -3,8 +3,8 @@ argv[1] = argv[1] = argv[1] = argv[1] = -./new-exp.tests: ${HOME:`echo }`}: bad substitution -./new-exp.tests: ${_ENV[(_$-=0)+(_=1)-_${-%%*i*}]}: bad substitution +./new-exp.tests: HOME: }: syntax error: operand expected (error token is "}") +unset argv[1] = argv[1] = argv[1] = @@ -12,7 +12,8 @@ argv[1] = argv[1] = argv[1] = argv[1] = -argv[1] = <*@> +argv[1] = <*@*> +argv[1] = <*@*> argv[1] = <@*> argv[1] = <)> argv[1] = <")"> @@ -25,9 +26,194 @@ argv[1] = bar foo bar foo bar foo -bar foo -bar foo +barfoo +barfoo +argv[1] = +argv[1] = +argv[2] = +argv[1] = +argv[1] = +argv[1] = +argv[1] = +argv[2] = +argv[1] = +argv[2] = +argv[1] = +argv[2] = +argv[3] = +argv[1] = +argv[2] = +argv[3] = +argv[4] = +argv[5] = +argv[1] = +argv[1] = <4> +argv[1] = +argv[1] = +argv[1] = ./new-exp.tests: ABX: unbound variable ./new-exp.tests: $6: cannot assign in this way +argv[1] = +argv[1] = +argv[1] = +argv[1] = +argv[1] = +argv[1] = +argv[1] = +argv[1] = +argv[1] = +argv[1] = +argv[1] = +argv[1] = +argv[1] = +argv[1] = +argv[1] = +argv[1] = +argv[1] = +argv[1] = +argv[2] = +argv[3] = +argv[4] = +argv[5] = +argv[6] = +argv[1] = +argv[2] = +argv[3] = +argv[4] = +argv[5] = +argv[6] = +argv[1] = +argv[2] = +argv[3] = +argv[4] = +argv[5] = +argv[6] = +argv[1] = +argv[2] = +argv[3] = +argv[4] = +argv[5] = +argv[6] = +argv[1] = +argv[2] = +argv[3] = +argv[4] = +argv[5] = +argv[6] = +argv[1] = +argv[1] = +argv[2] = +argv[3] = +argv[4] = +argv[5] = +argv[6] = +argv[1] = +argv[2] = +argv[3] = +argv[4] = +argv[5] = +argv[6] = +argv[1] = +argv[1] = +argv[1] = +argv[2] = +argv[3] = +argv[4] = +argv[5] = +argv[6] = +argv[1] = +argv[2] = +argv[3] = +argv[4] = +argv[5] = +argv[6] = +argv[1] = +argv[2] = +argv[3] = +argv[4] = +argv[5] = +argv[6] = +argv[1] = +argv[2] = +argv[3] = +argv[4] = +argv[5] = +argv[6] = +argv[1] = +argv[2] = +argv[3] = +argv[4] = +argv[5] = +argv[6] = +this is a test of proc subst +this is test 2 +./new-exp.tests: ${#:-foo}: bad substitution +./new-exp.tests: ${#:}: bad substitution +argv[1] = <'> +argv[1] = <"> +argv[1] = <"hello"> +argv[1] = <> +argv[1] = <> +argv[1] = <> +argv[1] = +argv[1] = +argv[1] = +argv[1] = +argv[2] = +argv[1] = +argv[1] = +argv[1] = +argv[1] = +argv[1] = +argv[2] = +argv[3] = +argv[4] = +argv[1] = +argv[2] = +argv[3] = +argv[4] = +argv[1] = +argv[2] = +argv[3] = +argv[4] = +argv[1] = <> +argv[1] = <> +argv[1] = <> +argv[1] = <> +argv[1] = <> +argv[1] = <> +argv[1] = +argv[1] = +argv[1] = +argv[1] = +argv[1] = +argv[1] = +argv[1] = +argv[1] = +argv[1] = <"2 3"> +argv[1] = <"2:3"> +argv[1] = <"34"> +argv[1] = <"3456"> +argv[1] = <"3456"> +argv[1] = <"3456"> +argv[1] = <^A> +argv[2] = <^B> +argv[3] = <^?> +argv[1] = <^A> +argv[2] = <^B> +argv[3] = <^?> +argv[1] = <^A> +argv[2] = <^B> +argv[3] = <^?> +argv[1] = <^A> +argv[2] = <^B> +argv[3] = <^?> +argv[1] = +argv[1] = +argv[1] = +argv[1] = +argv[1] = +argv[1] = +argv[1] = ./new-exp.tests: ABXD: parameter unset diff --git a/tests/new-exp.tests b/tests/new-exp.tests index f19ecf6..4ac36d0 100644 --- a/tests/new-exp.tests +++ b/tests/new-exp.tests @@ -16,11 +16,13 @@ recho "${HOME-'}'}" expect "<$HOME>" recho "${HOME-"}"}" -expect $0: '${HOME:`echo }`}: bad substitution' -recho "${HOME:`echo }`}" # should be an error -- bad substitution +expect $0: 'HOME: }: syntax error: operand expected (error token is "}")' +recho "${HOME:`echo }`}" # should be a math error -- bad substring substitution -expect $0: '${_ENV[(_$-=0)+(_=1)-_${-%%*i*}]}: bad substitution' +expect unset +_ENV=oops x=${_ENV[(_$-=0)+(_=1)-_${-%%*i*}]} # memory leak +echo ${x:-unset} expect "<$HOME>" recho ${HOME} @@ -38,8 +40,10 @@ expect "<$HOME>" recho "$(echo "$(echo "${HOME}")")" P=*@* -expect '<*@>' -recho "${P%"*"}" # should be *@ +expect '<*@*>' +recho "${P%"*"}" # +expect '<*@*>' +recho "${P%'*'}" # expect '<@*>' recho "${P#\*}" # should be @* @@ -73,12 +77,65 @@ echo -n $foo" " ; echo foo expect '' echo -n "$foo " ; echo foo -expect '' +expect '' echo -e "$foo\c " ; echo foo -expect '' +expect '' echo -e $foo"\c " ; echo foo +# substring tests +z=abcdefghijklmnop +expect '' +recho ${z:0:4} + +expect ' ' +recho ${z:4:3} ${z:${#z}-3:3} + +expect '' +recho ${z:7:30} + +expect '' +recho ${z:0:100} + +expect '' +recho ${z:0:${#z}} + +set 'ab cd' 'ef' 'gh ij' 'kl mn' 'op' +expect ' ' +recho "${@:1:2}" + +expect ' ' +recho "${@:3:2}" + +expect ' ' +recho "${@:3:4}" + +expect ' ' +recho "${@:1:$#}" + +# indirect variable references +expect '' +recho ${!9:-$z} + +ef=4 +expect '<4>' +recho ${!2} + +expect '' +recho ${!#} + +set a b c d e +a= +expect '' +recho ${a:-$z} +expect '' +recho ${!1:-$z} + +expect nothing +recho ${a-$z} +expect nothing +recho ${!1-$z} + set -u expect $0: ABX: unbound variable recho ${ABX} @@ -87,9 +144,229 @@ set +u expect $0: '$6: cannot assign in this way' recho ${6="arg6"} +v=abcde + +# sed-like variable substitution +expect '' +recho ${v/a[a-z]/xx} +expect '' +recho ${v/a??/axx} +expect '' +recho ${v/c??/xyz} +expect '' +recho ${v/#a/ab} +expect '' +recho ${v/#d/ab} +expect '' +recho ${v/d/ab} +expect '' +recho ${v/%?/last} +expect '' +recho ${v/%x/last} + +av=(abcd efgh ijkl mnop qrst uvwx) + +expect '' +recho ${av/??/xx} +expect '' +recho ${av/%??/xx} +expect '' +recho ${av[1]/??/xx} +expect '' +recho ${av[1]/%ab/xx} +expect '' +recho ${av[1]/#?/xx} +expect '' +recho ${av[1]/??/za} +expect '' +recho ${av[1]//??/za} +expect '' +recho ${av[1]//#??/za} +expect '' +recho ${av[1]//%??/za} + +expect ' ' +recho ${av[@]/*/yyy} +expect ' ' +recho ${av[@]/#*/yyy} +expect ' ' +recho ${av[@]/%*/yyy} +expect ' ' +recho ${av[@]/a*/yyy} +expect ' ' +recho ${av[@]/%??/xx} + +set abcd efgh ijkl mnop qrst uvwx + +expect '' +recho ${1/??/xx} +expect ' ' +recho ${@/??/xx} +expect ' ' +recho ${@/%??/xx} +expect '' +recho ${3//??/za} +expect '' +recho ${3//%??/za} +expect ' ' +recho ${@//??/za} +expect ' ' +recho ${@//#??/za} +expect ' ' +recho ${@//*/yyy} +expect ' ' +recho ${@//a*/yyy} +expect ' ' +recho ${@//%x*/yyy} + expect a newline echo $abmcde +expect this is a test of proc subst +cat <(echo this is a test of proc subst) +echo this is test 2 > /tmp/x +expect this is test 2 +cat <(cat /tmp/x) +rm -f /tmp/x + +expect $0: '${#:-foo}: bad substitution' +echo ${#:-foo} +expect $0: '${#:}: bad substitution' +echo ${#:} + +expect "<'>" +recho "'" +expect '<">' +recho '"' +expect '<"hello">' +recho "\"hello\"" + +shift $# +unset foo +z=abcdef +z1='abc def' + +expect '<>' +recho ${foo:-""} +expect nothing +recho ${foo:-"$@"} +expect '<>' +recho "${foo:-$@}" + +# unset var +expect '<>' +recho ${foo:-"$zbcd"} +expect nothing +recho ${foo:-$zbcd} + +# set var +expect '' +recho ${foo:-"$z"} +expect '' +recho ${foo:-"$z1"} + +expect '' +recho ${foo:-$z} +expect ' ' +recho ${foo:-$z1} + +expect '' +recho "${foo:-$z}" +expect '' +recho "${foo:-$z1}" + +expect '' +recho "${foo:-"$z"}" +# this disagrees with sh and ksh, but I think it is right according +# to posix.2. +expect '' +recho "${foo:-"$z1"}" + +set ab cd ef gh +expect ' ' +recho ${foo:-"$@"} +expect ' ' +recho "${foo:-$@}" +expect ' ' +recho "${foo:-"$@"}" + +shift $# +expect nothing +recho $xxx"$@" +expect nothing +recho ${foo:-$xxx"$@"} +expect '<>' +recho "${foo:-$xxx$@}" +expect '<>' +recho "${foo:-$xxx"$@"}" + +expect nothing +recho $xxx"$@" +expect nothing +recho "$xxx$@" +expect nothing +recho "$@"$xxx + +expect '<>' +recho $xxx"" +expect '<>' +recho $xxx'' +expect '<>' +recho ''$xxx +expect '<>' +recho ""$xxx + +AB='abcdefghijklmnopqrstuvwxyz' + +recho ${AB:7:15} +recho ${AB:15:7} + +recho ${AB:20} + +recho ${AB:0} +recho ${AB:0:20} + +recho ${AB:10:7} +recho ${AB:10:3+4} +recho ${AB:20/2:3+4} + +set 1 2 3 4 5 6 +recho \""${*:2:2}"\" + +IFS=: +recho \""${*:2:2}"\" + +IFS=$' \t\n' + +z=123456 + +recho \""${z:2:2}"\" +recho \""${z:2}"\" +recho \""${z:2:4}"\" +recho \""${z:2:6}"\" + +set $'\1' $'\2' $'\177' + +recho $* +recho $@ + +recho ${*} +recho ${@} + +xx=one/two/two +recho ${xx%/*} +recho ${xx/\/two} + +yy=oneonetwo +recho ${yy//one} +recho ${yy/\/one} + +xx=oneonetwo + +recho ${xx/one} +recho ${xx//one} +recho ${xx/\/one} + # this must be last! expect $0: 'ABXD: parameter unset' recho ${ABXD:?"parameter unset"} diff --git a/tests/nquote.right b/tests/nquote.right new file mode 100644 index 0000000..3a0fc53 --- /dev/null +++ b/tests/nquote.right @@ -0,0 +1,16 @@ +argv[1] = <^J^J^J> +argv[1] = <> +argv[1] = <^J^I > +argv[1] = +argv[1] = <^M^[^Gabc> +argv[1] = +argv[2] = +argv[1] = +argv[1] = <> +argv[1] = <$hello, world> +argv[1] = +argv[1] = +argv[1] = +argv[1] = +argv[1] = <$hello, chet> +argv[1] = diff --git a/tests/nquote.tests b/tests/nquote.tests new file mode 100644 index 0000000..a2e596b --- /dev/null +++ b/tests/nquote.tests @@ -0,0 +1,57 @@ +expect() +{ + echo expect "$@" +} + +expect '<^J^J^J>' +recho $'\n\n\n' + +z1=$'' +expect '<>' +recho "$z1" + +ZIFS=$'\n'$'\t'$' ' + +expect '<^J^I >' +recho "$ZIFS" + +expect '' +recho $'abc' + +expect '<^M^[^Gabc>' +recho $'\r\e\aabc' + +D=$"hello"," "$"world" + +expect ' ' +recho $D + +expect '' +recho "$D" + +D=$"" +expect '<>' +recho "$D" + +world=chet + +expect '<$hello, world>' +recho \$"hello, world" + +expect '' +recho $"hello, \$world" + +expect '' +recho $"hello, \"world\"" + +expect '' +recho $"hello"', $"world"' + +expect '' +recho $'hello, $"world"' + +expect '<$hello, chet>' +recho \$"hello, $world" + +expect '' +recho $"hello, $world" diff --git a/tests/posix2.right b/tests/posix2.right new file mode 100644 index 0000000..df30c4f --- /dev/null +++ b/tests/posix2.right @@ -0,0 +1,2 @@ +Testing for POSIX.2 conformance +All tests passed diff --git a/tests/posix2.tests b/tests/posix2.tests new file mode 100644 index 0000000..5eea7e0 --- /dev/null +++ b/tests/posix2.tests @@ -0,0 +1,148 @@ +#! /bin/sh +# posix-2.sh - Simple identification tests for POSIX.2 features +# commonly missing or incorrectly implemented. +# Time-stamp: <96/04/10 16:43:48 gildea> +# By Stephen Gildea March 1995 +# +# Copyright (c) 1995 Stephen Gildea +# Permission is hereby granted to deal in this Software without restriction. +# THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND. +# +# MODIFIED BY chet@po.cwru.edu to make part of the bash test suite. +# last change: Wed Jun 19 12:24:24 EDT 1996 +# +# some of the tests: +# +# shell functions (do we care?) +# var=${var:-val} +# unset +# set -- +# IFS parsing +## not exiting with -e and failed "if", the way Ultrix does (Ultrix 4.2?) +# "$@" expands to zero arguments if passed zero arguments +# $SHELL -c 'echo $1' bad good +# test -x +# positional parameters greater than 9 +# arithmetic expansion $(( ... )) +# getopts + +# For some tests we must run a sub-shell; $TESTSHELL says what to use. +# If set, TESTSHELL must be an absolute pathname. +# For example, on HP-UX 9, /bin/posix/sh is the supposedly-compliant shell. +TESTSHELL=${THIS_SH:-$PWD/../bash} + +# these tests create temp files with names $TMPDIR/conf* +: ${TMPDIR:=/tmp} + +exitval=0 +numtests=0 + +echo "Testing for POSIX.2 conformance" + +newtest() +{ + numtests=$(($numtests + 1)) +} + +testfail() +{ + echo "$1 test failed" + exitval=$(($exitval + 1)) +} + +newtest +empty="" +test "${empty:-ok}" = ok || testfail "empty var colon" +newtest +test "${empty-bad}" = "" || testfail "got \"${empty-bad}\": empty var nocolon" +newtest +test "${unsetvar-ok}" = ok || testfail "unset var" +newtest +unset empty +test "${empty-ok}" = ok || testfail "unset" + +newtest +set -- -Z +test "x$1" = x-Z || testfail '\"set -- arg\"' +# this should empty the argument list +newtest +set -- +test $# = 0 || testfail "still $# args: \"set --\"" + +# IFS parsing: +newtest +names=one/good/three +saved_ifs="$IFS" +IFS=/ +set $names lose +test "$2" = good || testfail "got \"$2\": IFS parsing" +IFS="$saved_ifs" + +# "$@" with 0 arguments should expand to 0 arguments +newtest +cat > $TMPDIR/conftest1 << EOF +$TMPDIR/conftest2 "\$@" +EOF +cat > $TMPDIR/conftest2 << "EOF" +#! /bin/sh +echo $# +EOF +chmod +x $TMPDIR/conftest1 $TMPDIR/conftest2 +numargs=$($TESTSHELL $TMPDIR/conftest1) +if [ "$?" != 0 ]; then + testfail 'running $@' +else + test "$numargs" = 0 || testfail '"$@" got '"$numargs args: expansion w 0 args" +fi +rm -f $TMPDIR/conftest1 $TMPDIR/conftest2 + +newtest +val=$("$TESTSHELL" -c 'echo $1' csh good) +test "$val" = good || testfail "got \"$val\": sh -c" + +newtest +# do these tests in a sub-shell because failure will exit +val=$("$TESTSHELL" -c 'echo ${10}' 0 1 2 3 4 5 6 7 8 9 ten 11 2> /dev/null) +test "$val" = ten || testfail "accessing more than 9 positional params" + +a=abc_def_ghi +export a +newtest; val=`"$TESTSHELL" -c 'echo "${a%_*}"' 2> /dev/null` +test "$val" = abc_def || testfail "parameter % op" +newtest; val=`"$TESTSHELL" -c 'echo "${a%%_*}"' 2> /dev/null` +test "$val" = abc || testfail "parameter %% op" +newtest; val=`"$TESTSHELL" -c 'echo "${a#*_}"' 2> /dev/null` +test "$val" = def_ghi || testfail "parameter # op" +newtest; val=`"$TESTSHELL" -c 'echo "${a##*_}"' 2> /dev/null` +test "$val" = ghi || testfail "parameter ## op" + +newtest +"$TESTSHELL" -c 'export a=value' 2> /dev/null || testfail "export with value" + +newtest +a=5; test "$(( ($a+1)/2 ))" = 3 || testfail "arithmetic expansion" + +# does "test" support the -x switch? +newtest +touch $TMPDIR/conftest +chmod -x $TMPDIR/conftest +test -x $TMPDIR/conftest && testfail "negative test -x" +chmod +x $TMPDIR/conftest +test -x $TMPDIR/conftest || testfail "positive test -x" +rm -f $TMPDIR/conftest + +newtest +test "$OPTIND" = 1 || testfail "OPTIND initial value" + +newtest +getopts a: store -a aoptval +if [ "$OPTIND" != 3 ] || [ "$store" != a ] || [ "$OPTARG" != aoptval ]; then + testfail "getopts" +fi + +if [ $exitval = 0 ]; then + echo "All tests passed" +else + echo "$exitval of $numtests tests failed" +fi +exit $exitval diff --git a/tests/quote.right b/tests/quote.right new file mode 100644 index 0000000..8d71f5d --- /dev/null +++ b/tests/quote.right @@ -0,0 +1,42 @@ +Single Quote +foo +bar +foo +bar +foo\ +bar +Double Quote +foo +bar +foo +bar +foobar +Backslash Single Quote +foo bar +foo bar +foobar +Backslash Double Quote +foo bar +foo bar +foobar +Double Quote Backslash Single Quote +foo +bar +foo +bar +foobar +Dollar Paren Single Quote +foo bar +foo bar +foo\ bar +Dollar Paren Double Quote +foo bar +foo bar +foobar +Double Quote Dollar Paren Single Quote +foo +bar +foo +bar +foo\ +bar diff --git a/tests/quote.tests b/tests/quote.tests new file mode 100644 index 0000000..152ea5a --- /dev/null +++ b/tests/quote.tests @@ -0,0 +1,63 @@ +echo "Single Quote" +echo 'foo +bar' +echo 'foo +bar' +echo 'foo\ +bar' + +echo "Double Quote" +echo "foo +bar" +echo "foo +bar" +echo "foo\ +bar" + +echo "Backslash Single Quote" +echo `echo 'foo +bar'` +echo `echo 'foo +bar'` +echo `echo 'foo\ +bar'` + +echo "Backslash Double Quote" +echo `echo "foo +bar"` +echo `echo "foo +bar"` +echo `echo "foo\ +bar"` + +echo "Double Quote Backslash Single Quote" +echo "`echo 'foo +bar'`" +echo "`echo 'foo +bar'`" +echo "`echo 'foo\ +bar'`" + +echo "Dollar Paren Single Quote" +echo $(echo 'foo +bar') +echo $(echo 'foo +bar') +echo $(echo 'foo\ +bar') + +echo "Dollar Paren Double Quote" +echo $(echo "foo +bar") +echo $(echo "foo +bar") +echo $(echo "foo\ +bar") + +echo "Double Quote Dollar Paren Single Quote" +echo "$(echo 'foo +bar')" +echo "$(echo 'foo +bar')" +echo "$(echo 'foo\ +bar')" diff --git a/tests/read.right b/tests/read.right new file mode 100644 index 0000000..68ce898 --- /dev/null +++ b/tests/read.right @@ -0,0 +1,14 @@ +a. +-a-b- +-a-b- +-a b- +-a b- +-a-b\- +-a b\- +-\-a b\- +-\ a b\- +-\-a b\- +-\ a b\- +1: x[A] y[B] z[] +1a: +2: x[A B] diff --git a/tests/read.tests b/tests/read.tests new file mode 100644 index 0000000..ad814d6 --- /dev/null +++ b/tests/read.tests @@ -0,0 +1,24 @@ +echo " a " | (read x; echo "$x.") + +echo " a b " | ( read x y ; echo -"$x"-"$y"- ) +echo " a b\ " | ( read x y ; echo -"$x"-"$y"- ) +echo " a b " | ( read x ; echo -"$x"- ) +echo " a b\ " | ( read x ; echo -"$x"- ) + +echo " a b\ " | ( read -r x y ; echo -"$x"-"$y"- ) +echo " a b\ " | ( read -r x ; echo -"$x"- ) + +echo "\ a b\ " | ( read -r x y ; echo -"$x"-"$y"- ) +echo "\ a b\ " | ( read -r x ; echo -"$x"- ) +echo " \ a b\ " | ( read -r x y ; echo -"$x"-"$y"- ) +echo " \ a b\ " | ( read -r x ; echo -"$x"- ) + +echo "A B " > /tmp/IN +unset x y z +read x y z < /tmp/IN +echo 1: "x[$x] y[$y] z[$z]" +echo 1a: ${z-z not set} +read x < /tmp/IN +echo 2: "x[$x]" +rm /tmp/IN + diff --git a/tests/rhs-exp.right b/tests/rhs-exp.right new file mode 100644 index 0000000..87b9e43 --- /dev/null +++ b/tests/rhs-exp.right @@ -0,0 +1,68 @@ +argv[1] = +argv[1] = +argv[1] = +argv[1] = +argv[1] = +argv[1] = +argv[1] = +argv[1] = +argv[1] = +argv[1] = +argv[1] = +argv[1] = +argv[2] = <=> +argv[3] = <-DSELECT_VECS=$selvecs> +argv[1] = +argv[2] = <=> +argv[3] = <-DSELECT_VECS='&m68kcoff_vec'> +argv[1] = +argv[2] = <=> +argv[3] = <-DSELECT_VECS=&m68kcoff_vec> +argv[1] = +argv[2] = <=> +argv[3] = <-DSELECT_VECS="&m68kcoff_vec"> +argv[1] = +argv[2] = <=> +argv[3] = <-DSELECT_VECS=\&m68kcoff_vec\> +argv[1] = +argv[2] = <=> +argv[3] = <-DSELECT_VECS=&m68kcoff_vec> +argv[1] = +argv[2] = <=> +argv[3] = <-DSELECT_VECS=$selvecs> +argv[1] = +argv[2] = <=> +argv[3] = <-DSELECT_VECS=$selvecs> +argv[1] = +argv[2] = <=> +argv[3] = <-DSELECT_VECS=$selvecs> +argv[1] = +argv[2] = <=> +argv[3] = <-DSELECT_VECS=\&m68kcoff_vec> +argv[1] = +argv[2] = <=> +argv[3] = <-DSELECT_VECS=\'&m68kcoff_vec\'> +argv[1] = +argv[1] = +argv[1] = +argv[1] = +argv[1] = +argv[1] = +argv[1] = +argv[2] = <=> +argv[3] = <-DSELECT_VECS=\'> diff --git a/tests/rhs-exp.tests b/tests/rhs-exp.tests new file mode 100644 index 0000000..9aecb82 --- /dev/null +++ b/tests/rhs-exp.tests @@ -0,0 +1,38 @@ +selvecs='&m68kcoff_vec' +recho "TDEFAULTS = ${selvecs:+-DSELECT_VECS='$selvecs'}" +recho "TDEFAULTS = ${selvecs:+-DSELECT_VECS=\'$selvecs\'}" +recho "TDEFAULTS = ${selvecs:+-DSELECT_VECS="$selvecs"}" +recho "TDEFAULTS = ${selvecs:+-DSELECT_VECS=\"$selvecs\"}" +recho "TDEFAULTS = ${selvecs:+-DSELECT_VECS=\\$selvecs\\}" +recho "TDEFAULTS = ${selvecs:+-DSELECT_VECS=$selvecs}" +recho "TDEFAULTS = ${selvecs:+-DSELECT_VECS=\$selvecs}" +recho "TDEFAULTS = ${selvecs:+-DSELECT_VECS="\$selvecs"}" +recho "TDEFAULTS = ${selvecs:+-DSELECT_VECS='$selvecs'"$null"}" +recho "TDEFAULTS = ${selvecs:+-DSELECT_VECS="\\$selvecs"}" +recho "TDEFAULTS = ${selvecs:+-DSELECT_VECS="\'$selvecs\'"}" + +recho TDEFAULTS = ${selvecs:+-DSELECT_VECS='$selvecs'} +recho TDEFAULTS = ${selvecs:+-DSELECT_VECS=\'$selvecs\'} +recho TDEFAULTS = ${selvecs:+-DSELECT_VECS="$selvecs"} +recho TDEFAULTS = ${selvecs:+-DSELECT_VECS=\"$selvecs\"} +recho TDEFAULTS = ${selvecs:+-DSELECT_VECS=\\$selvecs\\} +recho TDEFAULTS = ${selvecs:+-DSELECT_VECS=$selvecs} +recho TDEFAULTS = ${selvecs:+-DSELECT_VECS=\$selvecs} +recho TDEFAULTS = ${selvecs:+-DSELECT_VECS="\$selvecs"} +recho TDEFAULTS = ${selvecs:+-DSELECT_VECS='$selvecs'"$null"} +recho TDEFAULTS = ${selvecs:+-DSELECT_VECS="\\$selvecs"} +recho TDEFAULTS = ${selvecs:+-DSELECT_VECS="\'$selvecs\'"} + +recho "TDEFAULTS = ${selvecs:+-DSELECT_VECS="\p"}" +recho "TDEFAULTS = ${selvecs:+-DSELECT_VECS=\p}" +recho "TDEFAULTS = ${selvecs:+-DSELECT_VECS="\\"}" +recho "TDEFAULTS = ${selvecs:+-DSELECT_VECS=\\}" +recho "TDEFAULTS = ${selvecs:+-DSELECT_VECS=\'}" +recho "TDEFAULTS = ${selvecs:+-DSELECT_VECS="\'"}" + +recho TDEFAULTS = ${selvecs:+-DSELECT_VECS="\p"} +recho TDEFAULTS = ${selvecs:+-DSELECT_VECS=\p} +recho TDEFAULTS = ${selvecs:+-DSELECT_VECS="\\"} +recho TDEFAULTS = ${selvecs:+-DSELECT_VECS=\\} +recho TDEFAULTS = ${selvecs:+-DSELECT_VECS=\'} +recho TDEFAULTS = ${selvecs:+-DSELECT_VECS="\'"} diff --git a/tests/run-all b/tests/run-all old mode 100755 new mode 100644 index 7add688..c4badc6 --- a/tests/run-all +++ b/tests/run-all @@ -1,14 +1,20 @@ #! /bin/sh -PATH=.:$PATH # just to get the right version of printenv +PATH=.:$PATH # just to get the right version of printenv export PATH -unset ENV +# unset ENV only if it is set +[ "${ENV+set}" = "set" ] && unset ENV + +: ${THIS_SH:=../bash} +export THIS_SH + +echo Testing ${THIS_SH} echo Any output from any test indicates an anomaly worth investigating for x in run-* do case $x in - $0) ;; + $0|run-minimal) ;; *.orig|*~) ;; *) echo $x ; sh $x ;; esac diff --git a/tests/run-arith b/tests/run-arith new file mode 100644 index 0000000..f9f573c --- /dev/null +++ b/tests/run-arith @@ -0,0 +1,2 @@ +${THIS_SH} ./arith.tests > /tmp/xx 2>&1 +diff /tmp/xx arith.right && rm -f /tmp/xx diff --git a/tests/run-array b/tests/run-array new file mode 100644 index 0000000..57a271f --- /dev/null +++ b/tests/run-array @@ -0,0 +1,2 @@ +${THIS_SH} ./array.tests > /tmp/xx 2>&1 +diff /tmp/xx array.right && rm -f /tmp/xx diff --git a/tests/run-braces b/tests/run-braces new file mode 100644 index 0000000..564a96f --- /dev/null +++ b/tests/run-braces @@ -0,0 +1,2 @@ +${THIS_SH} ./braces-tests > /tmp/xx +diff /tmp/xx braces.right && rm -f /tmp/xx diff --git a/tests/run-dollars b/tests/run-dollars old mode 100755 new mode 100644 index 00ad7f1..e230026 --- a/tests/run-dollars +++ b/tests/run-dollars @@ -1,3 +1,3 @@ -../bash ./dollar-star.sh a b > x 2>&1 -../bash ./dollar-at.sh a b >>x 2>&1 -diff x dollar.right && rm -f x +${THIS_SH} ./dollar-star.sh a b > /tmp/xx 2>&1 +${THIS_SH} ./dollar-at.sh a b >>/tmp/xx 2>&1 +diff /tmp/xx dollar.right && rm -f /tmp/xx diff --git a/tests/run-exp-tests b/tests/run-exp-tests old mode 100755 new mode 100644 index b95f603..c55f714 --- a/tests/run-exp-tests +++ b/tests/run-exp-tests @@ -1,2 +1,2 @@ -../bash ./exp-tests | grep -v '^expect' > xx -diff xx exp.right && rm -f xx +${THIS_SH} ./exp-tests | grep -v '^expect' > /tmp/xx +diff /tmp/xx exp.right && rm -f /tmp/xx diff --git a/tests/run-glob-test b/tests/run-glob-test old mode 100755 new mode 100644 index 1e598dc..a01047f --- a/tests/run-glob-test +++ b/tests/run-glob-test @@ -1,4 +1,4 @@ PATH=$PATH:`pwd` export PATH -../bash ./glob-test | grep -v '^expect' > xx -diff xx glob.right && rm -f xx +${THIS_SH} ./glob-test | grep -v '^expect' > /tmp/xx +diff /tmp/xx glob.right && rm -f /tmp/xx diff --git a/tests/run-heredoc b/tests/run-heredoc new file mode 100644 index 0000000..c4e3168 --- /dev/null +++ b/tests/run-heredoc @@ -0,0 +1,2 @@ +${THIS_SH} ./heredoc.tests > /tmp/xx 2>&1 +diff /tmp/xx heredoc.right && rm -f /tmp/xx diff --git a/tests/run-ifs-tests b/tests/run-ifs-tests old mode 100755 new mode 100644 index 1f9c8c0..3d5fc50 --- a/tests/run-ifs-tests +++ b/tests/run-ifs-tests @@ -1,13 +1,13 @@ # # show that IFS is only applied to the result of expansions # -../bash ifs-test-1.sh > xx -diff xx ./ifs.1.right +${THIS_SH} ifs-test-1.sh > /tmp/xx +diff /tmp/xx ./ifs.1.right -../bash ifs-test-2.sh > xx -diff xx ./ifs.2.right +${THIS_SH} ifs-test-2.sh > /tmp/xx +diff /tmp/xx ./ifs.2.right -../bash ifs-test-3.sh > xx -diff xx ./ifs.3.right +${THIS_SH} ifs-test-3.sh > /tmp/xx +diff /tmp/xx ./ifs.3.right -rm -f xx +rm -f /tmp/xx diff --git a/tests/run-input-test b/tests/run-input-test old mode 100755 new mode 100644 index 25d63a0..aaa5d35 --- a/tests/run-input-test +++ b/tests/run-input-test @@ -1,2 +1,2 @@ -../bash < ./input-line.sh > xx -diff xx input.right && rm -f xx +${THIS_SH} < ./input-line.sh > /tmp/xx +diff /tmp/xx input.right && rm -f /tmp/xx diff --git a/tests/run-minus-e b/tests/run-minus-e old mode 100755 new mode 100644 index 51d3229..2a91a3d --- a/tests/run-minus-e +++ b/tests/run-minus-e @@ -1,2 +1,2 @@ -../bash ./minus-e > xx -diff xx minus-e.right && rm -f xx +${THIS_SH} ./minus-e > /tmp/xx +diff /tmp/xx minus-e.right && rm -f /tmp/xx diff --git a/tests/run-more-exp b/tests/run-more-exp new file mode 100644 index 0000000..60f55cb --- /dev/null +++ b/tests/run-more-exp @@ -0,0 +1,2 @@ +${THIS_SH} ./more-exp.tests 2>&1 | grep -v '^expect' > /tmp/xx +diff /tmp/xx more-exp.right && rm -f /tmp/xx diff --git a/tests/run-new-exp b/tests/run-new-exp old mode 100755 new mode 100644 index ef57d32..a000b6b --- a/tests/run-new-exp +++ b/tests/run-new-exp @@ -1,2 +1,2 @@ -../bash ./new-exp.tests 2>&1 | grep -v '^expect' > xx -diff xx new-exp.right && rm -f xx +${THIS_SH} ./new-exp.tests 2>&1 | grep -v '^expect' > /tmp/xx +diff /tmp/xx new-exp.right && rm -f /tmp/xx diff --git a/tests/run-nquote b/tests/run-nquote new file mode 100644 index 0000000..006872c --- /dev/null +++ b/tests/run-nquote @@ -0,0 +1,2 @@ +${THIS_SH} ./nquote.tests 2>&1 | grep -v '^expect' > /tmp/xx +diff /tmp/xx nquote.right && rm -f /tmp/xx diff --git a/tests/run-posix2 b/tests/run-posix2 new file mode 100644 index 0000000..52eea2f --- /dev/null +++ b/tests/run-posix2 @@ -0,0 +1,2 @@ +${THIS_SH} ./posix2.tests 2>&1 | grep -v '^expect' > /tmp/xx +diff /tmp/xx posix2.right && rm -f /tmp/xx diff --git a/tests/run-precedence b/tests/run-precedence old mode 100755 new mode 100644 index 9303e87..d81a868 --- a/tests/run-precedence +++ b/tests/run-precedence @@ -1,2 +1,2 @@ -../bash ./precedence > xx -diff xx prec.right && rm -f xx +${THIS_SH} ./precedence > /tmp/xx +diff /tmp/xx prec.right && rm -f /tmp/xx diff --git a/tests/run-quote b/tests/run-quote new file mode 100644 index 0000000..6905042 --- /dev/null +++ b/tests/run-quote @@ -0,0 +1,2 @@ +${THIS_SH} ./quote.tests >/tmp/xx 2>&1 +diff /tmp/xx quote.right && rm -f /tmp/xx diff --git a/tests/run-read b/tests/run-read new file mode 100644 index 0000000..f2444ba --- /dev/null +++ b/tests/run-read @@ -0,0 +1,2 @@ +${THIS_SH} ./read.tests > /tmp/xx +diff /tmp/xx read.right && rm -f /tmp/xx diff --git a/tests/run-rhs-exp b/tests/run-rhs-exp new file mode 100644 index 0000000..1f89d0b --- /dev/null +++ b/tests/run-rhs-exp @@ -0,0 +1,2 @@ +${THIS_SH} ./rhs-exp.tests 2>&1 > /tmp/xx +diff /tmp/xx rhs-exp.right && rm -f /tmp/xx diff --git a/tests/run-set-e-test b/tests/run-set-e-test old mode 100755 new mode 100644 index 1afef16..cca61cd --- a/tests/run-set-e-test +++ b/tests/run-set-e-test @@ -1,2 +1,2 @@ -../bash ./set-e-test > xx -diff xx set-e.right && rm -f xx +${THIS_SH} ./set-e-test > /tmp/xx +diff /tmp/xx set-e.right && rm -f /tmp/xx diff --git a/tests/run-strip b/tests/run-strip old mode 100755 new mode 100644 index 8c97f6f..0d32115 --- a/tests/run-strip +++ b/tests/run-strip @@ -1,2 +1,2 @@ -../bash ./strip.tests > xx -diff xx strip.right && rm -f xx +${THIS_SH} ./strip.tests > /tmp/xx +diff /tmp/xx strip.right && rm -f /tmp/xx diff --git a/tests/run-test b/tests/run-test new file mode 100644 index 0000000..ab13380 --- /dev/null +++ b/tests/run-test @@ -0,0 +1,2 @@ +${THIS_SH} ./test-tests 2>&1 > /tmp/xx +diff /tmp/xx test.right && rm -f /tmp/xx diff --git a/tests/run-tilde b/tests/run-tilde new file mode 100644 index 0000000..ecb7e9a --- /dev/null +++ b/tests/run-tilde @@ -0,0 +1,2 @@ +${THIS_SH} ./tilde-tests > /tmp/xx +diff /tmp/xx tilde.right && rm -f /tmp/xx diff --git a/tests/run-varenv b/tests/run-varenv old mode 100755 new mode 100644 index 04aece9..f0ce195 --- a/tests/run-varenv +++ b/tests/run-varenv @@ -1,2 +1,2 @@ -../bash ./varenv.sh | grep -v '^expect' > xx -diff xx varenv.right && rm -f xx +${THIS_SH} ./varenv.sh | grep -v '^expect' > /tmp/xx +diff /tmp/xx varenv.right && rm -f /tmp/xx diff --git a/tests/set-e-test b/tests/set-e-test index ce3feb0..214ff88 100644 --- a/tests/set-e-test +++ b/tests/set-e-test @@ -14,3 +14,6 @@ if : ; then done set +e fi +# command subst should not inherit -e +set -e +echo $(false; echo ok) diff --git a/tests/set-e.right b/tests/set-e.right index 92cb7af..61f13b2 100644 --- a/tests/set-e.right +++ b/tests/set-e.right @@ -13,3 +13,4 @@ 7 8 9 +ok diff --git a/tests/test-tests b/tests/test-tests new file mode 100644 index 0000000..1fb0dc8 --- /dev/null +++ b/tests/test-tests @@ -0,0 +1,279 @@ +t() +{ + test "$@" + echo $? +} + +echo 't -a noexist' +t -a noexist +echo 't -a run-all' +t -a run-all + +echo 't -b run-all' +t -b run-all +echo 't -b /dev/jb1a' +t -b /dev/jb1a + +echo 't -c run-all' +t -c run-all +echo 't -c /dev/tty' +t -c /dev/tty + +echo 't -d run-all' +t -d run-all +echo 't -d /etc' +t -d /etc + +echo 't -e noexist' +t -e noexist +echo 't -e run-all' +t -e run-all + +echo 't -f noexist' +t -f noexist +echo 't -f /dev/tty' +t -f /dev/tty +echo 't -f run-all' +t -f run-all + +echo 't -g run-all' +t -g run-all + +touch /tmp/test.setgid +chmod ug+x /tmp/test.setgid +chmod g+s /tmp/test.setgid +echo 't -g /tmp/test.setgid' +t -g /tmp/test.setgid +rm -f /tmp/test.setgid + +echo 't -k run-all' +t -k run-all + +echo 't -n ""' +t -n "" +echo 't -n "hello"' +t -n "hello" + +echo 't -p run-all' +t -p run-all + +echo 't -r noexist' +t -r noexist + +touch /tmp/test.noread +chmod a-r /tmp/test.noread +echo 't -r /tmp/test.noread' +t -r /tmp/test.noread +rm -f /tmp/test.noread + +echo 't -r run-all' +t -r run-all + +echo 't -s noexist' +t -s noexist +echo 't -s /dev/null' +t -s /dev/null +echo 't -s run-all' +t -s run-all + +echo 't -t 20' +t -t 20 +echo 't -t 0' +t -t 0 + +echo 't -u noexist' +t -u noexist + +echo 't -u run-all' +t -u run-all + +touch /tmp/test.setuid +chmod u+x /tmp/test.setuid # some systems require this to turn on setuid bit +chmod u+s /tmp/test.setuid +echo 't -u /tmp/test.setuid' +t -u /tmp/test.setuid +rm -f /tmp/test.setuid + +echo 't -w noexist' +t -w noexist + +touch /tmp/test.nowrite +chmod a-w /tmp/test.nowrite +echo 't -w /tmp/test.nowrite' +t -w /tmp/test.nowrite +rm -f /tmp/test.nowrite + +echo 't -w /dev/null' +t -w /dev/null + +echo 't -x noexist' +t -x noexist + +touch /tmp/test.exec +chmod u+x /tmp/test.exec +echo 't -x /tmp/test.exec' +t -x /tmp/test.exec +rm -f /tmp/test.exec + +touch /tmp/test.noexec +chmod u-x /tmp/test.noexec +echo 't -x /tmp/test.noexec' +t -x /tmp/test.noexec +rm -f /tmp/test.noexec + +echo 't -z ""' +t -z "" +echo 't -z "foo"' +t -z "foo" + +echo 't "foo"' +t "foo" +echo 't ""' +t "" + +touch /tmp/test.owner +echo 't -O /tmp/test.owner' +t -O /tmp/test.owner +rm -f /tmp/test.owner + +echo 't "hello" = "hello"' +t "hello" = "hello" +echo 't "hello" = "goodbye"' +t "hello" = "goodbye" + +echo 't "hello" == "hello"' +t "hello" == "hello" +echo 't "hello" == "goodbye"' +t "hello" == "goodbye" + +echo 't "hello" != "hello"' +t "hello" != "hello" +echo 't "hello" != "goodbye"' +t "hello" != "goodbye" + +echo 't "hello" < "goodbye"' +t "hello" \< "goodbye" +echo 't "hello" > "goodbye"' +t "hello" \> "goodbye" + +echo 't ! "hello" > "goodbye"' +t "! hello" \> "goodbye" + +echo 't 200 -eq 200' +t 200 -eq 200 +echo 't 34 -eq 222' +t 34 -eq 222 + +echo 't 200 -ne 200' +t 200 -ne 200 +echo 't 34 -ne 222' +t 34 -ne 222 + +echo 't 200 -gt 200' +t 200 -gt 200 +echo 't 340 -gt 222' +t 340 -gt 222 + +echo 't 200 -ge 200' +t 200 -ge 200 +echo 't 34 -ge 222' +t 34 -ge 222 + +echo 't 200 -lt 200' +t 200 -lt 200 +echo 't 34 -lt 222' +t 34 -lt 222 + +echo 't 200 -le 200' +t 200 -le 200 +echo 't 340 -le 222' +t 340 -le 222 + +echo 't 700 -le 1000 -a -n "1" -a "20" = "20"' +t 700 -le 1000 -a -n "1" -a "20" = "20" +echo 't ! \( 700 -le 1000 -a -n "1" -a "20" = "20" \)' +t ! \( 700 -le 1000 -a -n "1" -a "20" = "20" \) + +touch /tmp/abc +sleep 2 +touch /tmp/def + +echo 't /tmp/abc -nt /tmp/def' +t /tmp/abc -nt /tmp/def +echo 't /tmp/abc -ot /tmp/def' +t /tmp/abc -ot /tmp/def +echo 't /tmp/def -nt /tmp/abc' +t /tmp/def -nt /tmp/abc +echo 't /tmp/def -ot /tmp/abc' +t /tmp/def -ot /tmp/abc + +echo 't /tmp/abc -ef /tmp/def' +t /tmp/abc -ef /tmp/def +ln /tmp/abc /tmp/ghi +echo 't /tmp/abc -ef /tmp/ghi' +t /tmp/abc -ef /tmp/ghi + +rm /tmp/abc /tmp/def /tmp/ghi + +echo 't -r /dev/fd/0' +t -r /dev/fd/0 +echo 't -w /dev/fd/1' +t -w /dev/fd/1 +echo 't -w /dev/fd/2' +t -w /dev/fd/2 +echo 't' +t + +echo 't 12 -eq 34' +t 12 -eq 34 +echo 't ! 12 -eq 34' +t ! 12 -eq 34 + +echo 't -n abcd -o aaa' +t -n abcd -o aaa +echo 't -n abcd -o -z aaa' +t -n abcd -o -z aaa + +echo 't -n abcd -a aaa' +t -n abcd -a aaa +echo 't -n abcd -a -z aaa' +t -n abcd -a -z aaa + +set +o allexport +echo 't -o allexport' +t -o allexport +echo 't ! -o allexport' +t ! -o allexport + +echo 't xx -a yy' +t xx -a yy +echo 't xx -o ""' +t xx -o "" +echo 't xx -a ""' +t xx -a "" + +echo 't -X -a -X' +t -X -a -X +echo 't -X -o -X' +t -X -o -X +echo 't -X -o ""' +t -X -o "" +echo 't -X -a ""' +t -X -a "" +echo 't "" -a -X' +t "" -a -X +echo 't "" -o -X' +t "" -o -X +echo 't "" -a ""' +t "" -a "" +echo 't "" -o ""' +t "" -o "" +echo 't true -o -X' +t true -o -X +echo 't true -a -X' +t true -a -X + +echo 't ( -E )' +t \( -E \) +echo 't ( "" )' +t \( "" \) diff --git a/tests/test.right b/tests/test.right new file mode 100644 index 0000000..9acf6c8 --- /dev/null +++ b/tests/test.right @@ -0,0 +1,194 @@ +t -a noexist +1 +t -a run-all +0 +t -b run-all +1 +t -b /dev/jb1a +1 +t -c run-all +1 +t -c /dev/tty +0 +t -d run-all +1 +t -d /etc +0 +t -e noexist +1 +t -e run-all +0 +t -f noexist +1 +t -f /dev/tty +1 +t -f run-all +0 +t -g run-all +1 +t -g /tmp/test.setgid +0 +t -k run-all +1 +t -n "" +1 +t -n "hello" +0 +t -p run-all +1 +t -r noexist +1 +t -r /tmp/test.noread +1 +t -r run-all +0 +t -s noexist +1 +t -s /dev/null +1 +t -s run-all +0 +t -t 20 +1 +t -t 0 +0 +t -u noexist +1 +t -u run-all +1 +t -u /tmp/test.setuid +0 +t -w noexist +1 +t -w /tmp/test.nowrite +1 +t -w /dev/null +0 +t -x noexist +1 +t -x /tmp/test.exec +0 +t -x /tmp/test.noexec +1 +t -z "" +0 +t -z "foo" +1 +t "foo" +0 +t "" +1 +t -O /tmp/test.owner +0 +t "hello" = "hello" +0 +t "hello" = "goodbye" +1 +t "hello" == "hello" +0 +t "hello" == "goodbye" +1 +t "hello" != "hello" +1 +t "hello" != "goodbye" +0 +t "hello" < "goodbye" +1 +t "hello" > "goodbye" +0 +t ! "hello" > "goodbye" +1 +t 200 -eq 200 +0 +t 34 -eq 222 +1 +t 200 -ne 200 +1 +t 34 -ne 222 +0 +t 200 -gt 200 +1 +t 340 -gt 222 +0 +t 200 -ge 200 +0 +t 34 -ge 222 +1 +t 200 -lt 200 +1 +t 34 -lt 222 +0 +t 200 -le 200 +0 +t 340 -le 222 +1 +t 700 -le 1000 -a -n "1" -a "20" = "20" +0 +t ! \( 700 -le 1000 -a -n "1" -a "20" = "20" \) +1 +t /tmp/abc -nt /tmp/def +1 +t /tmp/abc -ot /tmp/def +0 +t /tmp/def -nt /tmp/abc +0 +t /tmp/def -ot /tmp/abc +1 +t /tmp/abc -ef /tmp/def +1 +t /tmp/abc -ef /tmp/ghi +0 +t -r /dev/fd/0 +0 +t -w /dev/fd/1 +0 +t -w /dev/fd/2 +0 +t +1 +t 12 -eq 34 +1 +t ! 12 -eq 34 +0 +t -n abcd -o aaa +0 +t -n abcd -o -z aaa +0 +t -n abcd -a aaa +0 +t -n abcd -a -z aaa +1 +t -o allexport +1 +t ! -o allexport +0 +t xx -a yy +0 +t xx -o "" +0 +t xx -a "" +1 +t -X -a -X +0 +t -X -o -X +0 +t -X -o "" +0 +t -X -a "" +1 +t "" -a -X +1 +t "" -o -X +0 +t "" -a "" +1 +t "" -o "" +1 +t true -o -X +0 +t true -a -X +0 +t ( -E ) +0 +t ( "" ) +1 diff --git a/tests/tilde-tests b/tests/tilde-tests index a510751..f0acd55 100644 --- a/tests/tilde-tests +++ b/tests/tilde-tests @@ -1,8 +1,7 @@ HOME=/usr/xyz -set -v -echo ~chet +SHELL=~/bash echo ~ch\et -echo ~chet/"foo" +echo ~/"foo" echo "~chet"/"foo" echo \~chet/"foo" echo \~chet/bar @@ -11,6 +10,30 @@ echo ~chet""/bar echo ":~chet/" echo abcd~chet echo "SHELL=~/bash" -echo SHELL=~/bash +echo $SHELL echo abcd:~chet -echo PATH=/usr/ucb:/bin:~/bin:~/tmp/bin:/usr/bin +path=/usr/ucb:/bin:~/bin:~/tmp/bin:/usr/bin +echo $path + +cd /usr +cd /tmp +echo ~- +echo ~+ + +XPATH=/bin:/usr/bin:. + +# yes tilde expansion +PPATH=$XPATH:~/bin +echo "$PPATH" + +# no tilde expansion +PPATH="$XPATH:~/bin" +echo "$PPATH" + +# yes tilde expansion +export PPATH=$XPATH:~/bin +echo "$PPATH" + +# no tilde expansion +export PPATH="$XPATH:~/bin" +echo "$PPATH" diff --git a/tests/tilde.right b/tests/tilde.right index 2920187..c07ade1 100644 --- a/tests/tilde.right +++ b/tests/tilde.right @@ -1,6 +1,5 @@ -/usr/homes/chet ~chet -/usr/homes/chet/foo +/usr/xyz/foo ~chet/foo ~chet/foo ~chet/bar @@ -9,6 +8,12 @@ :~chet/ abcd~chet SHELL=~/bash -SHELL=/usr/xyz/bash +/usr/xyz/bash abcd:~chet -PATH=/usr/ucb:/bin:~/bin:~/tmp/bin:/usr/bin +/usr/ucb:/bin:/usr/xyz/bin:/usr/xyz/tmp/bin:/usr/bin +/usr +/tmp +/bin:/usr/bin:.:/usr/xyz/bin +/bin:/usr/bin:.:~/bin +/bin:/usr/bin:.:/usr/xyz/bin +/bin:/usr/bin:.:~/bin diff --git a/tests/varenv.right b/tests/varenv.right index 74ce5d3..35972b7 100644 --- a/tests/varenv.right +++ b/tests/varenv.right @@ -12,3 +12,4 @@ /a/b/c /a/b/c 1 2 1 1 +unset diff --git a/tests/varenv.sh b/tests/varenv.sh index d6bd4e5..9938cba 100644 --- a/tests/varenv.sh +++ b/tests/varenv.sh @@ -92,3 +92,14 @@ echo $c $d d=$c c=$d expect "1 1" echo $c $d + +# just for completeness +unset d c +expect unset +echo ${d-unset} + +# no output +export a +a=bcde +export a +/bin/true 2>/dev/null diff --git a/trap.c b/trap.c index c2b951b..139dc2a 100644 --- a/trap.c +++ b/trap.c @@ -19,6 +19,8 @@ with Bash; see the file COPYING. If not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include "config.h" + #include #include "bashtypes.h" @@ -30,8 +32,13 @@ # include #endif /* !HAVE_STRING_H */ +#if defined (HAVE_UNISTD_H) +# include +#endif + #include "shell.h" #include "signames.h" +#include "builtins/common.h" /* Flags which describe the current handling state of a signal. */ #define SIG_INHERITED 0x0 /* Value inherited from parent. */ @@ -39,13 +46,14 @@ #define SIG_HARD_IGNORE 0x2 /* Signal was ignored on shell entry. */ #define SIG_SPECIAL 0x4 /* Treat this signal specially. */ #define SIG_NO_TRAP 0x8 /* Signal cannot be trapped. */ -#define SIG_INPROGRESS 0x10 /* Signal handler currently executing. */ -#define SIG_CHANGED 0x20 /* Trap value changed in trap handler. */ -#define SIG_IGNORED 0x40 /* The signal is currently being ignored. */ +#define SIG_INPROGRESS 0x10 /* Signal handler currently executing. */ +#define SIG_CHANGED 0x20 /* Trap value changed in trap handler. */ +#define SIG_IGNORED 0x40 /* The signal is currently being ignored. */ /* An array of such flags, one for each signal, describing what the - shell will do with a signal. */ -static int sigmodes[NSIG]; + shell will do with a signal. DEBUG_TRAP == NSIG; some code below + assumes this. */ +static int sigmodes[NSIG+1]; static void change_signal (), restore_signal (); @@ -62,11 +70,17 @@ SigHandler *original_signals[NSIG]; DEFAULT_SIG, which means do whatever you were going to do before you were so rudely interrupted, or IGNORE_SIG, which says ignore this signal. */ -char *trap_list[NSIG]; +char *trap_list[NSIG+1]; /* A bitmap of signals received for which we have trap handlers. */ int pending_traps[NSIG]; +/* Set to the number of the signal we're running the trap for + 1. + Used in execute_cmd.c and builtins/common.c to clean up when + parse_and_execute does not return normally after executing the + trap command (e.g., when `return' is executed in the trap command). */ +int running_trap; + /* A value which can never be the target of a trap handler. */ #define IMPOSSIBLE_TRAP_HANDLER (SigHandler *)initialize_traps @@ -75,8 +89,9 @@ initialize_traps () { register int i; - trap_list[0] = (char *)NULL; - sigmodes[0] = SIG_INHERITED; /* On EXIT trap handler. */ + trap_list[EXIT_TRAP] = trap_list[DEBUG_TRAP] = (char *)NULL; + sigmodes[EXIT_TRAP] = sigmodes[DEBUG_TRAP] = SIG_INHERITED; + original_signals[EXIT_TRAP] = IMPOSSIBLE_TRAP_HANDLER; for (i = 1; i < NSIG; i++) { @@ -88,7 +103,8 @@ initialize_traps () /* Show which signals are treated specially by the shell. */ #if defined (SIGCHLD) - original_signals[SIGCHLD] = (SigHandler *) set_signal_handler (SIGCHLD, SIG_DFL); + original_signals[SIGCHLD] = + (SigHandler *) set_signal_handler (SIGCHLD, SIG_DFL); set_signal_handler (SIGCHLD, original_signals[SIGCHLD]); sigmodes[SIGCHLD] |= (SIG_SPECIAL | SIG_NO_TRAP); #endif /* SIGCHLD */ @@ -105,7 +121,8 @@ initialize_traps () if (interactive) { - original_signals[SIGTERM] = (SigHandler *)set_signal_handler (SIGTERM, SIG_DFL); + original_signals[SIGTERM] = + (SigHandler *)set_signal_handler (SIGTERM, SIG_DFL); set_signal_handler (SIGTERM, original_signals[SIGTERM]); sigmodes[SIGTERM] |= SIG_SPECIAL; } @@ -116,10 +133,7 @@ char * signal_name (sig) int sig; { - if (sig >= NSIG || sig < 0) - return ("bad signal number"); - else - return (signal_names[sig]); + return ((sig > NSIG || sig < 0) ? "bad signal number" : signal_names[sig]); } /* Turn a string into a signal number, or a number into @@ -130,30 +144,21 @@ int decode_signal (string) char *string; { - int sig; + long sig; - if (sscanf (string, "%d", &sig) == 1) - { - if (sig < NSIG && sig >= 0) - return (sig); - else - return (NO_SIG); - } + if (legal_number (string, &sig)) + return ((sig >= 0 && sig <= NSIG) ? (int)sig : NO_SIG); - for (sig = 0; sig < NSIG; sig++) - if (STREQ (string, signal_names[sig]) || - STREQ (string, &(signal_names[sig])[3])) - return (sig); + for (sig = 0; sig <= NSIG; sig++) + if (strcasecmp (string, signal_names[sig]) == 0 || + strcasecmp (string, &(signal_names[sig])[3]) == 0) + return ((int)sig); return (NO_SIG); } /* Non-zero when we catch a trapped signal. */ -static int catch_flag = 0; - -#if !defined (USG) && !defined (USGr4) -#define HAVE_BSD_SIGNALS -#endif +static int catch_flag; void run_pending_traps () @@ -175,7 +180,7 @@ run_pending_traps () while (pending_traps[sig]--) instead of the if statement. */ if (pending_traps[sig]) { -#if defined (_POSIX_VERSION) +#if defined (HAVE_POSIX_SIGNALS) sigset_t set, oset; sigemptyset (&set); @@ -187,19 +192,19 @@ run_pending_traps () # if defined (HAVE_BSD_SIGNALS) int oldmask = sigblock (sigmask (sig)); # endif -#endif /* POSIX_VERSION */ +#endif /* HAVE_POSIX_SIGNALS */ if (sig == SIGINT) { run_interrupt_trap (); - interrupt_state = 0; + CLRINTERRUPT; } else parse_and_execute (savestring (trap_list[sig]), "trap", 0); pending_traps[sig] = 0; -#if defined (_POSIX_VERSION) +#if defined (HAVE_POSIX_SIGNALS) sigprocmask (SIG_SETMASK, &oset, (sigset_t *)NULL); #else # if defined (HAVE_BSD_SIGNALS) @@ -219,12 +224,12 @@ trap_handler (sig) if ((sig >= NSIG) || (trap_list[sig] == (char *)DEFAULT_SIG) || (trap_list[sig] == (char *)IGNORE_SIG)) - programming_error ("trap_handler: Bad signal %d", sig); + programming_error ("trap_handler: bad signal %d", sig); else { -#if defined (USG) && !defined (HAVE_BSD_SIGNALS) && !defined (_POSIX_VERSION) +#if defined (MUST_REINSTALL_SIGHANDLERS) set_signal_handler (sig, trap_handler); -#endif /* USG && !HAVE_BSD_SIGNALS && !_POSIX_VERSION */ +#endif /* MUST_REINSTALL_SIGHANDLERS */ catch_flag = 1; pending_traps[sig]++; @@ -232,9 +237,8 @@ trap_handler (sig) if (interrupt_immediately) run_pending_traps (); } -#if !defined (VOID_SIGHANDLER) - return (0); -#endif /* VOID_SIGHANDLER */ + + SIGRETURN (0); } #if defined (JOB_CONTROL) && defined (SIGCHLD) @@ -243,8 +247,6 @@ void set_sigchld_trap (command_string) char *command_string; { - void set_signal (); - set_signal (SIGCHLD, command_string); } @@ -254,19 +256,22 @@ void maybe_set_sigchld_trap (command_string) char *command_string; { - void set_signal (); - if ((sigmodes[SIGCHLD] & SIG_TRAPPED) == 0) set_signal (SIGCHLD, command_string); } #endif /* JOB_CONTROL && SIGCHLD */ -static void -set_sigint_trap (command) +void +set_debug_trap (command) char *command; { - void set_signal (); + set_signal (DEBUG_TRAP, command); +} +void +set_sigint_trap (command) + char *command; +{ set_signal (SIGINT, command); } @@ -280,8 +285,8 @@ set_sigint_handler () return ((SigHandler *)SIG_IGN); else if (sigmodes[SIGINT] & SIG_IGNORED) - return ((SigHandler *)set_signal_handler (SIGINT, SIG_IGN)); - + return ((SigHandler *)set_signal_handler (SIGINT, SIG_IGN)); /* XXX */ + else if (sigmodes[SIGINT] & SIG_TRAPPED) return ((SigHandler *)set_signal_handler (SIGINT, trap_handler)); @@ -299,6 +304,12 @@ set_signal (sig, string) int sig; char *string; { + if (sig == DEBUG_TRAP || sig == EXIT_TRAP) + { + change_signal (sig, savestring (string)); + return; + } + /* A signal ignored on entry to the shell cannot be trapped or reset, but no error is reported when attempting to do so. -- Posix.2 */ if (sigmodes[sig] & SIG_HARD_IGNORE) @@ -347,7 +358,7 @@ free_trap_command (sig) (trap_list[sig] != (char *)IMPOSSIBLE_TRAP_HANDLER)) free (trap_list[sig]); } - + /* If SIG has a string assigned to it, get rid of it. Then give it VALUE. */ static void @@ -396,7 +407,7 @@ void restore_default_signal (sig) int sig; { - if (sig == 0) + if (sig == DEBUG_TRAP || sig == EXIT_TRAP) { free_trap_command (sig); trap_list[sig] = (char *)NULL; @@ -412,11 +423,11 @@ restore_default_signal (sig) return; /* If we aren't trapping this signal, don't bother doing anything else. */ - if (!(sigmodes[sig] & SIG_TRAPPED)) + if ((sigmodes[sig] & SIG_TRAPPED) == 0) return; /* Only change the signal handler for SIG if it allows it. */ - if (!(sigmodes[sig] & SIG_NO_TRAP)) + if ((sigmodes[sig] & SIG_NO_TRAP) == 0) set_signal_handler (sig, original_signals[sig]); /* Change the trap command in either case. */ @@ -431,20 +442,25 @@ void ignore_signal (sig) int sig; { + if ((sig == EXIT_TRAP || sig == DEBUG_TRAP) && ((sigmodes[sig] & SIG_IGNORED) == 0)) + { + change_signal (sig, (char *)IGNORE_SIG); + return; + } + GET_ORIGINAL_SIGNAL (sig); /* A signal ignored on entry to the shell cannot be trapped or reset. - No error is reported when the user attempts to do so. - Thanks to Posix.2. */ + No error is reported when the user attempts to do so. */ if (sigmodes[sig] & SIG_HARD_IGNORE) return; /* If already trapped and ignored, no change necessary. */ - if ((sigmodes[sig] & SIG_TRAPPED) && (trap_list[sig] == (char *)IGNORE_SIG)) + if (sigmodes[sig] & SIG_IGNORED) return; /* Only change the signal handler for SIG if it allows it. */ - if (!(sigmodes[sig] & SIG_NO_TRAP)) + if ((sigmodes[sig] & SIG_NO_TRAP) == 0) set_signal_handler (sig, SIG_IGN); /* Change the trap command in either case. */ @@ -457,28 +473,27 @@ ignore_signal (sig) int run_exit_trap () { - int old_exit_value; + char *trap_command; + int code, old_exit_value; old_exit_value = last_command_exit_value; - /* Run the trap only if signal 0 is trapped and not ignored. */ - if ((sigmodes[0] & SIG_TRAPPED) && - (trap_list[0] != (char *)IGNORE_SIG) && - (sigmodes[0] & SIG_INPROGRESS) == 0) + /* Run the trap only if signal 0 is trapped and not ignored, and we are not + currently running in the trap handler (call to exit in the list of + commands given to trap 0). */ + if ((sigmodes[EXIT_TRAP] & SIG_TRAPPED) && + (sigmodes[EXIT_TRAP] & (SIG_IGNORED|SIG_INPROGRESS)) == 0) { - char *trap_command; - int code; - - trap_command= savestring (trap_list[0]); - sigmodes[0] &= ~SIG_TRAPPED; - sigmodes[0] |= SIG_INPROGRESS; + trap_command = savestring (trap_list[EXIT_TRAP]); + sigmodes[EXIT_TRAP] &= ~SIG_TRAPPED; + sigmodes[EXIT_TRAP] |= SIG_INPROGRESS; code = setjmp (top_level); if (code == 0) - parse_and_execute (trap_command, "trap", 0); + parse_and_execute (trap_command, "exit trap", 0); else if (code == EXITPROG) - return (last_command_exit_value); + return (last_command_exit_value); else return (old_exit_value); } @@ -486,15 +501,63 @@ run_exit_trap () return (old_exit_value); } -/* Set the handler signal SIG to the original and free any trap - command associated with it. */ +void +run_trap_cleanup (sig) + int sig; +{ + sigmodes[sig] &= ~(SIG_INPROGRESS|SIG_CHANGED); +} + +/* Run a trap command for SIG. SIG is one of the signals the shell treats + specially. */ static void -restore_signal (sig) +_run_trap_internal (sig, tag) int sig; + char *tag; { - set_signal_handler (sig, original_signals[sig]); - change_signal (sig, (char *)DEFAULT_SIG); - sigmodes[sig] &= ~SIG_TRAPPED; + char *trap_command, *old_trap; + int old_exit_value; + + /* Run the trap only if SIG is trapped and not ignored, and we are not + currently executing in the trap handler. */ + if ((sigmodes[sig] & SIG_TRAPPED) && ((sigmodes[sig] & SIG_IGNORED) == 0) && + (trap_list[sig] != (char *)IMPOSSIBLE_TRAP_HANDLER) && + ((sigmodes[sig] & SIG_INPROGRESS) == 0)) + { + old_trap = trap_list[sig]; + sigmodes[sig] |= SIG_INPROGRESS; + sigmodes[sig] &= ~SIG_CHANGED; /* just to be sure */ + trap_command = savestring (old_trap); + + running_trap = sig + 1; + old_exit_value = last_command_exit_value; + parse_and_execute (trap_command, tag, 0); + last_command_exit_value = old_exit_value; + running_trap = 0; + + sigmodes[sig] &= ~SIG_INPROGRESS; + + if (sigmodes[sig] & SIG_CHANGED) + { + free (old_trap); + sigmodes[sig] &= ~SIG_CHANGED; + } + } +} + +void +run_debug_trap () +{ + if ((sigmodes[DEBUG_TRAP] & SIG_TRAPPED) && (sigmodes[DEBUG_TRAP] & SIG_INPROGRESS) == 0) + _run_trap_internal (DEBUG_TRAP, "debug trap"); +} + +/* Run a trap set on SIGINT. This is called from throw_to_top_level (), and + declared here to localize the trap functions. */ +void +run_interrupt_trap () +{ + _run_trap_internal (SIGINT, "interrupt trap"); } /* Free all the allocated strings in the list of traps and reset the trap @@ -504,12 +567,13 @@ free_trap_strings () { register int i; - for (i = 0; i < NSIG; i++) + for (i = 0; i < NSIG+1; i++) { free_trap_command (i); trap_list[i] = (char *)DEFAULT_SIG; sigmodes[i] &= ~SIG_TRAPPED; } + trap_list[DEBUG_TRAP] = trap_list[EXIT_TRAP] = (char *)NULL; } /* Reset the handler for SIG to the original value. */ @@ -520,98 +584,57 @@ reset_signal (sig) set_signal_handler (sig, original_signals[sig]); } -/* Reset the handlers for all trapped signals to the values they had when - the shell was started. */ -void -reset_signal_handlers () +/* Set the handler signal SIG to the original and free any trap + command associated with it. */ +static void +restore_signal (sig) + int sig; { - register int i; - - if (sigmodes[0] & SIG_TRAPPED) - { - free_trap_command (0); - trap_list[0] = (char *)NULL; - sigmodes[0] &= ~SIG_TRAPPED; - } - - for (i = 1; i < NSIG; i++) - { - if (sigmodes[i] & SIG_SPECIAL) - reset_signal (i); - else if (sigmodes[i] & SIG_TRAPPED) - { - if (trap_list[i] == (char *)IGNORE_SIG) - set_signal_handler (i, SIG_IGN); - else - reset_signal (i); - } - } + set_signal_handler (sig, original_signals[sig]); + change_signal (sig, (char *)DEFAULT_SIG); + sigmodes[sig] &= ~SIG_TRAPPED; } -/* Reset all trapped signals to their original values. Signals set to be - ignored with trap '' SIGNAL should be ignored, so we make sure that they - are. Called by child processes after they are forked. */ -void -restore_original_signals () +static void +reset_or_restore_signal_handlers (reset) + VFunction *reset; { register int i; - reset_terminating_signals (); /* in shell.c */ - - if (sigmodes[0] & SIG_TRAPPED) + /* Take care of the exit trap first */ + if (sigmodes[EXIT_TRAP] & SIG_TRAPPED) { - free_trap_command (0); - trap_list[0] = (char *)NULL; - sigmodes[0] &= ~SIG_TRAPPED; + free_trap_command (EXIT_TRAP); + trap_list[EXIT_TRAP] = (char *)NULL; + sigmodes[EXIT_TRAP] &= ~SIG_TRAPPED; } - for (i = 1; i < NSIG; i++) { - if (sigmodes[i] & SIG_SPECIAL) - restore_signal (i); - else if (sigmodes[i] & SIG_TRAPPED) + if (sigmodes[i] & SIG_TRAPPED) { if (trap_list[i] == (char *)IGNORE_SIG) set_signal_handler (i, SIG_IGN); else - restore_signal (i); + (*reset) (i); } + else if (sigmodes[i] & SIG_SPECIAL) + (*reset) (i); } } -/* Run a trap set on SIGINT. This is called from throw_to_top_level (), and - declared here to localize the trap functions. */ void -run_interrupt_trap () +reset_signal_handlers () { - char *command, *saved_command; - int old_exit_value; - - /* Run the interrupt trap if SIGINT is trapped and not ignored, and if - we are not currently running in the interrupt trap handler. */ - if ((sigmodes[SIGINT] & SIG_TRAPPED) && - (trap_list[SIGINT] != (char *)IGNORE_SIG) && - (trap_list[SIGINT] != (char *)IMPOSSIBLE_TRAP_HANDLER) && - ((sigmodes[SIGINT] & SIG_INPROGRESS) == 0)) - { - saved_command = trap_list[SIGINT]; - sigmodes[SIGINT] |= SIG_INPROGRESS; - sigmodes[SIGINT] &= ~SIG_CHANGED; - - command = savestring (saved_command); - - old_exit_value = last_command_exit_value; - parse_and_execute (command, "interrupt trap", 0); - last_command_exit_value = old_exit_value; - - sigmodes[SIGINT] &= ~SIG_INPROGRESS; + reset_or_restore_signal_handlers (reset_signal); +} - if (sigmodes[SIGINT] & SIG_CHANGED) - { - free (saved_command); - sigmodes[SIGINT] &= ~SIG_CHANGED; - } - } +/* Reset all trapped signals to their original values. Signals set to be + ignored with trap '' SIGNAL should be ignored, so we make sure that they + are. Called by child processes after they are forked. */ +void +restore_original_signals () +{ + reset_or_restore_signal_handlers (restore_signal); } /* If a trap handler exists for signal SIG, then call it; otherwise just @@ -621,17 +644,19 @@ maybe_call_trap_handler (sig) int sig; { /* Call the trap handler for SIG if the signal is trapped and not ignored. */ - if ((sigmodes[sig] & SIG_TRAPPED) && - (trap_list[sig] != (char *)IGNORE_SIG)) + if ((sigmodes[sig] & SIG_TRAPPED) && ((sigmodes[sig] & SIG_IGNORED) == 0)) { switch (sig) { case SIGINT: run_interrupt_trap (); break; - case 0: + case EXIT_TRAP: run_exit_trap (); break; + case DEBUG_TRAP: + run_debug_trap (); + break; default: trap_handler (sig); break; @@ -668,5 +693,5 @@ set_signal_ignored (sig) int sig; { sigmodes[sig] |= SIG_HARD_IGNORE; - original_signals[sig] = SIG_IGN; + original_signals[sig] = SIG_IGN; } diff --git a/trap.h b/trap.h index 1670231..1983a47 100644 --- a/trap.h +++ b/trap.h @@ -18,8 +18,8 @@ with Bash; see the file COPYING. If not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ -#if !defined (__TRAP_H__) -#define __TRAP_H__ +#if !defined (_TRAP_H_) +#define _TRAP_H_ #include "stdc.h" @@ -36,19 +36,27 @@ #define DEFAULT_SIG SIG_DFL #define IGNORE_SIG SIG_IGN +/* Special shell trap names. */ +#define DEBUG_TRAP NSIG +#define EXIT_TRAP 0 + #define signal_object_p(x) (decode_signal (x) != NO_SIG) -extern char *trap_list[NSIG]; +extern char *trap_list[]; /* Externally-visible functions declared in trap.c. */ extern void initialize_traps __P((void)); extern void run_pending_traps __P((void)); extern void maybe_set_sigchld_trap __P((char *)); extern void set_sigchld_trap __P((char *)); +extern void set_debug_trap __P((char *)); +extern void set_sigint_trap __P((char *)); extern void set_signal __P((int, char *)); extern void restore_default_signal __P((int)); extern void ignore_signal __P((int)); extern int run_exit_trap __P((void)); +extern void run_trap_cleanup __P((int)); +extern void run_debug_trap __P((void)); extern void free_trap_strings __P((void)); extern void reset_signal_handlers __P((void)); extern void restore_original_signals __P((void)); @@ -59,7 +67,8 @@ extern int decode_signal __P((char *)); extern void run_interrupt_trap __P((void)); extern int maybe_call_trap_handler __P((int)); extern int signal_is_trapped __P((int)); -extern int signal_is_special __P((int)); extern int signal_is_ignored __P((int)); +extern int signal_is_special __P((int)); +extern void set_signal_ignored __P((int)); -#endif /* __TRAP_H__ */ +#endif /* _TRAP_H_ */ diff --git a/unwind_prot.c b/unwind_prot.c index d9399d7..dac5e04 100644 --- a/unwind_prot.c +++ b/unwind_prot.c @@ -24,13 +24,18 @@ Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ /* Unwind Protection Scheme for Bash */ /* */ /* **************************************************************** */ -#include "bashtypes.h" -#include #include "config.h" + +#include "bashtypes.h" +#if defined (HAVE_UNISTD_H) +# include +#endif + #include "command.h" #include "general.h" #include "unwind_prot.h" #include "quit.h" +#include "sig.h" /* If CLEANUP is null, then ARG contains a tag to throw back to. */ typedef struct _uwp { @@ -235,7 +240,7 @@ static void restore_variable (sv) SAVED_VAR *sv; { - if (sv->size > sizeof (int)) + if (sv->size != sizeof (int)) { bcopy ((char *)sv->desired_setting, (char *)sv->variable, sv->size); free (sv->desired_setting); @@ -260,7 +265,7 @@ unwind_protect_var (var, value, size) SAVED_VAR *s = (SAVED_VAR *)xmalloc (sizeof (SAVED_VAR)); s->variable = var; - if (size > sizeof (int)) + if (size != sizeof (int)) { s->desired_setting = (char *)xmalloc (size); bcopy (value, (char *)s->desired_setting, size); diff --git a/unwind_prot.h b/unwind_prot.h index e013631..14ef5dc 100644 --- a/unwind_prot.h +++ b/unwind_prot.h @@ -22,16 +22,36 @@ #define _UNWIND_PROT_H /* Run a function without interrupts. */ -void - begin_unwind_frame (), discard_unwind_frame (), - run_unwind_frame (), add_unwind_protect (), remove_unwind_protect (), - run_unwind_protects (); +extern void begin_unwind_frame (); +extern void discard_unwind_frame (); +extern void run_unwind_frame (); +extern void add_unwind_protect (); +extern void remove_unwind_protect (); +extern void run_unwind_protects (); +extern void unwind_protect_var (); + +/* Try to force correct alignment on machines where pointers and ints + differ in size. */ +typedef union { + char *s; + int i; +} UWP; /* Define for people who like their code to look a certain way. */ #define end_unwind_frame() /* How to protect an integer. */ -#define unwind_protect_int(X) unwind_protect_var (&(X), (char *)(X), sizeof (int)) +#define unwind_protect_int(X) \ + do \ + { \ + UWP u; \ + u.i = (X); \ + unwind_protect_var (&(X), u.s, sizeof (int)); \ + } \ + while (0) + +#define unwind_protect_short(X) \ + unwind_protect_var ((int *)&(X), (char *)&(X), sizeof (short)) /* How to protect a pointer to a string. */ #define unwind_protect_string(X) \ @@ -42,6 +62,6 @@ void /* How to protect the contents of a jmp_buf. */ #define unwind_protect_jmp_buf(X) \ - unwind_protect_var ((int *)(X), (char *)(X), sizeof (jmp_buf)) + unwind_protect_var ((int *)(X), (char *)(X), sizeof (procenv_t)) #endif /* _UNWIND_PROT_H */ diff --git a/variables.c b/variables.c index 2c911c2..2c8b939 100644 --- a/variables.c +++ b/variables.c @@ -18,31 +18,45 @@ along with Bash; see the file COPYING. If not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include +#include "config.h" + #include "bashtypes.h" #include "posixstat.h" + +#if defined (HAVE_UNISTD_H) +# include +#endif + +#include #include #include - #include "bashansi.h" + #include "shell.h" -#include "hash.h" #include "flags.h" #include "execute_cmd.h" +#include "mailcheck.h" +#include "input.h" #include "builtins/common.h" #include +#if defined (HISTORY) +# include "bashhist.h" +#endif /* HISTORY */ + /* Variables used here and defined in other files. */ extern int posixly_correct; extern int variable_context, line_number; -extern int interactive, interactive_shell, login_shell, shell_level; -extern int subshell_environment; -extern int build_version; -extern char *dist_version; +extern int interactive, interactive_shell, login_shell; +extern int subshell_environment, indirection_level; +extern int build_version, patch_level; +extern char *dist_version, *release_status; extern char *shell_name; extern char *primary_prompt, *secondary_prompt; +extern char *current_host_name; extern Function *this_shell_builtin; +extern char *this_command_name; extern time_t shell_start_time; /* The list of shell variables that the user has created, or that came from @@ -86,14 +100,17 @@ char **export_env = (char **)NULL; /* Non-zero means that we have to remake EXPORT_ENV. */ int array_needs_making = 1; -/* The list of variables that may not be unset in this shell. */ -char **non_unsettable_vars = (char **)NULL; +/* The number of times BASH has been executed. This is set + by initialize_variables (). */ +int shell_level = 0; -static char *have_local_variables; /* XXX */ -static int local_variable_stack_size = 0; /* XXX */ +static char *have_local_variables; +static int local_variable_stack_size; /* Some forward declarations. */ +static void uidset (); static void initialize_dynamic_variables (); +static void make_vers_array (); static void sbrand (); /* set bash random number generator. */ static int qsort_var_comp (); @@ -101,18 +118,14 @@ static int qsort_var_comp (); #define set_auto_export(var) \ do { var->attributes |= att_exported; array_needs_making = 1; } while (0) -#if defined (HISTORY) -# include "bashhist.h" -#endif /* HISTORY */ - /* Initialize the shell variables from the current environment. */ void -initialize_shell_variables (env) +initialize_shell_variables (env, no_functions) char **env; + int no_functions; /* If set, don't import functions from ENV. */ { - char *name, *string, *current_dir; - int c, char_index; - int string_index = 0; + char *name, *string, *temp_string; + int c, char_index, string_index, string_length; SHELL_VAR *temp_var; if (!shell_variables) @@ -121,10 +134,8 @@ initialize_shell_variables (env) if (!shell_functions) shell_functions = make_hash_table (0); - while (string = env[string_index++]) + for (string_index = 0; string = env[string_index++]; ) { - int string_length; - char_index = 0; string_length = strlen (string); @@ -136,33 +147,42 @@ initialize_shell_variables (env) name[char_index] = '\0'; /* If exported function, define it now. */ - if (!privileged_mode && STREQN ("() {", string, 4)) + if (no_functions == 0 && STREQN ("() {", string, 4)) { - SHELL_VAR *f; - char *eval_string; - - eval_string = xmalloc (3 + string_length + strlen (name)); - sprintf (eval_string, "%s %s", name, string); + temp_string = xmalloc (3 + string_length + strlen (name)); + sprintf (temp_string, "%s %s", name, string); - parse_and_execute (eval_string, name, 0); + parse_and_execute (temp_string, name, 0); if (name[char_index - 1] == ')') name[char_index - 2] = '\0'; - if (f = find_function (name)) + if (temp_var = find_function (name)) { - f->attributes |= (att_exported | att_imported); + temp_var->attributes |= (att_exported | att_imported); array_needs_making = 1; } else report_error ("error importing function definition for `%s'", name); } +#if defined (ARRAY_VARS) +# if 0 + /* Array variables may not yet be exported. */ + else if (*string == '(' && string[1] == '[' && strchr (string, ')')) + { + string_length = 1; + temp_string = extract_array_assignment_list (string, &string_length); + temp_var = assign_array_from_string (name, temp_string); + FREE (temp_string); + temp_var->attributes |= (att_exported | att_imported); + array_needs_making = 1; + } +# endif +#endif else { - SHELL_VAR *v; - - v = bind_variable (name, string); - v->attributes |= (att_exported | att_imported); + temp_var = bind_variable (name, string); + temp_var->attributes |= (att_exported | att_imported); array_needs_making = 1; } free (name); @@ -170,23 +190,26 @@ initialize_shell_variables (env) /* If we got PWD from the environment, update our idea of the current working directory. In any case, make sure that PWD exists before - checking it. It is possible for getwd () to fail on shell startup, + checking it. It is possible for getcwd () to fail on shell startup, and in that case, PWD would be undefined. */ temp_var = find_variable ("PWD"); if (temp_var && imported_p (temp_var) && - (current_dir = value_cell (temp_var)) && - same_file (current_dir, ".", (struct stat *)NULL, (struct stat *)NULL)) - set_working_directory (current_dir); + (temp_string = value_cell (temp_var)) && + same_file (temp_string, ".", (struct stat *)NULL, (struct stat *)NULL)) + set_working_directory (temp_string); else { - current_dir = get_working_directory ("shell-init"); - if (current_dir) - { - bind_variable ("PWD", current_dir); - free (current_dir); - } + temp_string = get_working_directory ("shell-init"); + if (temp_string) + { + bind_variable ("PWD", temp_string); + free (temp_string); + } } + /* Set up initial value of $_ */ + temp_var = bind_variable ("_", dollar_vars[0]); + /* Remember this pid. */ dollar_dollar_pid = (int)getpid (); @@ -198,6 +221,7 @@ initialize_shell_variables (env) temp_var = set_if_not ("TERM", "dumb"); set_auto_export (temp_var); + /* set up the prompts. */ if (interactive_shell) { set_if_not ("PS1", primary_prompt); @@ -205,19 +229,23 @@ initialize_shell_variables (env) } set_if_not ("PS4", "+ "); -#if defined (INSECURITY) - set_if_not ("IFS", " \t\n"); -#else - bind_variable ("IFS", " \t\n"); -#endif /* INSECURITY */ + /* Don't allow IFS to be imported from the environment. */ + temp_var = bind_variable ("IFS", " \t\n"); /* Magic machine types. Pretty convenient. */ - temp_var = set_if_not ("HOSTTYPE", HOSTTYPE); + temp_var = bind_variable ("HOSTTYPE", HOSTTYPE); set_auto_export (temp_var); - temp_var = set_if_not ("OSTYPE", OSTYPE); + temp_var = bind_variable ("OSTYPE", OSTYPE); + set_auto_export (temp_var); + temp_var = bind_variable ("MACHTYPE", MACHTYPE); + set_auto_export (temp_var); + temp_var = bind_variable ("HOSTNAME", current_host_name); set_auto_export (temp_var); - /* Default MAILCHECK for interactive shells. */ + /* Default MAILCHECK for interactive shells. Defer the creation of a + default MAILPATH until the startup files are read, because MAIL + names a mail file if MAILCHECK is not set, and we should provide a + default only if neither is set. */ if (interactive_shell) set_if_not ("MAILCHECK", "60"); @@ -227,90 +255,82 @@ initialize_shell_variables (env) adjust_shell_level (1); /* Make a variable $PPID, which holds the pid of the shell's parent. */ - { - char *ppid; - SHELL_VAR *v; - - ppid = itos ((int) getppid ()); - v = find_variable ("PPID"); - - if (v) - v->attributes &= ~(att_readonly | att_exported); - - v = bind_variable ("PPID", ppid); - v->attributes |= (att_readonly | att_integer); - - non_unsettable ("PPID"); - free (ppid); - } + name = itos ((int) getppid ()); + temp_var = find_variable ("PPID"); + if (temp_var) + temp_var->attributes &= ~(att_readonly | att_exported); + temp_var = bind_variable ("PPID", name); + temp_var->attributes |= (att_readonly | att_integer); + free (name); -#if defined (GETOPTS_BUILTIN) /* Initialize the `getopts' stuff. */ bind_variable ("OPTIND", "1"); + sv_optind ("OPTIND"); bind_variable ("OPTERR", "1"); -#endif /* GETOPTS_BUILTIN */ + sv_opterr ("OPTERR"); /* Get the full pathname to THIS shell, and set the BASH variable to it. */ - { - char *tname; - - if ((login_shell == 1) && (*shell_name != '/')) - { - /* If HOME doesn't exist, set it. */ - temp_var = set_if_not ("HOME", current_user.home_dir); - temp_var->attributes |= att_exported; - - name = savestring (current_user.shell); - } - else if (*shell_name == '/') - name = savestring (shell_name); - else - { - int s; - - tname = find_user_command (shell_name); - if (tname == 0) - { - /* Try the current directory. If there is not an executable - there, just punt and use the login shell. */ - s = file_status (shell_name); - if (s & FS_EXECABLE) - { - tname = make_absolute (shell_name, get_string_value ("PWD")); - if (*shell_name == '.') - { - name = canonicalize_pathname (tname); + if ((login_shell == 1) && (*shell_name != '/')) + { + /* If HOME doesn't exist, set it. */ + temp_var = set_if_not ("HOME", current_user.home_dir); + temp_var->attributes |= att_exported; + + name = savestring (current_user.shell); + } + else if (*shell_name == '/') + name = savestring (shell_name); + else + { + char *tname; + int s; + + tname = find_user_command (shell_name); + + if (tname == 0) + { + /* Try the current directory. If there is not an executable + there, just punt and use the login shell. */ + s = file_status (shell_name); + if (s & FS_EXECABLE) + { + tname = make_absolute (shell_name, get_string_value ("PWD")); + if (*shell_name == '.') + { + name = canonicalize_pathname (tname); + if (name == 0) + name = tname; + else free (tname); - } - else - name = tname; - } - else - name = savestring (current_user.shell); - } - else - { - name = full_pathname (tname); - free (tname); - } - } - - /* Make the exported environment variable SHELL be the user's login - shell. Note that the `tset' command looks at this variable - to determine what style of commands to output; if it ends in "csh", - then C-shell commands are output, else Bourne shell commands. */ - temp_var = set_if_not ("SHELL", current_user.shell); - set_auto_export (temp_var); - - /* Make a variable called BASH, which is the name of THIS shell. */ - temp_var = bind_variable ("BASH", name); - - free (name); - } + } + else + name = tname; + } + else + name = savestring (current_user.shell); + } + else + { + name = full_pathname (tname); + free (tname); + } + } + temp_var = bind_variable ("BASH", name); + free (name); + + /* Make the exported environment variable SHELL be the user's login + shell. Note that the `tset' command looks at this variable + to determine what style of commands to output; if it ends in "csh", + then C-shell commands are output, else Bourne shell commands. */ + temp_var = set_if_not ("SHELL", current_user.shell); + set_auto_export (temp_var); /* Make a variable called BASH_VERSION which contains the version info. */ bind_variable ("BASH_VERSION", shell_version_string ()); +#if defined (ARRAY_VARS) + make_vers_array (); +#endif /* Find out if we're supposed to be in Posix.2 mode via an environment variable. */ @@ -326,10 +346,7 @@ initialize_shell_variables (env) that we are remembering commands on the history list. */ if (remember_on_history) { - if (posixly_correct) - name = tilde_expand ("~/.sh_history"); - else - name = tilde_expand ("~/.bash_history"); + name = bash_tilde_expand (posixly_correct ? "~/.sh_history" : "~/.bash_history"); set_if_not ("HISTFILE", name); free (name); @@ -340,13 +357,11 @@ initialize_shell_variables (env) #endif /* HISTORY */ /* Seed the random number generator. */ - sbrand (dollar_dollar_pid); + sbrand (dollar_dollar_pid + (long)shell_start_time); /* Handle some "special" variables that we may have inherited from a parent shell. */ - noclobber = find_variable ("noclobber") != (SHELL_VAR *)NULL; - temp_var = find_variable ("IGNOREEOF"); if (!temp_var) temp_var = find_variable ("ignoreeof"); @@ -356,36 +371,16 @@ initialize_shell_variables (env) #if defined (HISTORY) if (interactive_shell && remember_on_history) { - sv_command_oriented_history ("command_oriented_history"); - if (find_variable ("history_control")) - sv_history_control ("history_control"); /* gone in next release */ - else - sv_history_control ("HISTCONTROL"); + sv_history_control ("HISTCONTROL"); + sv_histignore ("HISTIGNORE"); } #endif /* HISTORY */ + /* Get the user's real and effective user ids. */ + uidset (); + /* Initialize the dynamic variables, and seed their values. */ initialize_dynamic_variables (); - - non_unsettable ("PATH"); - non_unsettable ("IFS"); - - if (interactive_shell) - { - non_unsettable ("PS1"); - non_unsettable ("PS2"); - } - - /* Get the users real user id, and save that in a readonly variable. - To make the variable *really* readonly, we have added it to a special - list of vars. */ - - sv_uids (); - set_var_read_only ("UID"); - set_var_read_only ("EUID"); - - non_unsettable ("EUID"); - non_unsettable ("UID"); } void @@ -409,28 +404,81 @@ adjust_shell_level (change) free (new_level); } -/* Add NAME to the list of variables that cannot be unset - if it isn't already there. */ -void -non_unsettable (name) - char *name; +static void +uidset () { - register int i; + char *buff; + register SHELL_VAR *v; + + buff = itos (current_user.uid); + v = find_variable ("UID"); + if (v) + v->attributes &= ~att_readonly; + + v = bind_variable ("UID", buff); + v->attributes |= (att_readonly | att_integer); - if (!non_unsettable_vars) + if (current_user.euid != current_user.uid) { - non_unsettable_vars = (char **)xmalloc (1 * sizeof (char *)); - non_unsettable_vars[0] = (char *)NULL; + free (buff); + buff = itos (current_user.euid); } - for (i = 0; non_unsettable_vars[i]; i++) - if (STREQ (non_unsettable_vars[i], name)) - return; + v = find_variable ("EUID"); + if (v) + v->attributes &= ~att_readonly; - non_unsettable_vars = (char **) - xrealloc (non_unsettable_vars, (2 + i) * sizeof (char *)); - non_unsettable_vars[i] = savestring (name); - non_unsettable_vars[i + 1] = (char *)NULL; + v = bind_variable ("EUID", buff); + v->attributes |= (att_readonly | att_integer); + free (buff); +} + +#if defined (ARRAY_VARS) +static void +make_vers_array () +{ + SHELL_VAR *vv; + ARRAY *av; + char *s, d[16]; + + makunbound ("BASH_VERSINFO", shell_variables); + + vv = make_new_array_variable ("BASH_VERSINFO"); + av = array_cell (vv); + strcpy (d, dist_version); + s = strchr (d, '.'); + if (s) + *s++ = '\0'; + array_add_element (av, 0, d); + array_add_element (av, 1, s); + s = itos (patch_level); + array_add_element (av, 2, s); + free (s); + s = itos (build_version); + array_add_element (av, 3, s); + free (s); + array_add_element (av, 4, release_status); + array_add_element (av, 5, MACHTYPE); + + vv->attributes |= att_readonly; +} +#endif /* ARRAY_VARS */ + +/* Set the environment variables $LINES and $COLUMNS in response to + a window size change. */ +void +set_lines_and_columns (lines, cols) + int lines, cols; +{ + char *val; + + val = itos (lines); + bind_variable ("LINES", val); + free (val); + + val = itos (cols); + bind_variable ("COLUMNS", val); + free (val); } /* Set NAME to VALUE if NAME has no value. */ @@ -438,8 +486,9 @@ SHELL_VAR * set_if_not (name, value) char *name, *value; { - SHELL_VAR *v = find_variable (name); + SHELL_VAR *v; + v = find_variable (name); if (!v) v = bind_variable (name, value); return (v); @@ -509,7 +558,7 @@ all_vars (table) SHELL_VAR **list; list = map_over ((Function *)NULL, table); - if (list) + if (list && posixly_correct) sort_variables (list); return (list); } @@ -545,6 +594,7 @@ print_var_list (list) /* Print LIST (a linked list of shell variables) to stdout by printing the names, without the values. Used to support the `set +' command. */ +void print_vars_no_values (list) register SHELL_VAR **list; { @@ -570,22 +620,40 @@ print_assignment (var) print_var_function (var); printf ("\n"); } +#if defined (ARRAY_VARS) + else if (array_p (var) && var->value) + print_array_assignment (var, 0); +#endif /* ARRAY_VARS */ else if (var->value) { printf ("%s=", var->name); - print_var_value (var); + print_var_value (var, 1); printf ("\n"); } } /* Print the value cell of VAR, a shell variable. Do not print - the name, nor leading/trailing newline. */ + the name, nor leading/trailing newline. If QUOTE is non-zero, + and the value contains shell metacharacters, quote the value + in such a way that it can be read back in. */ void -print_var_value (var) +print_var_value (var, quote) SHELL_VAR *var; + int quote; { + char *t; + if (var->value) - printf ("%s", var->value); + { + if (quote && contains_shell_metas (var->value)) + { + t = single_quote (var->value); + printf ("%s", t); + free (t); + } + else + printf ("%s", var->value); + } } /* Print the function cell of VAR, a shell variable. Do not @@ -598,38 +666,61 @@ print_var_function (var) printf ("%s", named_function_string ((char *)NULL, function_cell(var), 1)); } +#if defined (ARRAY_VARS) +void +print_array_assignment (var, quoted) + SHELL_VAR *var; + int quoted; +{ + char *vstr; + + if (quoted) + vstr = quoted_array_assignment_string (array_cell (var)); + else + vstr = array_to_assignment_string (array_cell (var)); + + if (vstr == 0) + printf ("%s=%s\n", var->name, quoted ? "'()'" : "()"); + else + { + printf ("%s=%s\n", var->name, vstr); + free (vstr); + } +} +#endif /* ARRAY_VARS */ + /* **************************************************************** */ -/* */ -/* Dynamic Variable Extension */ -/* */ +/* */ +/* Dynamic Variable Extension */ +/* */ /* **************************************************************** */ /* DYNAMIC VARIABLES - + These are variables whose values are generated anew each time they are referenced. These are implemented using a pair of function pointers in the struct variable: assign_func, which is called from bind_variable, and dynamic_value, which is called from find_variable. - + assign_func is called from bind_variable, if bind_variable discovers that the variable being assigned to has such a function. The function is called as SHELL_VAR *temp = (*(entry->assign_func)) (entry, value) and the (SHELL_VAR *)temp is returned as the value of bind_variable. It is usually ENTRY (self). - + dynamic_value is called from find_variable to return a `new' value for the specified dynamic varible. If this function is NULL, the variable is treated as a `normal' shell variable. If it is not, however, then this function is called like this: tempvar = (*(var->dynamic_value)) (var); - + Sometimes `tempvar' will replace the value of `var'. Other times, the shell will simply use the string value. Pretty object-oriented, huh? - + Be warned, though: if you `unset' a special variable, it loses its special meaning, even if you subsequently set it. - + The special assignment code would probably have been better put in subst.c: do_assignment, in the same style as stupidly_hack_special_variables, but I wanted the changes as @@ -638,14 +729,14 @@ print_var_function (var) /* The value of $SECONDS. This is the number of seconds since shell invocation, or, the number of seconds since the last assignment + the value of the last assignment. */ -static long seconds_value_assigned = (long)0; +static long seconds_value_assigned; static SHELL_VAR * assign_seconds (self, value) SHELL_VAR *self; char *value; { - seconds_value_assigned = atol (value); + seconds_value_assigned = string_to_long (value); shell_start_time = NOW; return (self); } @@ -669,6 +760,7 @@ get_seconds (var) /* The random number seed. You can change this by setting RANDOM. */ static unsigned long rseed = 1; +static unsigned long last_random_value; /* A linear congruential random number generator based on the ANSI C standard. A more complicated one is overkill. */ @@ -694,9 +786,7 @@ assign_random (self, value) SHELL_VAR *self; char *value; { - int s = atoi (value); - - sbrand (s); + sbrand (atoi (value)); return (self); } @@ -707,7 +797,15 @@ get_random (var) int rv; char *p; - rv = brand (); + /* Reset for command and process substitution. */ + if (subshell_environment) + sbrand ((int)(getpid() + NOW)); + + do + rv = brand (); + while (rv == (int)last_random_value); + + last_random_value = rv; p = itos ((int)rv); FREE (var->value); @@ -723,13 +821,24 @@ get_lineno (var) SHELL_VAR *var; { char *p; + int ln; - p = itos (line_number); + ln = executing_line_number (); + p = itos (ln); FREE (var->value); var->value = p; return (var); } +static SHELL_VAR * +assign_lineno (var, value) + SHELL_VAR *var; + char *value; +{ + line_number = atoi (value); + return var; +} + #if defined (HISTORY) static SHELL_VAR * get_histcmd (var) @@ -744,6 +853,32 @@ get_histcmd (var) } #endif +#if defined (PUSHD_AND_POPD) && defined (ARRAY_VARS) +static SHELL_VAR * +get_dirstack (self) + SHELL_VAR *self; +{ + ARRAY *a; + WORD_LIST *l; + + l = get_directory_stack (); + a = word_list_to_array (l); + dispose_array (array_cell (self)); + self->value = (char *)a; + return self; +} + +static SHELL_VAR * +assign_dirstack (self, ind, value) + SHELL_VAR *self; + int ind; + char *value; +{ + set_dirstack_element (ind, 1, value); + return self; +} +#endif /* PUSHD AND POPD && ARRAY_VARS */ + static void initialize_dynamic_variables () { @@ -759,13 +894,19 @@ initialize_dynamic_variables () v = bind_variable ("LINENO", (char *)NULL); v->dynamic_value = get_lineno; - v->assign_func = (DYNAMIC_FUNC *)NULL; + v->assign_func = assign_lineno; #if defined (HISTORY) v = bind_variable ("HISTCMD", (char *)NULL); v->dynamic_value = get_histcmd; v->assign_func = (DYNAMIC_FUNC *)NULL; #endif + +#if defined (PUSHD_AND_POPD) && defined (ARRAY_VARS) + v = make_new_array_variable ("DIRSTACK"); + v->dynamic_value = get_dirstack; + v->assign_func = assign_dirstack; +#endif /* PUSHD_AND_POPD && ARRAY_VARS */ } /* How to get a pointer to the shell variable or function named NAME. @@ -779,11 +920,7 @@ var_lookup (name, hashed_vars) BUCKET_CONTENTS *bucket; bucket = find_hash_item (name, hashed_vars); - - if (bucket) - return ((SHELL_VAR *)bucket->data); - else - return ((SHELL_VAR *)NULL); + return (bucket ? (SHELL_VAR *)bucket->data : (SHELL_VAR *)NULL); } /* Look up the variable entry named NAME. If SEARCH_TEMPENV is non-zero, @@ -810,10 +947,7 @@ find_variable_internal (name, search_tempenv) if (!var) return ((SHELL_VAR *)NULL); - if (var->dynamic_value) - return ((*(var->dynamic_value)) (var)); - else - return (var); + return (var->dynamic_value ? (*(var->dynamic_value)) (var) : var); } /* Look up the variable entry named NAME. Returns the entry or NULL. */ @@ -845,6 +979,10 @@ get_string_value (var_name) if (!var) return (char *)NULL; +#if defined (ARRAY_VARS) + else if (array_p (var)) + return (array_reference (array_cell (var), 0)); +#endif else return (var->value); } @@ -883,15 +1021,13 @@ make_local_variable (name) new_var = (SHELL_VAR *)xmalloc (sizeof (SHELL_VAR)); new_var->name = savestring (name); - new_var->value = savestring (""); + new_var->value = xmalloc (1); + new_var->value[0] = '\0'; new_var->dynamic_value = (DYNAMIC_FUNC *)NULL; new_var->assign_func = (DYNAMIC_FUNC *)NULL; - new_var->attributes = 0; - - if (exported_p (old_var)) - new_var->attributes |= att_exported; + new_var->attributes = exported_p (old_var) ? att_exported : 0; new_var->prev_context = old_var; elt = add_hash_item (savestring (name), shell_variables); @@ -899,15 +1035,14 @@ make_local_variable (name) } new_var->context = variable_context; + new_var->attributes |= att_local; /* XXX */ - if (local_variable_stack_size <= variable_context) + if (variable_context >= local_variable_stack_size) { int old_size = local_variable_stack_size; - while (local_variable_stack_size <= variable_context) - local_variable_stack_size += 8; - have_local_variables = - xrealloc (have_local_variables, local_variable_stack_size); + RESIZE_MALLOCED_BUFFER (have_local_variables, variable_context, 1, + local_variable_stack_size, 8); bzero ((char *)have_local_variables + old_size, local_variable_stack_size - old_size); } @@ -916,95 +1051,156 @@ make_local_variable (name) return (new_var); } -/* Bind a variable NAME to VALUE. This conses up the name - and value strings. */ +#if defined (ARRAY_VARS) SHELL_VAR * -bind_variable (name, value) - char *name, *value; +make_local_array_variable (name) + char *name; +{ + SHELL_VAR *var; + ARRAY *array; + + var = make_local_variable (name); + array = new_array (); + + FREE (value_cell(var)); + var->value = (char *)array; + var->attributes |= att_array; + return var; +} +#endif /* ARRAY_VARS */ + +/* Create a new shell variable with name NAME and add it to the hash table + of shell variables. */ +static +SHELL_VAR * +make_new_variable (name) + char *name; { - SHELL_VAR *entry = var_lookup (name, shell_variables); + SHELL_VAR *entry; BUCKET_CONTENTS *elt; - if (!entry) - { - /* Make a new entry for this variable. Then do the binding. */ - entry = (SHELL_VAR *)xmalloc (sizeof (SHELL_VAR)); + entry = (SHELL_VAR *)xmalloc (sizeof (SHELL_VAR)); - entry->attributes = 0; - entry->name = savestring (name); + entry->attributes = 0; + entry->name = savestring (name); + entry->value = (char *)NULL; - if (value) + entry->dynamic_value = (DYNAMIC_FUNC *)NULL; + entry->assign_func = (DYNAMIC_FUNC *)NULL; + + /* Always assume variables are to be made at toplevel! + make_local_variable has the responsibilty of changing the + variable context. */ + entry->context = 0; + entry->prev_context = (SHELL_VAR *)NULL; + + elt = add_hash_item (savestring (name), shell_variables); + elt->data = (char *)entry; + + return entry; +} + +#if defined (ARRAY_VARS) +SHELL_VAR * +make_new_array_variable (name) + char *name; +{ + SHELL_VAR *entry; + ARRAY *array; + + entry = make_new_variable (name); + array = new_array (); + entry->value = (char *)array; + entry->attributes |= att_array; + return entry; +} +#endif + +char * +make_variable_value (var, value) + SHELL_VAR *var; + char *value; +{ + char *retval; + long lval; + + /* If this variable has had its type set to integer (via `declare -i'), + then do expression evaluation on it and store the result. The + functions in expr.c (evalexp and bind_int_variable) are responsible + for turning off the integer flag if they don't want further + evaluation done. */ + if (integer_p (var)) + { + lval = evalexp (value); + retval = itos (lval); + } + else if (value) + { + if (*value) + retval = savestring (value); + else { - if (*value) - entry->value = savestring (value); - else - { - entry->value = xmalloc (1); - entry->value[0] = '\0'; - } + retval = xmalloc (1); + retval[0] = '\0'; } - else - entry->value = (char *)NULL; + } + else + retval = (char *)NULL; - entry->dynamic_value = (DYNAMIC_FUNC *)NULL; - entry->assign_func = (DYNAMIC_FUNC *)NULL; + return retval; +} - /* Always assume variables are to be made at toplevel! - make_local_variable has the responsibilty of changing the - variable context. */ - entry->context = 0; - entry->prev_context = (SHELL_VAR *)NULL; +/* Bind a variable NAME to VALUE. This conses up the name + and value strings. */ +SHELL_VAR * +bind_variable (name, value) + char *name, *value; +{ + char *newval; + SHELL_VAR *entry; - elt = add_hash_item (savestring (name), shell_variables); - elt->data = (char *)entry; + entry = var_lookup (name, shell_variables); + + if (entry == 0) + { + entry = make_new_variable (name); + entry->value = make_variable_value (entry, value); } +#if defined (ARRAY_VARS) + else if (entry->assign_func && array_p (entry) == 0) +#else else if (entry->assign_func) +#endif return ((*(entry->assign_func)) (entry, value)); else { if (readonly_p (entry)) { - report_error ("%s: read-only variable", name); + report_error ("%s: readonly variable", name); return (entry); } /* Variables which are bound are visible. */ entry->attributes &= ~att_invisible; - /* If this variable has had its type set to integer (via `declare -i'), - then do expression evaluation on it and store the result. The - functions in expr.c (evalexp and bind_int_variable) are responsible - for turning off the integer flag if they don't want further - evaluation done. */ - if (integer_p (entry)) - { - long val; + newval = make_variable_value (entry, value); - val = evalexp (value); - /* We cannot free () entry->value before this; what if the string - we are working is `even=even+2'? We need the original value - around while we are doing the evaluation to handle any possible - recursion. */ - FREE (entry->value); - entry->value = itos (val); - } +#if defined (ARRAY_VARS) + /* XXX -- this bears looking at again -- XXX */ + /* If an existing array variable x is being assigned to with x=b or + `read x' or something of that nature, silently convert it to + x[0]=b or `read x[0]'. */ + if (array_p (entry)) + array_add_element (array_cell (entry), 0, newval); else { FREE (entry->value); - - if (value) - { - if (*value) - entry->value = savestring (value); - else - { - entry->value = xmalloc (1); - entry->value[0] = '\0'; - } - } - else - entry->value = (char *)NULL; + entry->value = newval; } +#else + FREE (entry->value); + entry->value = newval; +#endif } if (mark_modified_vars) @@ -1016,6 +1212,188 @@ bind_variable (name, value) return (entry); } +#if defined (ARRAY_VARS) +/* Convert a shell variable to an array variable. The original value is + saved as array[0]. */ +SHELL_VAR * +convert_var_to_array (var) + SHELL_VAR *var; +{ + char *oldval; + ARRAY *array; + + oldval = value_cell (var); + array = new_array (); + array_add_element (array, 0, oldval); + FREE (value_cell (var)); + var->value = (char *)array; + var->attributes |= att_array; + var->attributes &= ~att_invisible; + + return var; +} + +/* Perform an array assignment name[ind]=value. If NAME already exists and + is not an array, and IND is 0, perform name=value instead. If NAME exists + and is not an array, and IND is not 0, convert it into an array with the + existing value as name[0]. + + If NAME does not exist, just create an array variable, no matter what + IND's value may be. */ +SHELL_VAR * +bind_array_variable (name, ind, value) + char *name; + int ind; + char *value; +{ + SHELL_VAR *entry; + char *newval; + + entry = var_lookup (name, shell_variables); + + if (entry == (SHELL_VAR *) 0) + entry = make_new_array_variable (name); + else if (readonly_p (entry)) + { + report_error ("%s: readonly variable", name); + return (entry); + } + else if (array_p (entry) == 0) + entry = convert_var_to_array (entry); + + /* ENTRY is an array variable, and ARRAY points to the value. */ + newval = make_variable_value (entry, value); + if (entry->assign_func) + (*entry->assign_func) (entry, ind, newval); + else + array_add_element (array_cell (entry), ind, newval); + FREE (newval); + + return (entry); +} + +SHELL_VAR * +assign_array_from_string (name, value) + char *name, *value; +{ + SHELL_VAR *var; + + var = find_variable (name); + if (var == 0) + var = make_new_array_variable (name); + else if (array_p (var) == 0) + var = convert_var_to_array (var); + + return (assign_array_var_from_string (var, value)); +} + +SHELL_VAR * +assign_array_var_from_word_list (var, list) + SHELL_VAR *var; + WORD_LIST *list; +{ + register int i; + register WORD_LIST *l; + ARRAY *a; + + for (a = array_cell (var), l = list, i = 0; l; l = l->next, i++) + if (var->assign_func) + (*var->assign_func) (var, i, l->word->word); + else + array_add_element (a, i, l->word->word); + return var; +} + +SHELL_VAR * +assign_array_var_from_string (var, value) + SHELL_VAR *var; + char *value; +{ + ARRAY *a; + WORD_LIST *list, *nlist; + char *w, *val, *nval; + int ni, len, ind, last_ind; + + a = array_cell (var); + + /* Expand the value string into a list of words, performing all the + shell expansions including word splitting. */ + if (*value == '(') + { + ni = 1; + val = extract_array_assignment_list (value, &ni); + if (val == 0) + return var; + nlist = expand_string (val, 0); + free (val); + } + else + nlist = expand_string (value, 0); + + for (last_ind = 0, list = nlist; list; list = list->next) + { + w = list->word->word; + + /* We have a word of the form [ind]=value */ + if (w[0] == '[') + { + len = skipsubscript (w, 0); + + if (w[len] != ']' || w[len+1] != '=') + { + nval = make_variable_value (var, w); + if (var->assign_func) + (*var->assign_func) (var, last_ind, nval); + else + array_add_element (a, last_ind, nval); + FREE (nval); + last_ind++; + continue; + } + + if (len == 1) + { + report_error ("%s: bad array subscript", w); + continue; + } + + if (ALL_ELEMENT_SUB (w[1]) && len == 2) + { + report_error ("%s: cannot assign to non-numeric index", w); + continue; + } + + ind = array_expand_index (w + 1, len); + if (ind < 0) + { + report_error ("%s: bad array subscript", w); + continue; + } + last_ind = ind; + val = w + len + 2; + } + else /* No [ind]=value, just a stray `=' */ + { + ind = last_ind; + val = w; + } + + if (integer_p (var)) + this_command_name = (char *)NULL; /* no command name for errors */ + nval = make_variable_value (var, val); + if (var->assign_func) + (*var->assign_func) (var, ind, nval); + else + array_add_element (a, ind, nval); + FREE (nval); + last_ind++; + } + + dispose_words (nlist); + return (var); +} +#endif /* ARRAY_VARS */ + /* Dispose of the information attached to VAR. */ void dispose_variable (var) @@ -1025,9 +1403,13 @@ dispose_variable (var) return; if (function_p (var)) - dispose_command ((COMMAND *)var->value); - else if (var->value) - free (var->value); + dispose_command (function_cell (var)); +#if defined (ARRAY_VARS) + else if (array_p (var)) + dispose_array (array_cell (var)); +#endif + else + FREE (value_cell (var)); free (var->name); @@ -1037,7 +1419,45 @@ dispose_variable (var) free (var); } +#if defined (ARRAY_VARS) +/* This function is called with SUB pointing to just after the beginning + `[' of an array subscript. */ +int +unbind_array_element (var, sub) + SHELL_VAR *var; + char *sub; +{ + int len, ind; + ARRAY_ELEMENT *ae; + + len = skipsubscript (sub, 0); + if (sub[len] != ']' || len == 0) + { + builtin_error ("%s[%s: bad array subscript", var->name, sub); + return -1; + } + sub[len] = '\0'; + + if (ALL_ELEMENT_SUB (sub[0]) && sub[1] == 0) + { + makunbound (var->name, shell_variables); + return (0); + } + ind = array_expand_index (sub, len+1); + if (ind < 0) + { + builtin_error ("[%s: bad array subscript", sub); + return -1; + } + ae = array_delete_element (array_cell (var), ind); + if (ae) + destroy_array_element (ae); + return 0; +} +#endif + /* Unset the variable referenced by NAME. */ +int unbind_variable (name) char *name; { @@ -1046,7 +1466,12 @@ unbind_variable (name) if (!var) return (-1); + /* This function should never be called with an array variable name. */ +#if defined (ARRAY_VARS) + if (array_p (var) == 0 && var->value) +#else if (var->value) +#endif { free (var->value); var->value = (char *)NULL; @@ -1061,6 +1486,7 @@ unbind_variable (name) hash table from which this variable should be deleted (either shell_variables or shell_functions). Returns non-zero if the variable couldn't be found. */ +int makunbound (name, hash_list) char *name; HASH_TABLE *hash_list; @@ -1080,6 +1506,21 @@ makunbound (name, hash_list) if (old_var && exported_p (old_var)) array_needs_making++; + /* If we're unsetting a local variable and we're still executing inside + the function, just mark the variable as invisible. + kill_all_local_variables will clean it up later. This must be done + so that if the variable is subsequently assigned a new value inside + the function, the `local' attribute is still present. We also need + to add it back into the correct hash table. */ + if (old_var && local_p (old_var) && variable_context == old_var->context) + { + old_var->attributes |= att_invisible; + elt = add_hash_item (savestring (old_var->name), hash_list); + elt->data = (char *)old_var; + stupidly_hack_special_variables (old_var->name); + return (0); + } + if (new_var) { /* Has to be a variable, functions don't have previous contexts. */ @@ -1089,7 +1530,7 @@ makunbound (name, hash_list) new_elt->data = (char *)new_var; if (exported_p (new_var)) - set_var_auto_export (new_var->name); + set_auto_export (new_var); } /* Have to save a copy of name here, because it might refer to @@ -1108,12 +1549,13 @@ makunbound (name, hash_list) /* Remove the variable with NAME if it is a local variable in the current context. */ +int kill_local_variable (name) char *name; { SHELL_VAR *temp = find_variable (name); - if (temp && (temp->context == variable_context)) + if (temp && temp->context == variable_context) { makunbound (name, shell_variables); return (0); @@ -1136,8 +1578,15 @@ kill_all_local_variables () register SHELL_VAR *var, **list; HASH_TABLE *varlist; - /* XXX */ - if (!have_local_variables || have_local_variables[variable_context] == 0) + /* If HAVE_LOCAL_VARIABLES == 0, it means that we don't have any local + variables at all. If VARIABLE_CONTEXT >= LOCAL_VARIABLE_STACK_SIZE, + it means that we have some local variables, but not in this variable + context (level of function nesting). Also, if + HAVE_LOCAL_VARIABLES[VARIABLE_CONTEXT] == 0, we have no local variables + at this context. */ + if (have_local_variables == 0 || + variable_context >= local_variable_stack_size || + have_local_variables[variable_context] == 0) return; for (pass = 0; pass < 2; pass++) @@ -1149,8 +1598,10 @@ kill_all_local_variables () if (list) { for (i = 0; var = list[i]; i++) - makunbound (var->name, varlist); - + { + var->attributes &= ~att_local; + makunbound (var->name, varlist); + } free (list); } } @@ -1158,40 +1609,27 @@ kill_all_local_variables () have_local_variables[variable_context] = 0; /* XXX */ } +static void +free_variable_hash_data (data) + char *data; +{ + SHELL_VAR *var, *prev; + + var = (SHELL_VAR *)data; + while (var) + { + prev = var->prev_context; + dispose_variable (var); + var = prev; + } +} + /* Delete the entire contents of the hash table. */ void delete_all_variables (hashed_vars) HASH_TABLE *hashed_vars; { - register int i; - register BUCKET_CONTENTS *bucket; - - for (i = 0; i < hashed_vars->nbuckets; i++) - { - bucket = hashed_vars->bucket_array[i]; - - while (bucket) - { - BUCKET_CONTENTS *temp = bucket; - SHELL_VAR *var, *prev; - - bucket = bucket->next; - - var = (SHELL_VAR *)temp->data; - - while (var) - { - prev = var->prev_context; - dispose_variable (var); - - var = prev; - } - - free (temp->key); - free (temp); - } - hashed_vars->bucket_array[i] = (BUCKET_CONTENTS *)NULL; - } + flush_hash_table (hashed_vars, free_variable_hash_data); } static SHELL_VAR * @@ -1214,8 +1652,9 @@ bind_function (name, value) char *name; COMMAND *value; { - SHELL_VAR *entry = find_function (name); + SHELL_VAR *entry; + entry = find_function (name); if (!entry) { BUCKET_CONTENTS *elt; @@ -1224,8 +1663,7 @@ bind_function (name, value) elt->data = (char *)new_shell_variable (name); entry = (SHELL_VAR *)elt->data; - entry->dynamic_value = (DYNAMIC_FUNC *)NULL; - entry->assign_func = (DYNAMIC_FUNC *)NULL; + entry->dynamic_value = entry->assign_func = (DYNAMIC_FUNC *)NULL; /* Functions are always made at the top level. This allows a function to define another function (like autoload). */ @@ -1235,11 +1673,7 @@ bind_function (name, value) if (entry->value) dispose_command ((COMMAND *)entry->value); - if (value) /* I don't think this can happen anymore */ - entry->value = (char *)copy_command (value); - else - entry->value = (char *)NULL; - + entry->value = value ? (char *)copy_command (value) : (char *)NULL; entry->attributes |= att_function; if (mark_modified_vars) @@ -1247,7 +1681,8 @@ bind_function (name, value) entry->attributes &= ~att_invisible; /* Just to be sure */ - array_needs_making = 1; + if (exported_p (entry)) + array_needs_making = 1; return (entry); } @@ -1267,9 +1702,13 @@ copy_variable (var) copy->name = savestring (var->name); if (function_p (var)) - copy->value = (char *)copy_command ((COMMAND *)var->value); - else if (var->value) - copy->value = savestring (var->value); + copy->value = (char *)copy_command (function_cell (var)); +#if defined (ARRAY_VARS) + else if (array_p (var)) + copy->value = (char *)dup_array (array_cell (var)); +#endif + else if (value_cell (var)) + copy->value = savestring (value_cell (var)); else copy->value = (char *)NULL; @@ -1284,24 +1723,31 @@ copy_variable (var) return (copy); } -/* Make the variable associated with NAME be read-only. +#define FIND_OR_MAKE_VARIABLE(name, entry) \ + do \ + { \ + entry = find_variable (name); \ + if (!entry) \ + { \ + entry = bind_variable (name, ""); \ + if (!no_invisible_vars) entry->attributes |= att_invisible; \ + } \ + } \ + while (0) + +/* Make the variable associated with NAME be readonly. If NAME does not exist yet, create it. */ void set_var_read_only (name) char *name; { - SHELL_VAR *entry = find_variable (name); + SHELL_VAR *entry; - if (!entry) - { - entry = bind_variable (name, ""); - if (!no_invisible_vars) - entry->attributes |= att_invisible; - } + FIND_OR_MAKE_VARIABLE (name, entry); entry->attributes |= att_readonly; } -/* Make the function associated with NAME be read-only. +/* Make the function associated with NAME be readonly. If NAME does not exist, we just punt, like auto_export code below. */ void set_func_read_only (name) @@ -1319,15 +1765,9 @@ void set_var_auto_export (name) char *name; { - SHELL_VAR *entry = find_variable (name); - - if (!entry) - { - entry = bind_variable (name, ""); - if (!no_invisible_vars) - entry->attributes |= att_invisible; - } + SHELL_VAR *entry; + FIND_OR_MAKE_VARIABLE (name, entry); set_auto_export (entry); } @@ -1336,25 +1776,45 @@ void set_func_auto_export (name) char *name; { - SHELL_VAR *entry = find_function (name); + SHELL_VAR *entry; + entry = find_function (name); if (entry) + set_auto_export (entry); +} + +#if defined (ARRAY_VARS) +/* This function assumes s[i] == '['; returns with s[ret] == ']' if + an array subscript is correctly parsed. */ +int +skipsubscript (s, i) + char *s; + int i; +{ + int count, c; + + for (count = 1; count && (c = s[++i]); ) { - entry->attributes |= att_exported; - array_needs_making = 1; + if (c == '[') + count++; + else if (c == ']') + count--; } + return i; } +#endif /* ARRAY_VARS */ /* Returns non-zero if STRING is an assignment statement. The returned value is the index of the `=' sign. */ +int assignment (string) char *string; { - register int c, indx = 0; + register int c, newi, indx; - c = string[indx]; + c = string[indx = 0]; - if (!isletter (c) && c != '_') + if (legal_variable_starter (c) == 0) return (0); while (c = string[indx]) @@ -1364,7 +1824,19 @@ assignment (string) if (c == '=') return (indx); - if (!isletter (c) && !digit (c) && c != '_') +#if defined (ARRAY_VARS) + if (c == '[') + { + newi = skipsubscript (string, indx); + if (string[newi++] != ']') + return (0); + return ((string[newi] == '=') ? newi : 0); + } +#endif /* ARRAY_VARS */ + + /* Variable names in assignment statements may contain only letters, + digits, and `_'. */ + if (legal_variable_char (c) == 0) return (0); indx++; @@ -1376,41 +1848,42 @@ static int visible_var (var) SHELL_VAR *var; { - return (!invisible_p (var)); + return (invisible_p (var) == 0); } -SHELL_VAR ** -all_visible_variables () +static SHELL_VAR ** +_visible_names (table) + HASH_TABLE *table; { SHELL_VAR **list; - list = map_over (visible_var, shell_variables); + list = map_over (visible_var, table); - if (list) + if (list && posixly_correct) sort_variables (list); return (list); } SHELL_VAR ** -all_visible_functions () +all_visible_variables () { - SHELL_VAR **list; - - list = map_over (visible_var, shell_functions); - - if (list) - sort_variables (list); + return (_visible_names (shell_variables)); +} - return (list); +SHELL_VAR ** +all_visible_functions () +{ + return (_visible_names (shell_functions)); } -/* Return non-zero if the variable VAR is visible and exported. */ +/* Return non-zero if the variable VAR is visible and exported. Array + variables cannot be exported. */ static int visible_and_exported (var) SHELL_VAR *var; { - return (!invisible_p (var) && exported_p (var)); + return (invisible_p (var) == 0 && exported_p (var)); } /* Make an array of assignment statements from the hash table @@ -1422,9 +1895,10 @@ make_var_array (hashed_vars) { register int i, list_index; register SHELL_VAR *var; - char **list = (char **)NULL; + char **list, *value; SHELL_VAR **vars; + list = (char **)NULL; vars = map_over (visible_and_exported, hashed_vars); if (!vars) @@ -1434,25 +1908,35 @@ make_var_array (hashed_vars) for (i = 0, list_index = 0; var = vars[i]; i++) { - char *value; - if (function_p (var)) - value = named_function_string - ((char *)NULL, (COMMAND *)function_cell (var), 0); + value = named_function_string ((char *)NULL, function_cell (var), 0); +#if defined (ARRAY_VARS) + else if (array_p (var)) +# if 0 + value = array_to_assignment_string (array_cell (var)); +# else + continue; /* XXX array vars cannot yet be exported */ +# endif +#endif else value = value_cell (var); if (value) { - int name_len = strlen (var->name); - int value_len = strlen (value); + int name_len, value_len; char *p; + name_len = strlen (var->name); + value_len = strlen (value); p = list[list_index] = xmalloc (2 + name_len + value_len); strcpy (p, var->name); p[name_len] = '='; strcpy (p + name_len + 1, value); list_index++; +#if defined (ARRAY_VARS) + if (array_p (var)) + free (value); +#endif } } @@ -1463,23 +1947,35 @@ make_var_array (hashed_vars) /* Add STRING to the array of foo=bar strings that we already have to add to the environment. */ +int assign_in_env (string) char *string; { - int size; - - int offset = assignment (string); - char *name = savestring (string); - char *temp, *value = (char *)NULL; + int size, offset; + char *name, *temp, *value; int nlen, vlen; + WORD_LIST *list; + SHELL_VAR *var; + + offset = assignment (string); + name = savestring (string); + value = (char *)NULL; +#define freetemp nlen if (name[offset] == '=') { - WORD_LIST *list; - name[offset] = 0; + + var = find_variable (name); + if (var && readonly_p (var)) + { + report_error ("%s: readonly variable", name); + return (0); + } temp = name + offset + 1; - temp = tilde_expand (temp); + freetemp = strchr (temp, '~') != 0; + if (freetemp) + temp = bash_tilde_expand (temp); list = expand_string_unsplit (temp, 0); value = string_list (list); @@ -1487,22 +1983,26 @@ assign_in_env (string) if (list) dispose_words (list); - free (temp); + if (freetemp) + free (temp); } - - if (!value) - value = savestring (""); +#undef freetemp nlen = strlen (name); - vlen = strlen (value); + vlen = value ? strlen (value) : 0; temp = xmalloc (2 + nlen + vlen); strcpy (temp, name); temp[nlen] = '='; - strcpy (temp + nlen + 1, value); + temp[nlen + 1] = '\0'; + if (value) + { + if (*value) + strcpy (temp + nlen + 1, value); + free (value); + } free (name); - free (value); - if (!temporary_env) + if (temporary_env == 0) { temporary_env = (char **)xmalloc (sizeof (char *)); temporary_env [0] = (char *)NULL; @@ -1512,13 +2012,13 @@ assign_in_env (string) temporary_env = (char **) xrealloc (temporary_env, (size + 2) * (sizeof (char *))); - temporary_env[size] = (temp); + temporary_env[size] = temp; temporary_env[size + 1] = (char *)NULL; array_needs_making = 1; if (echo_command_at_execute) { - /* The K*rn shell prints the `+ ' in front of assignment statements, + /* The Korn shell prints the `+ ' in front of assignment statements, so we do too. */ fprintf (stderr, "%s%s\n", indirection_level_string (), temp); fflush (stderr); @@ -1535,30 +2035,28 @@ find_name_in_env_array (name, array) char *name; char **array; { - register int i, l = strlen (name); + register int i, l; - if (!array) + if (array == 0) return ((SHELL_VAR *)NULL); - for (i = 0; array[i]; i++) + for (i = 0, l = strlen (name); array[i]; i++) { if (STREQN (array[i], name, l) && array[i][l] == '=') { SHELL_VAR *temp; + char *w; temp = new_shell_variable (name); + w = array[i] + l + 1; - if (array[i][l + 1]) - temp->value = savestring (&array[i][l + 1]); - else - temp->value = (char *) NULL; + temp->value = *w ? savestring (w) : (char *)NULL; temp->attributes = att_exported; temp->context = 0; temp->prev_context = (SHELL_VAR *)NULL; - temp->dynamic_value = (DYNAMIC_FUNC *)NULL; - temp->assign_func = (DYNAMIC_FUNC *)NULL; + temp->dynamic_value = temp->assign_func = (DYNAMIC_FUNC *)NULL; return (temp); } @@ -1631,13 +2129,40 @@ dispose_builtin_env () dispose_temporary_vars (&builtin_env); } -/* Sort ARRAY, a null terminated array of pointers to strings. */ +/* Take all of the shell variables in ENV_ARRAY and make shell variables + from them at the current variable context. */ +static void +merge_env_array (env_array) + char **env_array; +{ + register int i, l; + SHELL_VAR *temp; + char *w, *name; + + if (env_array == 0) + return; + + for (i = 0; env_array[i]; i++) + { + l = assignment (env_array[i]); + name = env_array[i]; + w = env_array[i] + l + 1; + name[l] = '\0'; + temp = bind_variable (name, w); + name[l] = '='; + } +} + void -sort_char_array (array) - char **array; +merge_temporary_env () { - qsort (array, array_len (array), sizeof (char *), - (Function *)qsort_string_compare); + merge_env_array (temporary_env); +} + +void +merge_builtin_env () +{ + merge_env_array (builtin_env); } #define ISFUNC(s, o) ((s[o + 1] == '(') && (s[o + 2] == ')')) @@ -1690,21 +2215,9 @@ maybe_make_export_env () if (export_env) free_array (export_env); -#ifdef SHADOWED_ENV - export_env = - (char **)xmalloc ((1 + array_len (shell_environment)) * sizeof (char *)); - - for (i = 0; shell_environment[i]; i++) - export_env[i] = savestring (shell_environment[i]); - export_env[i] = (char *)NULL; - -#else /* !SHADOWED_ENV */ - export_env = (char **)xmalloc (sizeof (char *)); export_env[0] = (char *)NULL; -#endif /* SHADOWED_ENV */ - temp_array = make_var_array (shell_variables); for (i = 0; temp_array && temp_array[i]; i++) export_env = add_or_supercede (temp_array[i], export_env); @@ -1723,9 +2236,11 @@ maybe_make_export_env () for (i = 0; temporary_env[i]; i++) export_env = add_or_supercede (temporary_env[i], export_env); +#if 0 /* If we changed the array, then sort it alphabetically. */ - if (temporary_env || function_env) + if (posixly_correct == 0 && (temporary_env || function_env)) sort_char_array (export_env); +#endif array_needs_making = 0; } @@ -1748,57 +2263,56 @@ put_command_name_into_env (command_name) free (dummy); } -/* We supply our own version of getenv () because we want library - routines to get the changed values of exported variables. */ +void +put_gnu_argv_flags_into_env (pid, flags_string) + int pid; + char *flags_string; +{ + char *dummy, *pbuf; + int l, fl; + + pbuf = itos (pid); + l = strlen (pbuf); + + fl = strlen (flags_string); + + dummy = xmalloc (l + fl + 30); + dummy[0] = '_'; + strcpy (dummy + 1, pbuf); + strcpy (dummy + 1 + l, "_GNU_nonoption_argv_flags_"); + dummy[l + 27] = '='; + strcpy (dummy + l + 28, flags_string); + + free (pbuf); + + export_env = add_or_supercede (dummy, export_env); + free (dummy); +} -/* The NeXT C library has getenv () defined and used in the same file. - This screws our scheme. However, Bash will run on the NeXT using - the C library getenv (), since right now the only environment variable - that we care about is HOME, and that is already defined. */ -#if !defined (NeXT) && !defined (HPOSF1) -static char *last_tempenv_value = (char *)NULL; -extern char **environ; +/* Return a string denoting what our indirection level is. */ +static char indirection_string[100]; char * -getenv (name) -#if defined (Linux) || defined (__bsdi__) || defined (convex) - const char *name; -#else - char const *name; -#endif /* !Linux */ +indirection_level_string () { - SHELL_VAR *var = find_tempenv_variable ((char *)name); + register int i, j; + char *ps4; - if (var) - { - FREE (last_tempenv_value); + indirection_string[0] = '\0'; + ps4 = get_string_value ("PS4"); - last_tempenv_value = savestring (value_cell (var)); - dispose_variable (var); - return (last_tempenv_value); - } - else if (shell_variables) - { - var = find_variable ((char *)name); - if (var && exported_p (var)) - return (value_cell (var)); - } - else - { - register int i, len = strlen (name); + if (ps4 == 0 || *ps4 == '\0') + return (indirection_string); - /* In some cases, s5r3 invokes getenv() before main(); BSD systems - using gprof also exhibit this behavior. This means that - shell_variables will be 0 when this is invoked. We look up the - variable in the real environment in that case. */ + ps4 = decode_prompt_string (ps4); - for (i = 0; environ[i]; i++) - { - if ((STREQN (environ[i], name, len)) && (environ[i][len] == '=')) - return (environ[i] + len + 1); - } - } + for (i = 0; *ps4 && i < indirection_level && i < 99; i++) + indirection_string[i] = *ps4; + + for (j = 1; *ps4 && ps4[j] && i < 99; i++, j++) + indirection_string[i] = ps4[j]; - return ((char *)NULL); + indirection_string[i] = '\0'; + free (ps4); + return (indirection_string); } -#endif /* !NeXT && !HPOSF1 */ diff --git a/variables.h b/variables.h index 8f4ef3e..cdeed92 100644 --- a/variables.h +++ b/variables.h @@ -4,9 +4,10 @@ #define _VARIABLES_H_ #include "stdc.h" +#include "array.h" /* Shell variables and functions are stored in hash tables. */ -#include "hash.h" +#include "hashlib.h" /* What a shell variable looks like. */ @@ -28,25 +29,33 @@ typedef struct variable { /* The various attributes that a given variable can have. We only reserve one byte of the INT. */ -#define att_exported 0x01 /* %00000001 (export to environment) */ -#define att_readonly 0x02 /* %00000010 (cannot change) */ -#define att_invisible 0x04 /* %00000100 (cannot see) */ -#define att_array 0x08 /* %00001000 (value is an array) */ -#define att_nounset 0x10 /* %00010000 (cannot unset) */ -#define att_function 0x20 /* %00100000 (value is a function) */ -#define att_integer 0x40 /* %01000000 (internal rep. is int) */ -#define att_imported 0x80 /* %10000000 (came from environment) */ +#define att_exported 0x01 /* export to environment */ +#define att_readonly 0x02 /* cannot change */ +#define att_invisible 0x04 /* cannot see */ +#define att_array 0x08 /* value is an array */ +#define att_nounset 0x10 /* cannot unset */ +#define att_function 0x20 /* value is a function */ +#define att_integer 0x40 /* internal representation is int */ +#define att_imported 0x80 /* came from environment */ +#define att_local 0x100 /* variable is local to a function */ #define exported_p(var) ((((var)->attributes) & (att_exported))) #define readonly_p(var) ((((var)->attributes) & (att_readonly))) #define invisible_p(var) ((((var)->attributes) & (att_invisible))) #define array_p(var) ((((var)->attributes) & (att_array))) +#define non_unsettable_p(var) ((((var)->attributes) & (att_nounset))) #define function_p(var) ((((var)->attributes) & (att_function))) #define integer_p(var) ((((var)->attributes) & (att_integer))) #define imported_p(var) ((((var)->attributes) & (att_imported))) +#define local_p(var) ((((var)->attributes) & (att_local))) #define value_cell(var) ((var)->value) #define function_cell(var) (COMMAND *)((var)->value) +#define array_cell(var) ((ARRAY *)(var)->value) + +#define SETVARATTR(var, attr, undo) \ + ((undo == 0) ? ((var)->attributes |= (attribute)) \ + : ((var)->attributes &= ~(attribute))) /* Stuff for hacking variables. */ extern int variable_context; @@ -55,14 +64,15 @@ extern char *dollar_vars[]; extern char **export_env; extern char **non_unsettable_vars; -extern void initialize_shell_variables __P((char **)); +extern void initialize_shell_variables __P((char **, int)); +extern SHELL_VAR *set_if_not __P((char *, char *)); +extern void set_lines_and_columns __P((int, int)); extern SHELL_VAR *find_function __P((char *)); extern SHELL_VAR *find_variable __P((char *)); extern SHELL_VAR *find_variable_internal __P((char *, int)); extern SHELL_VAR *find_tempenv_variable __P((char *)); extern SHELL_VAR *copy_variable __P((SHELL_VAR *)); -extern SHELL_VAR *set_if_not __P((char *, char *)); extern SHELL_VAR *make_local_variable __P((char *)); extern SHELL_VAR *bind_variable __P((char *, char *)); extern SHELL_VAR *bind_function __P((char *, COMMAND *)); @@ -76,6 +86,7 @@ extern char **make_var_array __P((HASH_TABLE *)); extern char **add_or_supercede __P((char *, char **)); extern char *get_string_value __P((char *)); +extern char *make_variable_value __P((SHELL_VAR *, char *)); extern int assignment __P((char *)); extern int variable_in_context __P((SHELL_VAR *)); @@ -88,21 +99,38 @@ extern void delete_all_variables __P((HASH_TABLE *)); extern void adjust_shell_level __P((int)); extern void non_unsettable __P((char *)); extern void dispose_variable __P((SHELL_VAR *)); +extern void dispose_used_env_vars __P((void)); extern void dispose_function_env __P((void)); extern void dispose_builtin_env __P((void)); -extern void dispose_used_env_vars __P((void)); +extern void merge_temporary_env __P((void)); +extern void merge_builtin_env __P((void)); extern void kill_all_local_variables __P((void)); extern void set_var_read_only __P((char *)); extern void set_func_read_only __P((char *)); extern void set_var_auto_export __P((char *)); extern void set_func_auto_export __P((char *)); -extern void sort_char_array __P((char **)); extern void sort_variables __P((SHELL_VAR **)); extern void maybe_make_export_env __P((void)); extern void put_command_name_into_env __P((char *)); +extern void put_gnu_argv_flags_into_env __P((int, char *)); extern void print_var_list __P((SHELL_VAR **)); extern void print_assignment __P((SHELL_VAR *)); -extern void print_var_value __P((SHELL_VAR *)); +extern void print_var_value __P((SHELL_VAR *, int)); extern void print_var_function __P((SHELL_VAR *)); +extern char *indirection_level_string __P((void)); + +#if defined (ARRAY_VARS) +extern SHELL_VAR *make_new_array_variable __P((char *)); +extern SHELL_VAR *make_local_array_variable __P((char *)); +extern SHELL_VAR *convert_var_to_array __P((SHELL_VAR *)); +extern SHELL_VAR *bind_array_variable __P((char *, int, char *)); +extern SHELL_VAR *assign_array_from_string __P((char *, char *)); +extern SHELL_VAR *assign_array_var_from_word_list __P((SHELL_VAR *, WORD_LIST *)); +extern SHELL_VAR *assign_array_var_from_string __P((SHELL_VAR *, char *)); +extern int unbind_array_element __P((SHELL_VAR *, char *)); +extern int skipsubscript __P((char *, int)); +extern void print_array_assignment __P((SHELL_VAR *, int)); +#endif + #endif /* !_VARIABLES_H_ */ diff --git a/version.c b/version.c index 8ba1db7..e230620 100644 --- a/version.c +++ b/version.c @@ -18,9 +18,50 @@ with Bash; see the file COPYING. If not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include + #include "version.h" +extern char *shell_name; + +/* Defines from version.h */ char *dist_version = DISTVERSION; int patch_level = PATCHLEVEL; int build_version = BUILDVERSION; +#ifdef RELSTATUS +char *release_status = RELSTATUS; +#else +char *release_status = (char *)0; +#endif char *sccs_version = SCCSVERSION; + +/* Functions for getting, setting, and displaying the shell version. */ + +/* Give version information about this shell. */ +char * +shell_version_string () +{ + static char tt[32] = { '\0' }; + + if (tt[0] == '\0') + { + if (release_status) + sprintf (tt, "%s.%d(%d)-%s", dist_version, patch_level, build_version, release_status); + else + sprintf (tt, "%s.%d(%d)", dist_version, patch_level, build_version); + } + return tt; +} + +#if !defined (MACHTYPE) +# define MACHTYPE "unknown" +#endif + +void +show_shell_version (extended) + int extended; +{ + printf ("GNU bash, version %s (%s)\n", shell_version_string (), MACHTYPE); + if (extended) + printf ("Copyright 1996 Free Software Foundation, Inc.\n"); +} diff --git a/vprint.c b/vprint.c index 9907936..431d686 100644 --- a/vprint.c +++ b/vprint.c @@ -18,11 +18,15 @@ 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, 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include "config.h" + +#if defined (USE_VFPRINTF_EMULATION) + #include #if !defined (NULL) # if defined (__STDC__) -# define NULL ((void *)0) +# define NULL ((void *)0) # else # define NULL 0x0 # endif /* __STDC__ */ @@ -78,3 +82,4 @@ vsprintf (str, fmt, ap) *f._ptr = 0; return (len); } +#endif /* USE_VFPRINTF_EMULATION */ diff --git a/xmalloc.c b/xmalloc.c new file mode 100644 index 0000000..743d4b3 --- /dev/null +++ b/xmalloc.c @@ -0,0 +1,119 @@ +/* xmalloc.c -- safe versions of malloc and realloc */ + +/* Copyright (C) 1991 Free Software Foundation, Inc. + + This file is part of GNU Readline, a library for reading lines + of text with interactive input and history editing. + + Readline is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 1, or (at your option) any + later version. + + Readline is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Readline; see the file COPYING. If not, write to the Free + Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#if defined (HAVE_CONFIG_H) +#include +#endif + +#include +#include + +#if defined (HAVE_UNISTD_H) +# include +#endif + +#if defined (HAVE_STDLIB_H) +# include +#else +# include "ansi_stdlib.h" +#endif /* HAVE_STDLIB_H */ + +#include "error.h" + +#if !defined (PTR_T) +# if defined (__STDC__) +# define PTR_T void * +# else +# define PTR_T char * +# endif /* !__STDC__ */ +#endif /* !PTR_T */ + +#if !defined (SBRK_DECLARED) +extern char *sbrk(); +#endif + +static PTR_T lbreak; +static int brkfound; +static size_t allocated; + +/* **************************************************************** */ +/* */ +/* Memory Allocation and Deallocation. */ +/* */ +/* **************************************************************** */ + +/* Return a pointer to free()able block of memory large enough + to hold BYTES number of bytes. If the memory cannot be allocated, + print an error message and abort. */ +char * +xmalloc (bytes) + size_t bytes; +{ + char *temp; + + temp = (char *)malloc (bytes); + + if (temp == 0) + { + if (brkfound == 0) + { + lbreak = (PTR_T)sbrk (0); + brkfound++; + } + allocated = (char *)sbrk (0) - (char *)lbreak; + fatal_error ("xmalloc: cannot allocate %lu bytes (%lu bytes allocated)", (unsigned long)bytes, (unsigned long)allocated); + } + + return (temp); +} + +char * +xrealloc (pointer, bytes) + PTR_T pointer; + size_t bytes; +{ + char *temp; + + temp = pointer ? (char *)realloc (pointer, bytes) : (char *)malloc (bytes); + + if (temp == 0) + { + if (brkfound == 0) + { + lbreak = (PTR_T)sbrk (0); + brkfound++; + } + allocated = (char *)sbrk (0) - (char *)lbreak; + fatal_error ("xrealloc: cannot reallocate %lu bytes (%lu bytes allocated)", (unsigned long)bytes, (unsigned long)allocated); + } + + return (temp); +} + +/* Use this as the function to call when adding unwind protects so we + don't need to know what free() returns. */ +void +xfree (string) + char *string; +{ + if (string) + free (string); +} diff --git a/y.tab.c b/y.tab.c index 0b1fd09..406b32e 100644 --- a/y.tab.c +++ b/y.tab.c @@ -21,33 +21,54 @@ #define FUNCTION 271 #define IN 272 #define BANG 273 -#define WORD 274 -#define ASSIGNMENT_WORD 275 -#define NUMBER 276 -#define AND_AND 277 -#define OR_OR 278 -#define GREATER_GREATER 279 -#define LESS_LESS 280 -#define LESS_AND 281 -#define GREATER_AND 282 -#define SEMI_SEMI 283 -#define LESS_LESS_MINUS 284 -#define AND_GREATER 285 -#define LESS_GREATER 286 -#define GREATER_BAR 287 -#define yacc_EOF 288 +#define TIME 274 +#define TIMEOPT 275 +#define WORD 276 +#define ASSIGNMENT_WORD 277 +#define NUMBER 278 +#define AND_AND 279 +#define OR_OR 280 +#define GREATER_GREATER 281 +#define LESS_LESS 282 +#define LESS_AND 283 +#define GREATER_AND 284 +#define SEMI_SEMI 285 +#define LESS_LESS_MINUS 286 +#define AND_GREATER 287 +#define LESS_GREATER 288 +#define GREATER_BAR 289 +#define yacc_EOF 290 #line 21 "./parse.y" -#include +#include "config.h" + #include "bashtypes.h" -#include #include "bashansi.h" + +#if defined (HAVE_UNISTD_H) +# include +#endif + +#if defined (HAVE_LOCALE_H) +# include +#endif + +#include +#include + +#include "memalloc.h" + #include "shell.h" +#include "trap.h" #include "flags.h" -#include "input.h" +#include "parser.h" +#include "mailcheck.h" +#include "builtins/common.h" +#include "builtins/builtext.h" #if defined (READLINE) +# include "bashline.h" # include #endif /* READLINE */ @@ -70,19 +91,24 @@ #include "maxpath.h" #endif /* PROMPT_STRING_DECODE */ -#define YYDEBUG 1 +#define RE_READ_TOKEN -99 +#define NO_EXPANSION -100 + +#define YYDEBUG 0 + extern int eof_encountered; -extern int no_line_editing; +extern int no_line_editing, running_under_emacs; extern int current_command_number; extern int interactive, interactive_shell, login_shell; +extern int sourcelevel; extern int posixly_correct; extern int last_command_exit_value; extern int interrupt_immediately; extern char *shell_name, *current_host_name; +extern char *dist_version; +extern int patch_level; +extern int dump_translatable_strings; extern Function *last_shell_builtin, *this_shell_builtin; -#if defined (READLINE) -extern int bash_readline_initialized; -#endif #if defined (BUFFERED_INPUT) extern int bash_input_fd_changed; #endif @@ -93,12 +119,13 @@ extern int bash_input_fd_changed; /* */ /* **************************************************************** */ -/* This is kind of sickening. In order to let these variables be seen by - all the functions that need them, I am forced to place their declarations - far away from the place where they should logically be found. */ - +static char *ansiexpand (); +static char *localeexpand (); static int reserved_word_acceptable (); static int read_token (); +static int yylex (); +static int read_token_word (); +static void discard_parser_constructs (); static void report_syntax_error (); static void handle_eof_input_unit (); @@ -106,6 +133,10 @@ static void prompt_again (); static void reset_readline_prompt (); static void print_prompt (); +/* Default prompt strings */ +char *primary_prompt = PPROMPT; +char *secondary_prompt = SPROMPT; + /* PROMPT_STRING_POINTER points to one of these, never to an actual string. */ char *ps1_prompt, *ps2_prompt; @@ -114,31 +145,46 @@ char *ps1_prompt, *ps2_prompt; char **prompt_string_pointer = (char **)NULL; char *current_prompt_string; +/* Non-zero means we expand aliases in commands. */ +int expand_aliases = 0; + +/* If non-zero, the decoded prompt string undergoes parameter and + variable substitution, command substitution, arithmetic substitution, + string expansion, process substitution, and quote removal in + decode_prompt_string. */ +int promptvars = 1; + /* The decoded prompt string. Used if READLINE is not defined or if editing is turned off. Analogous to current_readline_prompt. */ static char *current_decoded_prompt; /* The number of lines read from input while creating the current command. */ -int current_command_line_count = 0; +int current_command_line_count; /* Variables to manage the task of reading here documents, because we need to defer the reading until after a complete command has been collected. */ static REDIRECT *redir_stack[10]; -int need_here_doc = 0; +int need_here_doc; /* Where shell input comes from. History expansion is performed on each line when the shell is interactive. */ static char *shell_input_line = (char *)NULL; -static int shell_input_line_index = 0; -static int shell_input_line_size = 0; /* Amount allocated for shell_input_line. */ -static int shell_input_line_len = 0; /* strlen (shell_input_line) */ +static int shell_input_line_index; +static int shell_input_line_size; /* Amount allocated for shell_input_line. */ +static int shell_input_line_len; /* strlen (shell_input_line) */ /* Either zero or EOF. */ -static int shell_input_line_terminator = 0; +static int shell_input_line_terminator; + +/* The line number in a script on which a function definition starts. */ +static int function_dstart; + +/* The line number in a script on which a function body starts. */ +static int function_bstart; static REDIRECTEE redir; -#line 122 "./parse.y" +#line 166 "./parse.y" typedef union { WORD_DESC *word; /* the word that we read. */ int number; /* the number that we read. */ @@ -158,26 +204,26 @@ typedef union { -#define YYFINAL 258 +#define YYFINAL 263 #define YYFLAG -32768 -#define YYNTBASE 45 +#define YYNTBASE 47 -#define YYTRANSLATE(x) ((unsigned)(x) <= 288 ? yytranslate[x] : 73) +#define YYTRANSLATE(x) ((unsigned)(x) <= 290 ? yytranslate[x] : 78) static const char yytranslate[] = { 0, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 35, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 37, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 33, 2, 43, - 44, 2, 2, 2, 40, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 34, 39, - 2, 38, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 35, 2, 45, + 46, 2, 2, 2, 42, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 36, 41, + 2, 40, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 41, 37, 42, 2, 2, 2, 2, 2, + 2, 2, 43, 39, 44, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, @@ -193,99 +239,97 @@ static const char yytranslate[] = { 0, 2, 2, 2, 2, 2, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, - 26, 27, 28, 29, 30, 31, 32, 36 + 26, 27, 28, 29, 30, 31, 32, 33, 34, 38 }; #if YYDEBUG != 0 static const short yyprhs[] = { 0, - 0, 3, 5, 8, 10, 11, 14, 17, 20, 24, - 28, 31, 35, 38, 42, 45, 49, 52, 56, 59, - 63, 66, 70, 73, 77, 80, 84, 87, 91, 94, - 98, 101, 104, 108, 110, 112, 114, 116, 119, 121, - 124, 126, 128, 130, 133, 140, 147, 155, 163, 174, - 185, 192, 200, 207, 213, 219, 221, 223, 225, 227, - 229, 236, 243, 251, 259, 270, 281, 287, 294, 301, - 309, 314, 320, 324, 330, 338, 345, 349, 354, 361, - 367, 369, 372, 377, 382, 388, 394, 396, 399, 405, - 411, 418, 425, 427, 431, 434, 436, 440, 444, 448, - 453, 458, 463, 468, 473, 475, 478, 480, 482, 484, - 485, 488, 490, 493, 496, 501, 506, 510, 514, 516, - 519, 524 + 0, 3, 5, 8, 10, 12, 15, 18, 21, 25, + 29, 32, 36, 39, 43, 46, 50, 53, 57, 60, + 64, 67, 71, 74, 78, 81, 85, 88, 92, 95, + 99, 102, 105, 109, 111, 113, 115, 117, 120, 122, + 125, 127, 129, 132, 134, 136, 142, 148, 150, 152, + 154, 156, 158, 165, 172, 180, 188, 199, 210, 217, + 224, 232, 240, 251, 262, 269, 277, 284, 290, 297, + 302, 306, 312, 320, 327, 331, 336, 343, 349, 351, + 354, 359, 364, 370, 376, 379, 383, 385, 389, 392, + 394, 397, 401, 405, 409, 414, 419, 424, 429, 434, + 436, 438, 440, 442, 443, 446, 448, 451, 454, 459, + 464, 468, 472, 474, 476, 479, 482, 486, 490, 495, + 497, 499 }; -static const short yyrhs[] = { 70, - 35, 0, 35, 0, 1, 35, 0, 36, 0, 0, - 46, 19, 0, 38, 19, 0, 39, 19, 0, 21, - 38, 19, 0, 21, 39, 19, 0, 24, 19, 0, - 21, 24, 19, 0, 25, 19, 0, 21, 25, 19, - 0, 26, 21, 0, 21, 26, 21, 0, 27, 21, - 0, 21, 27, 21, 0, 26, 19, 0, 21, 26, - 19, 0, 27, 19, 0, 21, 27, 19, 0, 29, - 19, 0, 21, 29, 19, 0, 27, 40, 0, 21, - 27, 40, 0, 26, 40, 0, 21, 26, 40, 0, - 30, 19, 0, 21, 31, 19, 0, 31, 19, 0, - 32, 19, 0, 21, 32, 19, 0, 19, 0, 20, - 0, 47, 0, 47, 0, 49, 47, 0, 48, 0, - 50, 48, 0, 50, 0, 52, 0, 53, 0, 53, - 49, 0, 10, 19, 69, 14, 65, 15, 0, 10, - 19, 69, 41, 65, 42, 0, 10, 19, 34, 69, - 14, 65, 15, 0, 10, 19, 34, 69, 41, 65, - 42, 0, 10, 19, 69, 17, 46, 68, 69, 14, - 65, 15, 0, 10, 19, 69, 17, 46, 68, 69, - 41, 65, 42, 0, 8, 19, 69, 17, 69, 9, - 0, 8, 19, 69, 17, 62, 69, 9, 0, 8, - 19, 69, 17, 60, 9, 0, 12, 65, 14, 65, - 15, 0, 13, 65, 14, 65, 15, 0, 54, 0, - 57, 0, 56, 0, 58, 0, 55, 0, 11, 19, - 69, 14, 65, 15, 0, 11, 19, 69, 41, 65, - 42, 0, 11, 19, 34, 69, 14, 65, 15, 0, - 11, 19, 34, 69, 41, 65, 42, 0, 11, 19, - 69, 17, 46, 68, 69, 14, 65, 15, 0, 11, - 19, 69, 17, 46, 68, 69, 41, 65, 42, 0, - 19, 43, 44, 69, 58, 0, 19, 43, 44, 69, - 58, 49, 0, 16, 19, 43, 44, 69, 58, 0, - 16, 19, 43, 44, 69, 58, 49, 0, 16, 19, - 69, 58, 0, 16, 19, 69, 58, 49, 0, 43, - 65, 44, 0, 3, 65, 4, 65, 7, 0, 3, - 65, 4, 65, 5, 65, 7, 0, 3, 65, 4, - 65, 59, 7, 0, 41, 65, 42, 0, 6, 65, - 4, 65, 0, 6, 65, 4, 65, 5, 65, 0, - 6, 65, 4, 65, 59, 0, 61, 0, 62, 61, - 0, 69, 64, 44, 65, 0, 69, 64, 44, 69, - 0, 69, 43, 64, 44, 65, 0, 69, 43, 64, - 44, 69, 0, 63, 0, 62, 63, 0, 69, 64, - 44, 65, 28, 0, 69, 64, 44, 69, 28, 0, - 69, 43, 64, 44, 65, 28, 0, 69, 43, 64, - 44, 69, 28, 0, 19, 0, 64, 37, 19, 0, - 69, 66, 0, 67, 0, 67, 35, 69, 0, 67, - 33, 69, 0, 67, 34, 69, 0, 67, 22, 69, - 67, 0, 67, 23, 69, 67, 0, 67, 33, 69, - 67, 0, 67, 34, 69, 67, 0, 67, 35, 69, - 67, 0, 72, 0, 18, 72, 0, 35, 0, 34, - 0, 36, 0, 0, 69, 35, 0, 71, 0, 71, - 33, 0, 71, 34, 0, 71, 22, 69, 71, 0, - 71, 23, 69, 71, 0, 71, 33, 71, 0, 71, - 34, 71, 0, 72, 0, 18, 72, 0, 72, 37, - 69, 72, 0, 51, 0 +static const short yyrhs[] = { 73, + 37, 0, 37, 0, 1, 37, 0, 38, 0, 21, + 0, 48, 21, 0, 40, 21, 0, 41, 21, 0, + 23, 40, 21, 0, 23, 41, 21, 0, 26, 21, + 0, 23, 26, 21, 0, 27, 21, 0, 23, 27, + 21, 0, 28, 23, 0, 23, 28, 23, 0, 29, + 23, 0, 23, 29, 23, 0, 28, 21, 0, 23, + 28, 21, 0, 29, 21, 0, 23, 29, 21, 0, + 31, 21, 0, 23, 31, 21, 0, 29, 42, 0, + 23, 29, 42, 0, 28, 42, 0, 23, 28, 42, + 0, 32, 21, 0, 23, 33, 21, 0, 33, 21, + 0, 34, 21, 0, 23, 34, 21, 0, 21, 0, + 22, 0, 49, 0, 49, 0, 51, 49, 0, 50, + 0, 52, 50, 0, 52, 0, 54, 0, 54, 51, + 0, 55, 0, 57, 0, 12, 68, 14, 68, 15, + 0, 13, 68, 14, 68, 15, 0, 56, 0, 60, + 0, 59, 0, 61, 0, 58, 0, 10, 21, 72, + 14, 67, 15, 0, 10, 21, 72, 43, 67, 44, + 0, 10, 21, 36, 72, 14, 67, 15, 0, 10, + 21, 36, 72, 43, 67, 44, 0, 10, 21, 72, + 17, 48, 71, 72, 14, 67, 15, 0, 10, 21, + 72, 17, 48, 71, 72, 43, 67, 44, 0, 11, + 21, 72, 14, 67, 15, 0, 11, 21, 72, 43, + 67, 44, 0, 11, 21, 36, 72, 14, 67, 15, + 0, 11, 21, 36, 72, 43, 67, 44, 0, 11, + 21, 72, 17, 48, 71, 72, 14, 67, 15, 0, + 11, 21, 72, 17, 48, 71, 72, 43, 67, 44, + 0, 8, 21, 72, 17, 72, 9, 0, 8, 21, + 72, 17, 65, 72, 9, 0, 8, 21, 72, 17, + 63, 9, 0, 21, 45, 46, 72, 61, 0, 16, + 21, 45, 46, 72, 61, 0, 16, 21, 72, 61, + 0, 45, 68, 46, 0, 3, 68, 4, 68, 7, + 0, 3, 68, 4, 68, 5, 68, 7, 0, 3, + 68, 4, 68, 62, 7, 0, 43, 67, 44, 0, + 6, 68, 4, 68, 0, 6, 68, 4, 68, 5, + 68, 0, 6, 68, 4, 68, 62, 0, 64, 0, + 65, 64, 0, 72, 66, 46, 68, 0, 72, 66, + 46, 72, 0, 72, 45, 66, 46, 68, 0, 72, + 45, 66, 46, 72, 0, 64, 30, 0, 65, 64, + 30, 0, 21, 0, 66, 39, 21, 0, 72, 69, + 0, 67, 0, 72, 70, 0, 70, 37, 72, 0, + 70, 35, 72, 0, 70, 36, 72, 0, 70, 24, + 72, 70, 0, 70, 25, 72, 70, 0, 70, 35, + 72, 70, 0, 70, 36, 72, 70, 0, 70, 37, + 72, 70, 0, 75, 0, 37, 0, 36, 0, 38, + 0, 0, 72, 37, 0, 74, 0, 74, 35, 0, + 74, 36, 0, 74, 24, 72, 74, 0, 74, 25, + 72, 74, 0, 74, 35, 74, 0, 74, 36, 74, + 0, 75, 0, 76, 0, 18, 76, 0, 77, 76, + 0, 77, 18, 76, 0, 18, 77, 76, 0, 76, + 39, 72, 76, 0, 53, 0, 19, 0, 19, 20, + 0 }; #endif #if YYDEBUG != 0 static const short yyrline[] = { 0, - 163, 172, 179, 195, 205, 207, 211, 216, 221, 226, - 231, 236, 241, 247, 253, 258, 263, 268, 273, 278, - 283, 288, 293, 300, 307, 312, 317, 322, 327, 332, - 337, 353, 358, 365, 367, 369, 373, 377, 388, 390, - 394, 396, 400, 402, 417, 419, 421, 423, 425, 427, - 430, 432, 434, 436, 438, 440, 442, 444, 446, 448, - 452, 458, 464, 470, 476, 482, 490, 493, 496, 499, - 502, 505, 509, 513, 515, 517, 522, 526, 528, 530, - 534, 535, 539, 541, 543, 545, 549, 550, 554, 556, - 558, 560, 564, 566, 575, 583, 584, 585, 592, 596, - 598, 600, 607, 609, 611, 613, 620, 621, 622, 625, - 626, 635, 641, 650, 658, 660, 662, 669, 671, 673, - 680, 683 + 209, 218, 225, 240, 250, 252, 256, 261, 266, 271, + 276, 281, 286, 292, 298, 303, 308, 313, 318, 323, + 328, 333, 338, 345, 352, 357, 362, 367, 372, 377, + 382, 387, 392, 399, 401, 403, 407, 411, 422, 424, + 428, 430, 432, 461, 463, 465, 467, 469, 471, 473, + 475, 477, 481, 483, 485, 487, 489, 491, 495, 499, + 503, 507, 511, 515, 521, 523, 525, 529, 533, 536, + 540, 544, 546, 548, 553, 557, 559, 561, 565, 566, + 570, 572, 574, 576, 580, 581, 585, 587, 596, 604, + 605, 611, 612, 619, 623, 625, 627, 634, 636, 638, + 642, 643, 644, 647, 648, 657, 663, 672, 680, 682, + 684, 691, 694, 698, 700, 705, 710, 715, 722, 725, + 729, 731 }; #endif @@ -294,236 +338,238 @@ static const short yyrline[] = { 0, static const char * const yytname[] = { "$","error","$undefined.","IF","THEN", "ELSE","ELIF","FI","CASE","ESAC","FOR","SELECT","WHILE","UNTIL","DO","DONE", -"FUNCTION","IN","BANG","WORD","ASSIGNMENT_WORD","NUMBER","AND_AND","OR_OR","GREATER_GREATER", -"LESS_LESS","LESS_AND","GREATER_AND","SEMI_SEMI","LESS_LESS_MINUS","AND_GREATER", -"LESS_GREATER","GREATER_BAR","'&'","';'","'\\n'","yacc_EOF","'|'","'>'","'<'", -"'-'","'{'","'}'","'('","')'","inputunit","words","redirection","simple_command_element", -"redirections","simple_command","command","shell_command","shell_command_1", -"select_command","function_def","subshell","if_command","group_command","elif_clause", -"case_clause_1","pattern_list_1","case_clause_sequence","pattern_list","pattern", -"list","list0","list1","list_terminator","newlines","simple_list","simple_list1", -"pipeline", NULL +"FUNCTION","IN","BANG","TIME","TIMEOPT","WORD","ASSIGNMENT_WORD","NUMBER","AND_AND", +"OR_OR","GREATER_GREATER","LESS_LESS","LESS_AND","GREATER_AND","SEMI_SEMI","LESS_LESS_MINUS", +"AND_GREATER","LESS_GREATER","GREATER_BAR","'&'","';'","'\\n'","yacc_EOF","'|'", +"'>'","'<'","'-'","'{'","'}'","'('","')'","inputunit","word_list","redirection", +"simple_command_element","redirection_list","simple_command","command","shell_command", +"for_command","select_command","case_command","function_def","subshell","if_command", +"group_command","elif_clause","case_clause","pattern_list","case_clause_sequence", +"pattern","list","compound_list","list0","list1","list_terminator","newline_list", +"simple_list","simple_list1","pipeline_command","pipeline","timespec", NULL }; #endif static const short yyr1[] = { 0, - 45, 45, 45, 45, 46, 46, 47, 47, 47, 47, - 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, - 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, - 47, 47, 47, 48, 48, 48, 49, 49, 50, 50, - 51, 51, 52, 52, 53, 53, 53, 53, 53, 53, - 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, - 54, 54, 54, 54, 54, 54, 55, 55, 55, 55, - 55, 55, 56, 57, 57, 57, 58, 59, 59, 59, - 60, 60, 61, 61, 61, 61, 62, 62, 63, 63, - 63, 63, 64, 64, 65, 66, 66, 66, 66, 67, - 67, 67, 67, 67, 67, 67, 68, 68, 68, 69, - 69, 70, 70, 70, 71, 71, 71, 71, 71, 71, - 72, 72 + 47, 47, 47, 47, 48, 48, 49, 49, 49, 49, + 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, + 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, + 49, 49, 49, 50, 50, 50, 51, 51, 52, 52, + 53, 53, 53, 54, 54, 54, 54, 54, 54, 54, + 54, 54, 55, 55, 55, 55, 55, 55, 56, 56, + 56, 56, 56, 56, 57, 57, 57, 58, 58, 58, + 59, 60, 60, 60, 61, 62, 62, 62, 63, 63, + 64, 64, 64, 64, 65, 65, 66, 66, 67, 68, + 68, 69, 69, 69, 70, 70, 70, 70, 70, 70, + 71, 71, 71, 72, 72, 73, 73, 73, 74, 74, + 74, 74, 74, 75, 75, 75, 75, 75, 76, 76, + 77, 77 }; static const short yyr2[] = { 0, - 2, 1, 2, 1, 0, 2, 2, 2, 3, 3, + 2, 1, 2, 1, 1, 2, 2, 2, 3, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 2, 3, 1, 1, 1, 1, 2, 1, 2, - 1, 1, 1, 2, 6, 6, 7, 7, 10, 10, - 6, 7, 6, 5, 5, 1, 1, 1, 1, 1, - 6, 6, 7, 7, 10, 10, 5, 6, 6, 7, - 4, 5, 3, 5, 7, 6, 3, 4, 6, 5, - 1, 2, 4, 4, 5, 5, 1, 2, 5, 5, - 6, 6, 1, 3, 2, 1, 3, 3, 3, 4, - 4, 4, 4, 4, 1, 2, 1, 1, 1, 0, - 2, 1, 2, 2, 4, 4, 3, 3, 1, 2, - 4, 1 + 1, 1, 2, 1, 1, 5, 5, 1, 1, 1, + 1, 1, 6, 6, 7, 7, 10, 10, 6, 6, + 7, 7, 10, 10, 6, 7, 6, 5, 6, 4, + 3, 5, 7, 6, 3, 4, 6, 5, 1, 2, + 4, 4, 5, 5, 2, 3, 1, 3, 2, 1, + 2, 3, 3, 3, 4, 4, 4, 4, 4, 1, + 1, 1, 1, 0, 2, 1, 2, 2, 4, 4, + 3, 3, 1, 1, 2, 2, 3, 3, 4, 1, + 1, 2 }; static const short yydefact[] = { 0, - 0, 110, 0, 0, 0, 110, 110, 0, 0, 34, - 35, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 2, 4, 0, 0, 110, 110, 36, 39, 41, 122, - 42, 43, 56, 60, 58, 57, 59, 0, 112, 119, - 3, 0, 0, 110, 110, 110, 0, 0, 110, 120, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 11, 13, 19, 15, 27, 21, 17, 25, 23, 29, - 31, 32, 7, 8, 0, 0, 34, 40, 37, 44, - 1, 110, 110, 113, 114, 110, 110, 0, 111, 95, - 96, 105, 0, 110, 0, 110, 0, 110, 110, 0, - 0, 110, 12, 14, 20, 16, 28, 22, 18, 26, - 24, 30, 33, 9, 10, 77, 73, 38, 0, 0, - 117, 118, 0, 0, 106, 110, 110, 110, 110, 110, - 110, 0, 110, 5, 110, 0, 110, 5, 110, 0, - 0, 110, 71, 0, 115, 116, 0, 0, 121, 110, - 110, 74, 0, 0, 0, 98, 99, 97, 0, 81, - 110, 87, 0, 110, 110, 0, 0, 0, 110, 110, - 0, 0, 0, 54, 55, 0, 72, 67, 0, 0, - 76, 100, 101, 102, 103, 104, 53, 82, 88, 0, - 51, 93, 0, 0, 0, 0, 45, 6, 108, 107, - 109, 110, 46, 0, 0, 61, 110, 62, 69, 68, - 75, 110, 110, 110, 110, 52, 0, 0, 110, 47, - 48, 0, 63, 64, 0, 70, 78, 0, 0, 0, - 110, 94, 83, 84, 110, 110, 110, 110, 110, 80, - 85, 86, 89, 90, 0, 0, 0, 0, 79, 91, - 92, 49, 50, 65, 66, 0, 0, 0 + 0, 104, 0, 0, 0, 104, 104, 0, 0, 121, + 34, 35, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 2, 4, 0, 0, 104, 104, 36, 39, 41, + 120, 42, 44, 48, 45, 52, 50, 49, 51, 0, + 106, 113, 114, 0, 3, 90, 0, 0, 104, 104, + 104, 0, 0, 104, 115, 0, 122, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 11, 13, 19, + 15, 27, 21, 17, 25, 23, 29, 31, 32, 7, + 8, 0, 0, 0, 34, 40, 37, 43, 1, 104, + 104, 107, 108, 104, 0, 116, 104, 105, 89, 91, + 100, 0, 104, 0, 104, 0, 104, 104, 0, 0, + 118, 104, 12, 14, 20, 16, 28, 22, 18, 26, + 24, 30, 33, 9, 10, 75, 0, 71, 38, 0, + 0, 111, 112, 0, 117, 0, 104, 104, 104, 104, + 104, 104, 0, 104, 0, 104, 0, 104, 0, 104, + 0, 0, 104, 70, 0, 109, 110, 0, 0, 119, + 104, 104, 72, 0, 0, 0, 93, 94, 92, 0, + 79, 104, 0, 104, 104, 0, 5, 0, 0, 104, + 104, 0, 0, 0, 46, 47, 0, 68, 0, 0, + 74, 95, 96, 97, 98, 99, 67, 85, 80, 0, + 65, 87, 0, 0, 0, 0, 53, 6, 102, 101, + 103, 104, 54, 0, 0, 59, 104, 60, 69, 73, + 104, 104, 104, 104, 86, 66, 0, 0, 104, 55, + 56, 0, 61, 62, 0, 76, 0, 0, 0, 104, + 88, 81, 82, 104, 104, 104, 104, 104, 78, 83, + 84, 0, 0, 0, 0, 77, 57, 58, 63, 64, + 0, 0, 0 }; -static const short yydefgoto[] = { 256, - 167, 27, 28, 80, 29, 30, 31, 32, 33, 34, - 35, 36, 37, 153, 159, 160, 161, 162, 194, 42, - 90, 91, 202, 43, 38, 121, 92 +static const short yydefgoto[] = { 261, + 178, 28, 29, 88, 30, 31, 32, 33, 34, 35, + 36, 37, 38, 39, 164, 170, 171, 172, 204, 46, + 47, 99, 100, 212, 83, 40, 132, 101, 43, 44 }; -static const short yypact[] = { 233, - -28,-32768, 2, 10, 15,-32768,-32768, 32, 437, 19, --32768, 494, 46, 52, -5, 39, 59, 61, 93, 95, --32768,-32768, 102, 103,-32768,-32768,-32768,-32768, 462,-32768, --32768, 478,-32768,-32768,-32768,-32768,-32768, 71, 116, 91, --32768, 126, 301,-32768, 117, 118, 123, 139, 89, 91, - 111, 137, 138, 75, 76, 141, 143, 146, 148, 149, +static const short yypact[] = { 246, + -19,-32768, 8, 25, 29,-32768,-32768, 33, 354, 4, + 34,-32768, 499, 46, 51, 32, 38, 56, 70, 72, + 90,-32768,-32768, 97, 101,-32768,-32768,-32768,-32768, 161, +-32768, 483,-32768,-32768,-32768,-32768,-32768,-32768,-32768, 6, + 139,-32768, 84, 390,-32768,-32768, 120, 282,-32768, 89, + 94, 112, 117, 87, 84, 462,-32768, 96, 123, 127, + 52, 55, 128, 129, 133, 137, 140,-32768,-32768,-32768, -32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768, --32768,-32768,-32768,-32768, 127, 131,-32768,-32768,-32768, 478, --32768,-32768,-32768, 369, 369,-32768,-32768, 437,-32768,-32768, - 101, 91, 37,-32768, -4,-32768, 22,-32768,-32768, 133, - -23,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768, --32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768, 335, 335, - 60, 60, 403, 98, 91,-32768,-32768,-32768,-32768,-32768, --32768, 3,-32768,-32768,-32768, 33,-32768,-32768,-32768, 167, - 172,-32768, 478, -23,-32768,-32768, 369, 369, 91,-32768, --32768,-32768, 181, 301, 301, 301, 301, 301, 186,-32768, --32768,-32768, 21,-32768,-32768, 192, 83, 168,-32768,-32768, - 194, 83, 175,-32768,-32768, -23, 478, 478, 208, 214, --32768,-32768,-32768, 87, 87, 87,-32768,-32768,-32768, 24, --32768,-32768, 200, -22, 205, 179,-32768,-32768,-32768,-32768, --32768,-32768,-32768, 207, 182,-32768,-32768,-32768, 478, 478, --32768,-32768,-32768,-32768,-32768,-32768, 29, 204,-32768,-32768, --32768, 34,-32768,-32768, 35, 478, 135, 301, 301, 301, --32768,-32768, 198, 173,-32768,-32768,-32768,-32768,-32768,-32768, - 199, 267,-32768,-32768, 213, 193, 222, 196,-32768,-32768, --32768,-32768,-32768,-32768,-32768, 239, 240,-32768 +-32768, 121, 282, 122,-32768,-32768,-32768, 483,-32768,-32768, +-32768, 318, 318,-32768, 462, 84,-32768,-32768,-32768, 92, +-32768, -10,-32768, 2,-32768, 14,-32768,-32768, 130, -28, + 84,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768, +-32768,-32768,-32768,-32768,-32768,-32768, 92,-32768,-32768, 282, + 282, 10, 10, 426, 84, 93,-32768,-32768,-32768,-32768, +-32768,-32768, 23,-32768, 148,-32768, 26,-32768, 148,-32768, + 158, 164,-32768,-32768, -28,-32768,-32768, 318, 318, 84, +-32768,-32768,-32768, 178, 282, 282, 282, 282, 282, 177, + 166,-32768, -7,-32768,-32768, 176,-32768, 83, 153,-32768, +-32768, 183, 83, 155,-32768,-32768, -28,-32768, 193, 199, +-32768,-32768,-32768, 57, 57, 57,-32768,-32768, 174, -1, +-32768,-32768, 184, -29, 191, 163,-32768,-32768,-32768,-32768, +-32768,-32768,-32768, 194, 167,-32768,-32768,-32768,-32768,-32768, +-32768,-32768,-32768,-32768,-32768,-32768, -13, 187,-32768,-32768, +-32768, 27,-32768,-32768, 28, 103, 282, 282, 282,-32768, +-32768,-32768, 282,-32768,-32768,-32768,-32768,-32768,-32768,-32768, + 282, 197, 169, 201, 170,-32768,-32768,-32768,-32768,-32768, + 217, 218,-32768 }; static const short yypgoto[] = {-32768, - 104, -30, 218, -132,-32768,-32768,-32768,-32768,-32768,-32768, --32768,-32768, -92, 28,-32768, 100,-32768, 105, 55, -6, --32768, -130, 78, -41,-32768, 6, 23 + 74, -26, 195,-32768,-32768,-32768,-32768,-32768,-32768,-32768, +-32768,-32768,-32768, -97, -12,-32768, 58,-32768, 30, -3, + 5,-32768, -82, 45, -2,-32768, 3, 22, 12, 220 }; -#define YYLAST 533 - - -static const short yytable[] = { 47, - 48, 79, 93, 95, 97, 39, 41, 101, 143, 133, - 177, 89, 134, 63, 218, 64, 164, 25, 75, 76, - 44, 219, 40, 182, 183, 184, 185, 186, 45, 191, - 89, 50, 216, 46, 65, 137, 135, 89, 138, 192, - 119, 120, 192, 165, 123, 210, 169, 235, 237, 118, - 49, 178, 132, 131, 136, 89, 89, 66, 89, 67, - 144, 51, 139, 193, 61, 218, 193, 89, 89, 89, - 62, 89, 231, 170, 236, 238, 226, 69, 68, 70, - 124, 82, 83, 209, 154, 155, 156, 157, 158, 163, - 122, 140, 141, 105, 108, 106, 109, 184, 185, 186, - 176, 198, 150, 151, 152, 81, 40, 40, 126, 127, - 125, 71, 79, 72, 107, 110, 199, 200, 201, 190, - 73, 74, 126, 127, 145, 146, 166, 86, 168, 87, - 171, 100, 173, 128, 129, 130, 98, 82, 83, 239, - 151, 40, 40, 179, 180, 149, 118, 79, 84, 85, - 94, 96, 99, 122, 102, 103, 104, 195, 196, 111, - 222, 112, 204, 205, 113, 225, 114, 115, 116, 40, - 40, 228, 229, 230, 117, 2, 142, 234, 79, 118, - 3, 174, 4, 5, 6, 7, 175, 181, 8, 242, - 88, 10, 11, 12, 187, 118, 13, 14, 15, 16, - 244, 17, 18, 19, 20, 227, 197, 89, 206, 203, - 23, 24, 233, 25, 211, 26, 208, 212, 192, 220, - 221, 223, 232, 224, 241, 243, 250, 252, 245, 246, - 247, 248, 249, 1, 253, 2, 254, 255, 257, 258, - 3, 172, 4, 5, 6, 7, 78, 217, 8, 207, - 9, 10, 11, 12, 240, 0, 13, 14, 15, 16, - 188, 17, 18, 19, 20, 189, 0, 21, 22, 2, - 23, 24, 0, 25, 3, 26, 4, 5, 6, 7, - 0, 0, 8, 0, 88, 10, 11, 12, 0, 0, - 13, 14, 15, 16, 251, 17, 18, 19, 20, 0, - 0, 89, 0, 2, 23, 24, 0, 25, 3, 26, - 4, 5, 6, 7, 0, 0, 8, 0, 88, 10, - 11, 12, 0, 0, 13, 14, 15, 16, 0, 17, - 18, 19, 20, 0, 0, 89, 0, 2, 23, 24, - 0, 25, 3, 26, 4, 5, 6, 7, 0, 0, - 8, 0, 9, 10, 11, 12, 0, 0, 13, 14, - 15, 16, 0, 17, 18, 19, 20, 0, 0, 89, - 0, 2, 23, 24, 0, 25, 3, 26, 4, 5, - 6, 7, 0, 0, 8, 0, 9, 10, 11, 12, - 0, 0, 13, 14, 15, 16, 0, 17, 18, 19, - 20, 0, 0, 0, 0, 2, 23, 24, 0, 25, - 3, 26, 4, 5, 6, 7, 0, 0, 8, 0, - 0, 10, 11, 12, 0, 0, 13, 14, 15, 16, - 0, 17, 18, 19, 20, 0, 0, 89, 0, 2, - 23, 24, 0, 25, 3, 26, 4, 5, 6, 7, - 0, 0, 8, 0, 0, 10, 11, 12, 0, 0, - 13, 14, 15, 16, 0, 17, 18, 19, 20, 0, - 0, 0, 0, 0, 23, 24, 0, 25, 0, 26, - 77, 11, 12, 0, 0, 13, 14, 15, 16, 0, - 17, 18, 19, 20, 0, 0, 0, 0, 12, 23, - 24, 13, 14, 15, 16, 0, 17, 18, 19, 20, - 0, 0, 0, 0, 0, 23, 24, 52, 53, 54, - 55, 0, 56, 0, 57, 58, 0, 0, 0, 0, - 0, 59, 60 +#define YYLAST 540 + + +static const short yytable[] = { 48, + 127, 201, 41, 48, 48, 87, 142, 226, 98, 228, + 52, 53, 154, 202, 26, 144, 229, 45, 145, 202, + 55, 42, 82, 57, 48, 228, 98, 148, 49, 98, + 149, 84, 240, 90, 91, 98, 174, 203, 98, 180, + 244, 246, 89, 203, 146, 50, 102, 104, 106, 51, + 98, 110, 70, 54, 71, 96, 150, 188, 73, 98, + 74, 129, 98, 98, 98, 175, 68, 111, 181, 245, + 247, 69, 115, 72, 116, 118, 76, 119, 58, 75, + 137, 138, 192, 193, 194, 195, 196, 130, 131, 219, + 77, 134, 78, 117, 48, 133, 120, 161, 162, 163, + 143, 136, 147, 208, 48, 48, 135, 248, 162, 155, + 79, 151, 152, 42, 42, 137, 138, 80, 209, 210, + 211, 81, 94, 97, 103, 107, 139, 140, 141, 105, + 108, 109, 156, 157, 165, 166, 167, 168, 169, 173, + 176, 112, 179, 113, 182, 160, 184, 114, 121, 122, + 187, 42, 42, 123, 194, 195, 196, 124, 48, 48, + 125, 133, 90, 91, 126, 189, 190, 128, 177, 200, + 205, 206, 185, 92, 93, 153, 214, 215, 186, 42, + 42, 85, 12, 13, 191, 197, 14, 15, 16, 17, + 207, 18, 19, 20, 21, 198, 213, 216, 218, 220, + 24, 25, 221, 225, 202, 230, 231, 241, 233, 232, + 234, 257, 258, 260, 235, 259, 262, 263, 48, 237, + 238, 239, 183, 249, 86, 236, 243, 217, 56, 199, + 0, 0, 227, 242, 0, 0, 0, 251, 0, 0, + 252, 253, 254, 255, 250, 48, 1, 0, 2, 0, + 0, 0, 256, 3, 0, 4, 5, 6, 7, 0, + 0, 8, 0, 9, 10, 0, 11, 12, 13, 0, + 0, 14, 15, 16, 17, 0, 18, 19, 20, 21, + 0, 0, 22, 23, 2, 24, 25, 0, 26, 3, + 27, 4, 5, 6, 7, 0, 0, 8, 0, 9, + 10, 0, 11, 12, 13, 0, 0, 14, 15, 16, + 17, 0, 18, 19, 20, 21, 0, 0, 98, 0, + 2, 24, 25, 0, 26, 3, 27, 4, 5, 6, + 7, 0, 0, 8, 0, 9, 10, 0, 11, 12, + 13, 0, 0, 14, 15, 16, 17, 0, 18, 19, + 20, 21, 0, 0, 0, 0, 2, 24, 25, 0, + 26, 3, 27, 4, 5, 6, 7, 0, 0, 8, + 0, 0, 10, 0, 11, 12, 13, 0, 0, 14, + 15, 16, 17, 0, 18, 19, 20, 21, 0, 0, + 0, 0, 2, 24, 25, 0, 26, 3, 27, 4, + 5, 6, 7, 0, 0, 8, 0, 95, 0, 0, + 11, 12, 13, 0, 0, 14, 15, 16, 17, 0, + 18, 19, 20, 21, 0, 0, 0, 0, 2, 24, + 25, 0, 26, 3, 27, 4, 5, 6, 7, 0, + 0, 8, 0, 0, 0, 0, 11, 12, 13, 0, + 0, 14, 15, 16, 17, 0, 18, 19, 20, 21, + 0, 0, 98, 0, 2, 24, 25, 0, 26, 3, + 27, 4, 5, 6, 7, 0, 0, 8, 0, 0, + 0, 0, 11, 12, 13, 0, 0, 14, 15, 16, + 17, 0, 18, 19, 20, 21, 0, 0, 0, 0, + 0, 24, 25, 0, 26, 13, 27, 0, 14, 15, + 16, 17, 0, 18, 19, 20, 21, 0, 0, 0, + 0, 0, 24, 25, 59, 60, 61, 62, 0, 63, + 0, 64, 65, 0, 0, 0, 0, 0, 66, 67 }; -static const short yycheck[] = { 6, - 7, 32, 44, 45, 46, 0, 35, 49, 101, 14, - 143, 35, 17, 19, 37, 21, 14, 41, 25, 26, - 19, 44, 0, 154, 155, 156, 157, 158, 19, 9, - 35, 9, 9, 19, 40, 14, 41, 35, 17, 19, - 82, 83, 19, 41, 86, 178, 14, 14, 14, 80, - 19, 144, 94, 17, 96, 35, 35, 19, 35, 21, - 102, 43, 41, 43, 19, 37, 43, 35, 35, 35, - 19, 35, 44, 41, 41, 41, 209, 19, 40, 19, - 87, 22, 23, 176, 126, 127, 128, 129, 130, 131, - 85, 98, 99, 19, 19, 21, 21, 228, 229, 230, - 142, 19, 5, 6, 7, 35, 84, 85, 22, 23, - 88, 19, 143, 19, 40, 40, 34, 35, 36, 161, - 19, 19, 22, 23, 119, 120, 133, 37, 135, 4, - 137, 43, 139, 33, 34, 35, 14, 22, 23, 5, - 6, 119, 120, 150, 151, 123, 177, 178, 33, 34, - 34, 34, 14, 148, 44, 19, 19, 164, 165, 19, - 202, 19, 169, 170, 19, 207, 19, 19, 42, 147, - 148, 213, 214, 215, 44, 3, 44, 219, 209, 210, - 8, 15, 10, 11, 12, 13, 15, 7, 16, 231, - 18, 19, 20, 21, 9, 226, 24, 25, 26, 27, - 28, 29, 30, 31, 32, 212, 15, 35, 15, 42, - 38, 39, 219, 41, 7, 43, 42, 4, 19, 15, - 42, 15, 19, 42, 231, 28, 28, 15, 235, 236, - 237, 238, 239, 1, 42, 3, 15, 42, 0, 0, - 8, 138, 10, 11, 12, 13, 29, 193, 16, 172, - 18, 19, 20, 21, 227, -1, 24, 25, 26, 27, - 161, 29, 30, 31, 32, 161, -1, 35, 36, 3, - 38, 39, -1, 41, 8, 43, 10, 11, 12, 13, - -1, -1, 16, -1, 18, 19, 20, 21, -1, -1, - 24, 25, 26, 27, 28, 29, 30, 31, 32, -1, - -1, 35, -1, 3, 38, 39, -1, 41, 8, 43, - 10, 11, 12, 13, -1, -1, 16, -1, 18, 19, - 20, 21, -1, -1, 24, 25, 26, 27, -1, 29, - 30, 31, 32, -1, -1, 35, -1, 3, 38, 39, - -1, 41, 8, 43, 10, 11, 12, 13, -1, -1, - 16, -1, 18, 19, 20, 21, -1, -1, 24, 25, - 26, 27, -1, 29, 30, 31, 32, -1, -1, 35, - -1, 3, 38, 39, -1, 41, 8, 43, 10, 11, - 12, 13, -1, -1, 16, -1, 18, 19, 20, 21, - -1, -1, 24, 25, 26, 27, -1, 29, 30, 31, - 32, -1, -1, -1, -1, 3, 38, 39, -1, 41, - 8, 43, 10, 11, 12, 13, -1, -1, 16, -1, - -1, 19, 20, 21, -1, -1, 24, 25, 26, 27, - -1, 29, 30, 31, 32, -1, -1, 35, -1, 3, - 38, 39, -1, 41, 8, 43, 10, 11, 12, 13, - -1, -1, 16, -1, -1, 19, 20, 21, -1, -1, - 24, 25, 26, 27, -1, 29, 30, 31, 32, -1, - -1, -1, -1, -1, 38, 39, -1, 41, -1, 43, - 19, 20, 21, -1, -1, 24, 25, 26, 27, -1, - 29, 30, 31, 32, -1, -1, -1, -1, 21, 38, - 39, 24, 25, 26, 27, -1, 29, 30, 31, 32, - -1, -1, -1, -1, -1, 38, 39, 24, 25, 26, - 27, -1, 29, -1, 31, 32, -1, -1, -1, -1, - -1, 38, 39 +static const short yycheck[] = { 2, + 83, 9, 0, 6, 7, 32, 17, 9, 37, 39, + 6, 7, 110, 21, 43, 14, 46, 37, 17, 21, + 9, 0, 26, 20, 27, 39, 37, 14, 21, 37, + 17, 27, 46, 24, 25, 37, 14, 45, 37, 14, + 14, 14, 37, 45, 43, 21, 49, 50, 51, 21, + 37, 54, 21, 21, 23, 44, 43, 155, 21, 37, + 23, 88, 37, 37, 37, 43, 21, 56, 43, 43, + 43, 21, 21, 42, 23, 21, 21, 23, 45, 42, + 24, 25, 165, 166, 167, 168, 169, 90, 91, 187, + 21, 94, 21, 42, 97, 93, 42, 5, 6, 7, + 103, 97, 105, 21, 107, 108, 95, 5, 6, 112, + 21, 107, 108, 92, 93, 24, 25, 21, 36, 37, + 38, 21, 39, 4, 36, 14, 35, 36, 37, 36, + 14, 45, 130, 131, 137, 138, 139, 140, 141, 142, + 144, 46, 146, 21, 148, 134, 150, 21, 21, 21, + 153, 130, 131, 21, 237, 238, 239, 21, 161, 162, + 21, 159, 24, 25, 44, 161, 162, 46, 21, 172, + 174, 175, 15, 35, 36, 46, 180, 181, 15, 158, + 159, 21, 22, 23, 7, 9, 26, 27, 28, 29, + 15, 31, 32, 33, 34, 30, 44, 15, 44, 7, + 40, 41, 4, 30, 21, 15, 44, 21, 15, 212, + 44, 15, 44, 44, 217, 15, 0, 0, 221, 222, + 223, 224, 149, 236, 30, 221, 229, 183, 9, 172, + -1, -1, 203, 229, -1, -1, -1, 240, -1, -1, + 244, 245, 246, 247, 240, 248, 1, -1, 3, -1, + -1, -1, 248, 8, -1, 10, 11, 12, 13, -1, + -1, 16, -1, 18, 19, -1, 21, 22, 23, -1, + -1, 26, 27, 28, 29, -1, 31, 32, 33, 34, + -1, -1, 37, 38, 3, 40, 41, -1, 43, 8, + 45, 10, 11, 12, 13, -1, -1, 16, -1, 18, + 19, -1, 21, 22, 23, -1, -1, 26, 27, 28, + 29, -1, 31, 32, 33, 34, -1, -1, 37, -1, + 3, 40, 41, -1, 43, 8, 45, 10, 11, 12, + 13, -1, -1, 16, -1, 18, 19, -1, 21, 22, + 23, -1, -1, 26, 27, 28, 29, -1, 31, 32, + 33, 34, -1, -1, -1, -1, 3, 40, 41, -1, + 43, 8, 45, 10, 11, 12, 13, -1, -1, 16, + -1, -1, 19, -1, 21, 22, 23, -1, -1, 26, + 27, 28, 29, -1, 31, 32, 33, 34, -1, -1, + -1, -1, 3, 40, 41, -1, 43, 8, 45, 10, + 11, 12, 13, -1, -1, 16, -1, 18, -1, -1, + 21, 22, 23, -1, -1, 26, 27, 28, 29, -1, + 31, 32, 33, 34, -1, -1, -1, -1, 3, 40, + 41, -1, 43, 8, 45, 10, 11, 12, 13, -1, + -1, 16, -1, -1, -1, -1, 21, 22, 23, -1, + -1, 26, 27, 28, 29, -1, 31, 32, 33, 34, + -1, -1, 37, -1, 3, 40, 41, -1, 43, 8, + 45, 10, 11, 12, 13, -1, -1, 16, -1, -1, + -1, -1, 21, 22, 23, -1, -1, 26, 27, 28, + 29, -1, 31, 32, 33, 34, -1, -1, -1, -1, + -1, 40, 41, -1, 43, 23, 45, -1, 26, 27, + 28, 29, -1, 31, 32, 33, 34, -1, -1, -1, + -1, -1, 40, 41, 26, 27, 28, 29, -1, 31, + -1, 33, 34, -1, -1, -1, -1, -1, 40, 41 }; /* -*-C-*- Note some compilers choke on comments on `#line' lines. */ #line 3 "/usr/local/lib/bison.simple" @@ -1024,7 +1070,7 @@ yyreduce: switch (yyn) { case 1: -#line 164 "./parse.y" +#line 210 "./parse.y" { /* Case of regular command. Discard the error safety net,and return the command just parsed. */ @@ -1035,7 +1081,7 @@ case 1: ; break;} case 2: -#line 173 "./parse.y" +#line 219 "./parse.y" { /* Case of regular command, but not a very interesting one. Return a NULL command. */ @@ -1044,7 +1090,7 @@ case 2: ; break;} case 3: -#line 181 "./parse.y" +#line 226 "./parse.y" { /* Error during parsing. Return NULL command. */ global_command = (COMMAND *)NULL; @@ -1061,9 +1107,9 @@ case 3: ; break;} case 4: -#line 196 "./parse.y" +#line 241 "./parse.y" { - /* Case of EOF seen by itself. Do ignoreeof or + /* Case of EOF seen by itself. Do ignoreeof or not. */ global_command = (COMMAND *)NULL; handle_eof_input_unit (); @@ -1071,57 +1117,57 @@ case 4: ; break;} case 5: -#line 206 "./parse.y" -{ yyval.word_list = (WORD_LIST *)NULL; ; +#line 251 "./parse.y" +{ yyval.word_list = make_word_list (yyvsp[0].word, (WORD_LIST *)NULL); ; break;} case 6: -#line 208 "./parse.y" +#line 253 "./parse.y" { yyval.word_list = make_word_list (yyvsp[0].word, yyvsp[-1].word_list); ; break;} case 7: -#line 212 "./parse.y" +#line 257 "./parse.y" { redir.filename = yyvsp[0].word; yyval.redirect = make_redirection (1, r_output_direction, redir); ; break;} case 8: -#line 217 "./parse.y" +#line 262 "./parse.y" { redir.filename = yyvsp[0].word; yyval.redirect = make_redirection (0, r_input_direction, redir); ; break;} case 9: -#line 222 "./parse.y" +#line 267 "./parse.y" { redir.filename = yyvsp[0].word; yyval.redirect = make_redirection (yyvsp[-2].number, r_output_direction, redir); ; break;} case 10: -#line 227 "./parse.y" +#line 272 "./parse.y" { redir.filename = yyvsp[0].word; yyval.redirect = make_redirection (yyvsp[-2].number, r_input_direction, redir); ; break;} case 11: -#line 232 "./parse.y" +#line 277 "./parse.y" { redir.filename = yyvsp[0].word; yyval.redirect = make_redirection (1, r_appending_to, redir); ; break;} case 12: -#line 237 "./parse.y" +#line 282 "./parse.y" { redir.filename = yyvsp[0].word; yyval.redirect = make_redirection (yyvsp[-2].number, r_appending_to, redir); ; break;} case 13: -#line 242 "./parse.y" +#line 287 "./parse.y" { redir.filename = yyvsp[0].word; yyval.redirect = make_redirection (0, r_reading_until, redir); @@ -1129,7 +1175,7 @@ case 13: ; break;} case 14: -#line 248 "./parse.y" +#line 293 "./parse.y" { redir.filename = yyvsp[0].word; yyval.redirect = make_redirection (yyvsp[-2].number, r_reading_until, redir); @@ -1137,63 +1183,63 @@ case 14: ; break;} case 15: -#line 254 "./parse.y" +#line 299 "./parse.y" { redir.dest = yyvsp[0].number; yyval.redirect = make_redirection (0, r_duplicating_input, redir); ; break;} case 16: -#line 259 "./parse.y" +#line 304 "./parse.y" { redir.dest = yyvsp[0].number; yyval.redirect = make_redirection (yyvsp[-2].number, r_duplicating_input, redir); ; break;} case 17: -#line 264 "./parse.y" +#line 309 "./parse.y" { redir.dest = yyvsp[0].number; yyval.redirect = make_redirection (1, r_duplicating_output, redir); ; break;} case 18: -#line 269 "./parse.y" +#line 314 "./parse.y" { redir.dest = yyvsp[0].number; yyval.redirect = make_redirection (yyvsp[-2].number, r_duplicating_output, redir); ; break;} case 19: -#line 274 "./parse.y" +#line 319 "./parse.y" { redir.filename = yyvsp[0].word; yyval.redirect = make_redirection (0, r_duplicating_input_word, redir); ; break;} case 20: -#line 279 "./parse.y" +#line 324 "./parse.y" { redir.filename = yyvsp[0].word; yyval.redirect = make_redirection (yyvsp[-2].number, r_duplicating_input_word, redir); ; break;} case 21: -#line 284 "./parse.y" +#line 329 "./parse.y" { redir.filename = yyvsp[0].word; yyval.redirect = make_redirection (1, r_duplicating_output_word, redir); ; break;} case 22: -#line 289 "./parse.y" +#line 334 "./parse.y" { redir.filename = yyvsp[0].word; yyval.redirect = make_redirection (yyvsp[-2].number, r_duplicating_output_word, redir); ; break;} case 23: -#line 294 "./parse.y" +#line 339 "./parse.y" { redir.filename = yyvsp[0].word; yyval.redirect = make_redirection @@ -1202,7 +1248,7 @@ case 23: ; break;} case 24: -#line 301 "./parse.y" +#line 346 "./parse.y" { redir.filename = yyvsp[0].word; yyval.redirect = make_redirection @@ -1211,369 +1257,342 @@ case 24: ; break;} case 25: -#line 308 "./parse.y" +#line 353 "./parse.y" { redir.dest = 0L; yyval.redirect = make_redirection (1, r_close_this, redir); ; break;} case 26: -#line 313 "./parse.y" +#line 358 "./parse.y" { redir.dest = 0L; yyval.redirect = make_redirection (yyvsp[-2].number, r_close_this, redir); ; break;} case 27: -#line 318 "./parse.y" +#line 363 "./parse.y" { redir.dest = 0L; yyval.redirect = make_redirection (0, r_close_this, redir); ; break;} case 28: -#line 323 "./parse.y" +#line 368 "./parse.y" { redir.dest = 0L; yyval.redirect = make_redirection (yyvsp[-2].number, r_close_this, redir); ; break;} case 29: -#line 328 "./parse.y" +#line 373 "./parse.y" { redir.filename = yyvsp[0].word; yyval.redirect = make_redirection (1, r_err_and_out, redir); ; break;} case 30: -#line 333 "./parse.y" +#line 378 "./parse.y" { redir.filename = yyvsp[0].word; yyval.redirect = make_redirection (yyvsp[-2].number, r_input_output, redir); ; break;} case 31: -#line 338 "./parse.y" +#line 383 "./parse.y" { - REDIRECT *t1, *t2; - redir.filename = yyvsp[0].word; - if (posixly_correct) - yyval.redirect = make_redirection (0, r_input_output, redir); - else - { - t1 = make_redirection (0, r_input_direction, redir); - redir.filename = copy_word (yyvsp[0].word); - t2 = make_redirection (1, r_output_direction, redir); - t1->next = t2; - yyval.redirect = t1; - } + yyval.redirect = make_redirection (0, r_input_output, redir); ; break;} case 32: -#line 354 "./parse.y" +#line 388 "./parse.y" { redir.filename = yyvsp[0].word; yyval.redirect = make_redirection (1, r_output_force, redir); ; break;} case 33: -#line 359 "./parse.y" +#line 393 "./parse.y" { redir.filename = yyvsp[0].word; yyval.redirect = make_redirection (yyvsp[-2].number, r_output_force, redir); ; break;} case 34: -#line 366 "./parse.y" +#line 400 "./parse.y" { yyval.element.word = yyvsp[0].word; yyval.element.redirect = 0; ; break;} case 35: -#line 368 "./parse.y" +#line 402 "./parse.y" { yyval.element.word = yyvsp[0].word; yyval.element.redirect = 0; ; break;} case 36: -#line 370 "./parse.y" +#line 404 "./parse.y" { yyval.element.redirect = yyvsp[0].redirect; yyval.element.word = 0; ; break;} case 37: -#line 374 "./parse.y" +#line 408 "./parse.y" { yyval.redirect = yyvsp[0].redirect; ; break;} case 38: -#line 378 "./parse.y" -{ - register REDIRECT *t = yyvsp[-1].redirect; +#line 412 "./parse.y" +{ + register REDIRECT *t; - while (t->next) - t = t->next; - t->next = yyvsp[0].redirect; + for (t = yyvsp[-1].redirect; t->next; t = t->next) + ; + t->next = yyvsp[0].redirect; yyval.redirect = yyvsp[-1].redirect; ; break;} case 39: -#line 389 "./parse.y" +#line 423 "./parse.y" { yyval.command = make_simple_command (yyvsp[0].element, (COMMAND *)NULL); ; break;} case 40: -#line 391 "./parse.y" +#line 425 "./parse.y" { yyval.command = make_simple_command (yyvsp[0].element, yyvsp[-1].command); ; break;} case 41: -#line 395 "./parse.y" +#line 429 "./parse.y" { yyval.command = clean_simple_command (yyvsp[0].command); ; break;} case 42: -#line 397 "./parse.y" +#line 431 "./parse.y" { yyval.command = yyvsp[0].command; ; break;} case 43: -#line 401 "./parse.y" -{ yyval.command = yyvsp[0].command; ; - break;} -case 44: -#line 403 "./parse.y" +#line 433 "./parse.y" { - if (yyvsp[-1].command->redirects) + COMMAND *tc; + + tc = yyvsp[-1].command; + /* According to Posix.2 3.9.5, redirections + specified after the body of a function should + be attached to the function and performed when + the function is executed, not as part of the + function definition command. */ + if (tc->type == cm_function_def) + { + tc = tc->value.Function_def->command; + if (tc->type == cm_group) + tc = tc->value.Group->command; + } + if (tc->redirects) { register REDIRECT *t; - for (t = yyvsp[-1].command->redirects; t->next; t = t->next) + for (t = tc->redirects; t->next; t = t->next) ; t->next = yyvsp[0].redirect; } else - yyvsp[-1].command->redirects = yyvsp[0].redirect; + tc->redirects = yyvsp[0].redirect; yyval.command = yyvsp[-1].command; ; break;} +case 44: +#line 462 "./parse.y" +{ yyval.command = yyvsp[0].command; ; + break;} case 45: -#line 418 "./parse.y" -{ yyval.command = make_for_command (yyvsp[-4].word, add_string_to_list ("\"$@\"", (WORD_LIST *)NULL), yyvsp[-1].command); ; +#line 464 "./parse.y" +{ yyval.command = yyvsp[0].command; ; break;} case 46: -#line 420 "./parse.y" -{ yyval.command = make_for_command (yyvsp[-4].word, add_string_to_list ("$@", (WORD_LIST *)NULL), yyvsp[-1].command); ; +#line 466 "./parse.y" +{ yyval.command = make_while_command (yyvsp[-3].command, yyvsp[-1].command); ; break;} case 47: -#line 422 "./parse.y" -{ yyval.command = make_for_command (yyvsp[-5].word, add_string_to_list ("\"$@\"", (WORD_LIST *)NULL), yyvsp[-1].command); ; +#line 468 "./parse.y" +{ yyval.command = make_until_command (yyvsp[-3].command, yyvsp[-1].command); ; break;} case 48: -#line 424 "./parse.y" -{ yyval.command = make_for_command (yyvsp[-5].word, add_string_to_list ("\"$@\"", (WORD_LIST *)NULL), yyvsp[-1].command); ; +#line 470 "./parse.y" +{ yyval.command = yyvsp[0].command; ; break;} case 49: -#line 426 "./parse.y" -{ yyval.command = make_for_command (yyvsp[-8].word, REVERSE_LIST (yyvsp[-5].word_list, WORD_LIST *), yyvsp[-1].command); ; +#line 472 "./parse.y" +{ yyval.command = yyvsp[0].command; ; break;} case 50: -#line 428 "./parse.y" -{ yyval.command = make_for_command (yyvsp[-8].word, REVERSE_LIST (yyvsp[-5].word_list, WORD_LIST *), yyvsp[-1].command); ; +#line 474 "./parse.y" +{ yyval.command = yyvsp[0].command; ; break;} case 51: -#line 431 "./parse.y" -{ yyval.command = make_case_command (yyvsp[-4].word, (PATTERN_LIST *)NULL); ; +#line 476 "./parse.y" +{ yyval.command = yyvsp[0].command; ; break;} case 52: -#line 433 "./parse.y" -{ yyval.command = make_case_command (yyvsp[-5].word, yyvsp[-2].pattern); ; +#line 478 "./parse.y" +{ yyval.command = yyvsp[0].command; ; break;} case 53: -#line 435 "./parse.y" -{ yyval.command = make_case_command (yyvsp[-4].word, yyvsp[-1].pattern); ; +#line 482 "./parse.y" +{ yyval.command = make_for_command (yyvsp[-4].word, add_string_to_list ("\"$@\"", (WORD_LIST *)NULL), yyvsp[-1].command); ; break;} case 54: -#line 437 "./parse.y" -{ yyval.command = make_while_command (yyvsp[-3].command, yyvsp[-1].command); ; +#line 484 "./parse.y" +{ yyval.command = make_for_command (yyvsp[-4].word, add_string_to_list ("$@", (WORD_LIST *)NULL), yyvsp[-1].command); ; break;} case 55: -#line 439 "./parse.y" -{ yyval.command = make_until_command (yyvsp[-3].command, yyvsp[-1].command); ; +#line 486 "./parse.y" +{ yyval.command = make_for_command (yyvsp[-5].word, add_string_to_list ("\"$@\"", (WORD_LIST *)NULL), yyvsp[-1].command); ; break;} case 56: -#line 441 "./parse.y" -{ yyval.command = yyvsp[0].command; ; +#line 488 "./parse.y" +{ yyval.command = make_for_command (yyvsp[-5].word, add_string_to_list ("\"$@\"", (WORD_LIST *)NULL), yyvsp[-1].command); ; break;} case 57: -#line 443 "./parse.y" -{ yyval.command = yyvsp[0].command; ; +#line 490 "./parse.y" +{ yyval.command = make_for_command (yyvsp[-8].word, REVERSE_LIST (yyvsp[-5].word_list, WORD_LIST *), yyvsp[-1].command); ; break;} case 58: -#line 445 "./parse.y" -{ yyval.command = yyvsp[0].command; ; +#line 492 "./parse.y" +{ yyval.command = make_for_command (yyvsp[-8].word, REVERSE_LIST (yyvsp[-5].word_list, WORD_LIST *), yyvsp[-1].command); ; break;} case 59: -#line 447 "./parse.y" -{ yyval.command = yyvsp[0].command; ; - break;} -case 60: -#line 449 "./parse.y" -{ yyval.command = yyvsp[0].command; ; - break;} -case 61: -#line 453 "./parse.y" +#line 496 "./parse.y" { -#if defined (SELECT_COMMAND) yyval.command = make_select_command (yyvsp[-4].word, add_string_to_list ("\"$@\"", (WORD_LIST *)NULL), yyvsp[-1].command); -#endif ; break;} -case 62: -#line 459 "./parse.y" +case 60: +#line 500 "./parse.y" { -#if defined (SELECT_COMMAND) yyval.command = make_select_command (yyvsp[-4].word, add_string_to_list ("$@", (WORD_LIST *)NULL), yyvsp[-1].command); -#endif ; break;} -case 63: -#line 465 "./parse.y" +case 61: +#line 504 "./parse.y" { -#if defined (SELECT_COMMAND) yyval.command = make_select_command (yyvsp[-5].word, add_string_to_list ("\"$@\"", (WORD_LIST *)NULL), yyvsp[-1].command); -#endif ; break;} -case 64: -#line 471 "./parse.y" +case 62: +#line 508 "./parse.y" { -#if defined (SELECT_COMMAND) yyval.command = make_select_command (yyvsp[-5].word, add_string_to_list ("\"$@\"", (WORD_LIST *)NULL), yyvsp[-1].command); -#endif ; break;} -case 65: -#line 477 "./parse.y" +case 63: +#line 512 "./parse.y" { -#if defined (SELECT_COMMAND) yyval.command = make_select_command (yyvsp[-8].word, (WORD_LIST *)reverse_list (yyvsp[-5].word_list), yyvsp[-1].command); -#endif ; break;} -case 66: -#line 483 "./parse.y" +case 64: +#line 516 "./parse.y" { -#if defined (SELECT_COMMAND) yyval.command = make_select_command (yyvsp[-8].word, (WORD_LIST *)reverse_list (yyvsp[-5].word_list), yyvsp[-1].command); -#endif ; break;} +case 65: +#line 522 "./parse.y" +{ yyval.command = make_case_command (yyvsp[-4].word, (PATTERN_LIST *)NULL); ; + break;} +case 66: +#line 524 "./parse.y" +{ yyval.command = make_case_command (yyvsp[-5].word, yyvsp[-2].pattern); ; + break;} case 67: -#line 491 "./parse.y" -{ yyval.command = make_function_def (yyvsp[-4].word, yyvsp[0].command); ; +#line 526 "./parse.y" +{ yyval.command = make_case_command (yyvsp[-4].word, yyvsp[-1].pattern); ; break;} case 68: -#line 494 "./parse.y" -{ yyvsp[-1].command->redirects = yyvsp[0].redirect; yyval.command = make_function_def (yyvsp[-5].word, yyvsp[-1].command); ; +#line 530 "./parse.y" +{ yyval.command = make_function_def (yyvsp[-4].word, yyvsp[0].command, function_dstart, function_bstart); ; break;} case 69: -#line 497 "./parse.y" -{ yyval.command = make_function_def (yyvsp[-4].word, yyvsp[0].command); ; +#line 534 "./parse.y" +{ yyval.command = make_function_def (yyvsp[-4].word, yyvsp[0].command, function_dstart, function_bstart); ; break;} case 70: -#line 500 "./parse.y" -{ yyvsp[-1].command->redirects = yyvsp[0].redirect; yyval.command = make_function_def (yyvsp[-5].word, yyvsp[-1].command); ; +#line 537 "./parse.y" +{ yyval.command = make_function_def (yyvsp[-2].word, yyvsp[0].command, function_dstart, function_bstart); ; break;} case 71: -#line 503 "./parse.y" -{ yyval.command = make_function_def (yyvsp[-2].word, yyvsp[0].command); ; - break;} -case 72: -#line 506 "./parse.y" -{ yyvsp[-1].command->redirects = yyvsp[0].redirect; yyval.command = make_function_def (yyvsp[-3].word, yyvsp[-1].command); ; - break;} -case 73: -#line 510 "./parse.y" +#line 541 "./parse.y" { yyvsp[-1].command->flags |= CMD_WANT_SUBSHELL; yyval.command = yyvsp[-1].command; ; break;} -case 74: -#line 514 "./parse.y" +case 72: +#line 545 "./parse.y" { yyval.command = make_if_command (yyvsp[-3].command, yyvsp[-1].command, (COMMAND *)NULL); ; break;} -case 75: -#line 516 "./parse.y" +case 73: +#line 547 "./parse.y" { yyval.command = make_if_command (yyvsp[-5].command, yyvsp[-3].command, yyvsp[-1].command); ; break;} -case 76: -#line 518 "./parse.y" +case 74: +#line 549 "./parse.y" { yyval.command = make_if_command (yyvsp[-4].command, yyvsp[-2].command, yyvsp[-1].command); ; break;} -case 77: -#line 523 "./parse.y" +case 75: +#line 554 "./parse.y" { yyval.command = make_group_command (yyvsp[-1].command); ; break;} -case 78: -#line 527 "./parse.y" +case 76: +#line 558 "./parse.y" { yyval.command = make_if_command (yyvsp[-2].command, yyvsp[0].command, (COMMAND *)NULL); ; break;} -case 79: -#line 529 "./parse.y" +case 77: +#line 560 "./parse.y" { yyval.command = make_if_command (yyvsp[-4].command, yyvsp[-2].command, yyvsp[0].command); ; break;} -case 80: -#line 531 "./parse.y" +case 78: +#line 562 "./parse.y" { yyval.command = make_if_command (yyvsp[-3].command, yyvsp[-1].command, yyvsp[0].command); ; break;} -case 82: -#line 536 "./parse.y" +case 80: +#line 567 "./parse.y" { yyvsp[0].pattern->next = yyvsp[-1].pattern; yyval.pattern = yyvsp[0].pattern; ; break;} -case 83: -#line 540 "./parse.y" +case 81: +#line 571 "./parse.y" { yyval.pattern = make_pattern_list (yyvsp[-2].word_list, yyvsp[0].command); ; break;} -case 84: -#line 542 "./parse.y" +case 82: +#line 573 "./parse.y" { yyval.pattern = make_pattern_list (yyvsp[-2].word_list, (COMMAND *)NULL); ; break;} -case 85: -#line 544 "./parse.y" +case 83: +#line 575 "./parse.y" { yyval.pattern = make_pattern_list (yyvsp[-2].word_list, yyvsp[0].command); ; break;} -case 86: -#line 546 "./parse.y" +case 84: +#line 577 "./parse.y" { yyval.pattern = make_pattern_list (yyvsp[-2].word_list, (COMMAND *)NULL); ; break;} -case 88: -#line 551 "./parse.y" -{ yyvsp[0].pattern->next = yyvsp[-1].pattern; yyval.pattern = yyvsp[0].pattern; ; - break;} -case 89: -#line 555 "./parse.y" -{ yyval.pattern = make_pattern_list (yyvsp[-3].word_list, yyvsp[-1].command); ; - break;} -case 90: -#line 557 "./parse.y" -{ yyval.pattern = make_pattern_list (yyvsp[-3].word_list, (COMMAND *)NULL); ; - break;} -case 91: -#line 559 "./parse.y" -{ yyval.pattern = make_pattern_list (yyvsp[-3].word_list, yyvsp[-1].command); ; - break;} -case 92: -#line 561 "./parse.y" -{ yyval.pattern = make_pattern_list (yyvsp[-3].word_list, (COMMAND *)NULL); ; +case 86: +#line 582 "./parse.y" +{ yyvsp[-1].pattern->next = yyvsp[-2].pattern; yyval.pattern = yyvsp[-1].pattern; ; break;} -case 93: -#line 565 "./parse.y" +case 87: +#line 586 "./parse.y" { yyval.word_list = make_word_list (yyvsp[0].word, (WORD_LIST *)NULL); ; break;} -case 94: -#line 567 "./parse.y" +case 88: +#line 588 "./parse.y" { yyval.word_list = make_word_list (yyvsp[0].word, yyvsp[-2].word_list); ; break;} -case 95: -#line 576 "./parse.y" +case 89: +#line 597 "./parse.y" { yyval.command = yyvsp[0].command; if (need_here_doc) gather_here_documents (); ; break;} -case 98: -#line 586 "./parse.y" +case 91: +#line 606 "./parse.y" +{ + yyval.command = yyvsp[0].command; + ; + break;} +case 93: +#line 613 "./parse.y" { if (yyvsp[-2].command->type == cm_connection) yyval.command = connect_async_list (yyvsp[-2].command, (COMMAND *)NULL, '&'); @@ -1581,16 +1600,16 @@ case 98: yyval.command = command_connect (yyvsp[-2].command, (COMMAND *)NULL, '&'); ; break;} -case 100: -#line 597 "./parse.y" +case 95: +#line 624 "./parse.y" { yyval.command = command_connect (yyvsp[-3].command, yyvsp[0].command, AND_AND); ; break;} -case 101: -#line 599 "./parse.y" +case 96: +#line 626 "./parse.y" { yyval.command = command_connect (yyvsp[-3].command, yyvsp[0].command, OR_OR); ; break;} -case 102: -#line 601 "./parse.y" +case 97: +#line 628 "./parse.y" { if (yyvsp[-3].command->type == cm_connection) yyval.command = connect_async_list (yyvsp[-3].command, yyvsp[0].command, '&'); @@ -1598,35 +1617,28 @@ case 102: yyval.command = command_connect (yyvsp[-3].command, yyvsp[0].command, '&'); ; break;} -case 103: -#line 608 "./parse.y" +case 98: +#line 635 "./parse.y" { yyval.command = command_connect (yyvsp[-3].command, yyvsp[0].command, ';'); ; break;} -case 104: -#line 610 "./parse.y" +case 99: +#line 637 "./parse.y" { yyval.command = command_connect (yyvsp[-3].command, yyvsp[0].command, ';'); ; break;} -case 105: -#line 612 "./parse.y" +case 100: +#line 639 "./parse.y" { yyval.command = yyvsp[0].command; ; break;} case 106: -#line 614 "./parse.y" -{ - yyvsp[0].command->flags |= CMD_INVERT_RETURN; - yyval.command = yyvsp[0].command; - ; - break;} -case 112: -#line 636 "./parse.y" +#line 658 "./parse.y" { yyval.command = yyvsp[0].command; if (need_here_doc) gather_here_documents (); ; break;} -case 113: -#line 642 "./parse.y" +case 107: +#line 664 "./parse.y" { if (yyvsp[-1].command->type == cm_connection) yyval.command = connect_async_list (yyvsp[-1].command, (COMMAND *)NULL, '&'); @@ -1636,24 +1648,24 @@ case 113: gather_here_documents (); ; break;} -case 114: -#line 651 "./parse.y" +case 108: +#line 673 "./parse.y" { yyval.command = yyvsp[-1].command; if (need_here_doc) gather_here_documents (); ; break;} -case 115: -#line 659 "./parse.y" +case 109: +#line 681 "./parse.y" { yyval.command = command_connect (yyvsp[-3].command, yyvsp[0].command, AND_AND); ; break;} -case 116: -#line 661 "./parse.y" +case 110: +#line 683 "./parse.y" { yyval.command = command_connect (yyvsp[-3].command, yyvsp[0].command, OR_OR); ; break;} -case 117: -#line 663 "./parse.y" +case 111: +#line 685 "./parse.y" { if (yyvsp[-2].command->type == cm_connection) yyval.command = connect_async_list (yyvsp[-2].command, yyvsp[0].command, '&'); @@ -1661,29 +1673,62 @@ case 117: yyval.command = command_connect (yyvsp[-2].command, yyvsp[0].command, '&'); ; break;} -case 118: -#line 670 "./parse.y" +case 112: +#line 692 "./parse.y" { yyval.command = command_connect (yyvsp[-2].command, yyvsp[0].command, ';'); ; break;} -case 119: -#line 672 "./parse.y" +case 113: +#line 695 "./parse.y" { yyval.command = yyvsp[0].command; ; break;} -case 120: -#line 674 "./parse.y" +case 114: +#line 699 "./parse.y" +{ yyval.command = yyvsp[0].command; ; + break;} +case 115: +#line 701 "./parse.y" { yyvsp[0].command->flags |= CMD_INVERT_RETURN; yyval.command = yyvsp[0].command; ; break;} -case 121: -#line 682 "./parse.y" +case 116: +#line 706 "./parse.y" +{ + yyvsp[0].command->flags |= yyvsp[-1].number; + yyval.command = yyvsp[0].command; + ; + break;} +case 117: +#line 711 "./parse.y" +{ + yyvsp[0].command->flags |= yyvsp[-2].number; + yyval.command = yyvsp[0].command; + ; + break;} +case 118: +#line 716 "./parse.y" +{ + yyvsp[0].command->flags |= yyvsp[-1].number|CMD_INVERT_RETURN; + yyval.command = yyvsp[0].command; + ; + break;} +case 119: +#line 724 "./parse.y" { yyval.command = command_connect (yyvsp[-3].command, yyvsp[0].command, '|'); ; break;} -case 122: -#line 684 "./parse.y" +case 120: +#line 726 "./parse.y" { yyval.command = yyvsp[0].command; ; break;} +case 121: +#line 730 "./parse.y" +{ yyval.number = CMD_TIME_PIPELINE; ; + break;} +case 122: +#line 732 "./parse.y" +{ yyval.number = CMD_TIME_PIPELINE|CMD_TIME_POSIX; ; + break;} } /* the action file gets copied in in place of this dollarsign */ #line 498 "/usr/local/lib/bison.simple" @@ -1882,31 +1927,64 @@ yyerrhandle: yystate = yyn; goto yynewstate; } -#line 686 "./parse.y" +#line 734 "./parse.y" + +/* Possible states for the parser that require it to do special things. */ +#define PST_CASEPAT 0x001 /* in a case pattern list */ +#define PST_ALEXPNEXT 0x002 /* expand next word for aliases */ +#define PST_ALLOWOPNBRC 0x004 /* allow open brace for function def */ +#define PST_NEEDCLOSBRC 0x008 /* need close brace */ +#define PST_DBLPAREN 0x010 /* double-paren parsing */ +#define PST_SUBSHELL 0x020 /* ( ... ) subshell */ +#define PST_CMDSUBST 0x040 /* $( ... ) command substitution */ +#define PST_CASESTMT 0x080 /* parsing a case statement */ /* Initial size to allocate for tokens, and the amount to grow them by. */ #define TOKEN_DEFAULT_GROW_SIZE 512 +/* Shell meta-characters that, when unquoted, separate words. */ +#define shellmeta(c) (strchr ("()<>;&|", (c)) != 0) +#define shellbreak(c) (strchr ("()<>;&| \t\n", (c)) != 0) +#define shellquote(c) ((c) == '"' || (c) == '`' || (c) == '\'') +#define shellexp(c) ((c) == '$' || (c) == '<' || (c) == '>') + /* The token currently being read. */ -static int current_token = 0; +static int current_token; /* The last read token, or NULL. read_token () uses this for context checking. */ -static int last_read_token = 0; +static int last_read_token; /* The token read prior to last_read_token. */ -static int token_before_that = 0; +static int token_before_that; + +/* The token read prior to token_before_that. */ +static int two_tokens_ago; /* If non-zero, it is the token that we want read_token to return regardless of what text is (or isn't) present to be read. This - is reset by read_token. */ -static int token_to_read = 0; + is reset by read_token. If token_to_read == WORD or + ASSIGNMENT_WORD, yylval.word should be set to word_desc_to_read. */ +static int token_to_read; +static WORD_DESC *word_desc_to_read; + +/* The current parser state. */ +static int parser_state; /* Global var is non-zero when end of file has been reached. */ int EOF_Reached = 0; +void +debug_parser (i) + int i; +{ +#if YYDEBUG != 0 + yydebug = i; +#endif +} + /* yy_getc () returns the next available character from input or EOF. yy_ungetc (c) makes `c' the next character to read. init_yy_io (get, unget, type, location) makes the function GET the @@ -1916,6 +1994,7 @@ int EOF_Reached = 0; the input is coming from. */ /* Unconditionally returns end-of-file. */ +int return_EOF () { return (EOF); @@ -1925,11 +2004,13 @@ return_EOF () See ./input.h for a clearer description. */ BASH_INPUT bash_input; -/* Set all of the fields in BASH_INPUT to NULL. */ +/* Set all of the fields in BASH_INPUT to NULL. Free bash_input.name if it + is non-null, avoiding a memory leak. */ void initialize_bash_input () { - bash_input.type = 0; + bash_input.type = st_none; + FREE (bash_input.name); bash_input.name = (char *)NULL; bash_input.location.file = (FILE *)NULL; bash_input.location.string = (char *)NULL; @@ -1948,12 +2029,9 @@ init_yy_io (get, unget, type, name, location) { bash_input.type = type; FREE (bash_input.name); + bash_input.name = name ? savestring (name) : (char *)NULL; - if (name) - bash_input.name = savestring (name); - else - bash_input.name = (char *)NULL; - + /* XXX */ #if defined (CRAY) memcpy((char *)&bash_input.location.string, (char *)&location.string, sizeof(location)); #else @@ -1964,6 +2042,7 @@ init_yy_io (get, unget, type, name, location) } /* Call this to get the next character of input. */ +int yy_getc () { return (*(bash_input.getter)) (); @@ -1971,6 +2050,7 @@ yy_getc () /* Call this to unget C. That is, to make C the next character to be read. */ +int yy_ungetc (c) int c; { @@ -1987,6 +2067,7 @@ input_file_descriptor () return (fileno (bash_input.location.file)); case st_bstream: return (bash_input.location.buffered_fd); + case st_stdin: default: return (fileno (stdin)); } @@ -2007,11 +2088,11 @@ int current_readline_line_index = 0; static int yy_readline_get () { + SigHandler *old_sigint; + int line_len, c; + if (!current_readline_line) { - SigHandler *old_sigint; - int line_len; - if (!bash_readline_initialized) initialize_readline (); @@ -2026,10 +2107,8 @@ yy_readline_get () interrupt_immediately++; } - if (!current_readline_prompt) - current_readline_line = readline (""); - else - current_readline_line = readline (current_readline_prompt); + current_readline_line = readline (current_readline_prompt ? + current_readline_prompt : ""); if (signal_is_ignored (SIGINT) == 0) { @@ -2037,22 +2116,23 @@ yy_readline_get () set_signal_handler (SIGINT, old_sigint); } - /* Reset the prompt to whatever is in the decoded value of - prompt_string_pointer. */ +#if 0 + /* Reset the prompt to the decoded value of prompt_string_pointer. */ reset_readline_prompt (); +#endif - current_readline_line_index = 0; - - if (!current_readline_line) + if (current_readline_line == 0) return (EOF); + current_readline_line_index = 0; line_len = strlen (current_readline_line); + current_readline_line = xrealloc (current_readline_line, 2 + line_len); current_readline_line[line_len++] = '\n'; current_readline_line[line_len] = '\0'; } - if (!current_readline_line[current_readline_line_index]) + if (current_readline_line[current_readline_line_index] == 0) { free (current_readline_line); current_readline_line = (char *)NULL; @@ -2060,20 +2140,21 @@ yy_readline_get () } else { - int c = (unsigned char)current_readline_line[current_readline_line_index++]; + c = (unsigned char)current_readline_line[current_readline_line_index++]; return (c); } } static int yy_readline_unget (c) + int c; { if (current_readline_line_index && current_readline_line) current_readline_line[--current_readline_line_index] = c; return (c); } -void +void with_input_from_stdin () { INPUT_STREAM location; @@ -2104,7 +2185,7 @@ with_input_from_stdin () static int yy_string_get () { - register unsigned char *string; + register char *string; register int c; string = bash_input.location.string; @@ -2113,7 +2194,7 @@ yy_string_get () /* If the string doesn't exist, or is empty, EOF found. */ if (string && *string) { - c = *string++; + c = *(unsigned char *)string++; bash_input.location.string = string; } return (c); @@ -2129,13 +2210,11 @@ yy_string_unget (c) void with_input_from_string (string, name) - char *string; - char *name; + char *string, *name; { INPUT_STREAM location; location.string = string; - init_yy_io (yy_string_get, yy_string_unget, st_string, name, location); } @@ -2151,11 +2230,14 @@ yy_stream_get () int result = EOF; if (bash_input.location.file) -#if defined (NO_READ_RESTART_ON_SIGNAL) - result = (unsigned char)getc_with_restart (bash_input.location.file); -#else - result = (unsigned char)getc (bash_input.location.file); -#endif /* !NO_READ_RESTART_ON_SIGNAL */ + { +#if !defined (HAVE_RESTARTABLE_SYSCALLS) + result = getc_with_restart (bash_input.location.file); +#else /* HAVE_RESTARTABLE_SYSCALLS */ + result = getc (bash_input.location.file); + result = (feof (bash_input.location.file)) ? EOF : (unsigned char)result; +#endif /* HAVE_RESTARTABLE_SYSCALLS */ + } return (result); } @@ -2163,11 +2245,11 @@ static int yy_stream_unget (c) int c; { -#if defined (NO_READ_RESTART_ON_SIGNAL) +#if !defined (HAVE_RESTARTABLE_SYSCALLS) return (ungetc_with_restart (c, bash_input.location.file)); -#else +#else /* HAVE_RESTARTABLE_SYSCALLS */ return (ungetc (c, bash_input.location.file)); -#endif +#endif /* HAVE_RESTARTABLE_SYSCALLS */ } void @@ -2195,7 +2277,9 @@ int line_number = 0; STREAM_SAVER *stream_list = (STREAM_SAVER *)NULL; -push_stream () +void +push_stream (reset_lineno) + int reset_lineno; { STREAM_SAVER *saver = (STREAM_SAVER *)xmalloc (sizeof (STREAM_SAVER)); @@ -2215,13 +2299,14 @@ push_stream () bash_input.name = (char *)NULL; saver->next = stream_list; stream_list = saver; - EOF_Reached = line_number = 0; + EOF_Reached = 0; + if (reset_lineno) + line_number = 0; } +void pop_stream () { - int temp; - if (!stream_list) EOF_Reached = 1; else @@ -2267,36 +2352,35 @@ pop_stream () /* Return 1 if a stream of type TYPE is saved on the stack. */ int stream_on_stack (type) - int type; + enum stream_type type; { register STREAM_SAVER *s; - + for (s = stream_list; s; s = s->next) if (s->bash_input.type == type) return 1; return 0; } - /* * This is used to inhibit alias expansion and reserved word recognition - * inside case statement pattern lists. A `case statement pattern list' - * is: + * inside case statement pattern lists. A `case statement pattern list' is: + * * everything between the `in' in a `case word in' and the next ')' * or `esac' * everything between a `;;' and the next `)' or `esac' */ -static int in_case_pattern_list = 0; #if defined (ALIAS) + +#define END_OF_ALIAS 0 + /* * Pseudo-global variables used in implementing token-wise alias expansion. */ -static int expand_next_token = 0; - /* - * Pushing and popping strings. This works together with shell_getc to + * Pushing and popping strings. This works together with shell_getc to * implement alias expansion on a per-token basis. */ @@ -2304,13 +2388,12 @@ typedef struct string_saver { struct string_saver *next; int expand_alias; /* Value to set expand_alias to when string is popped. */ char *saved_line; + alias_t *expander; /* alias that caused this line to be pushed. */ int saved_line_size, saved_line_index, saved_line_terminator; } STRING_SAVER; STRING_SAVER *pushed_string_list = (STRING_SAVER *)NULL; -static void save_expansion (); - /* * Push the current shell_input_line onto a stack of such lines and make S * the current input. Used when expanding aliases. EXPAND is used to set @@ -2320,10 +2403,10 @@ static void save_expansion (); * into S; it is saved and used to prevent infinite recursive expansion. */ static void -push_string (s, expand, token) +push_string (s, expand, ap) char *s; int expand; - char *token; + alias_t *ap; { STRING_SAVER *temp = (STRING_SAVER *) xmalloc (sizeof (STRING_SAVER)); @@ -2332,16 +2415,17 @@ push_string (s, expand, token) temp->saved_line_size = shell_input_line_size; temp->saved_line_index = shell_input_line_index; temp->saved_line_terminator = shell_input_line_terminator; + temp->expander = ap; temp->next = pushed_string_list; pushed_string_list = temp; - save_expansion (token); + ap->flags |= AL_BEINGEXPANDED; shell_input_line = s; shell_input_line_size = strlen (s); shell_input_line_index = 0; shell_input_line_terminator = '\0'; - expand_next_token = 0; + parser_state &= ~PST_ALEXPNEXT; } /* @@ -2360,102 +2444,38 @@ pop_string () shell_input_line_index = pushed_string_list->saved_line_index; shell_input_line_size = pushed_string_list->saved_line_size; shell_input_line_terminator = pushed_string_list->saved_line_terminator; - expand_next_token = pushed_string_list->expand_alias; - t = pushed_string_list; + if (pushed_string_list->expand_alias) + parser_state |= PST_ALEXPNEXT; + else + parser_state &= ~PST_ALEXPNEXT; + + t = pushed_string_list; pushed_string_list = pushed_string_list->next; - free((char *)t); + + t->expander->flags &= ~AL_BEINGEXPANDED; + + free ((char *)t); } static void free_string_list () { - register STRING_SAVER *t = pushed_string_list, *t1; + register STRING_SAVER *t, *t1; - while (t) + for (t = pushed_string_list; t; ) { t1 = t->next; FREE (t->saved_line); + t->expander->flags &= ~AL_BEINGEXPANDED; free ((char *)t); t = t1; } pushed_string_list = (STRING_SAVER *)NULL; } -/* This is a stack to save the values of all tokens for which alias - expansion has been performed during the current call to read_token (). - It is used to prevent alias expansion loops: - - alias foo=bar - alias bar=baz - alias baz=foo - - Ideally this would be taken care of by push and pop string, but because - of when strings are popped the stack will not contain the correct - strings to test against. (The popping is done in shell_getc, so that when - the current string is exhausted, shell_getc can simply pop that string off - the stack, restore the previous string, and continue with the character - following the token whose expansion was originally pushed on the stack.) - - What we really want is a record of all tokens that have been expanded for - aliases during the `current' call to read_token(). This does that, at the - cost of being somewhat special-purpose (OK, OK vile and unclean). */ - -typedef struct _exp_saver { - struct _exp_saver *next; - char *saved_token; -} EXPANSION_SAVER; - -EXPANSION_SAVER *expanded_token_stack = (EXPANSION_SAVER *)NULL; - -static void -save_expansion (s) - char *s; -{ - EXPANSION_SAVER *t; - - t = (EXPANSION_SAVER *) xmalloc (sizeof (EXPANSION_SAVER)); - t->saved_token = savestring (s); - t->next = expanded_token_stack; - expanded_token_stack = t; -} - -/* Return 1 if TOKEN has already been expanded in the current `stack' of - expansions. If it has been expanded already, it will appear as the value - of saved_token for some entry in the stack of expansions created for the - current token being expanded. */ -static int -token_has_been_expanded (token) - char *token; -{ - register EXPANSION_SAVER *t = expanded_token_stack; - - while (t) - { - if (STREQ (token, t->saved_token)) - return (1); - t = t->next; - } - return (0); -} - -static void -free_expansion_stack () -{ - register EXPANSION_SAVER *t = expanded_token_stack, *t1; - - while (t) - { - t1 = t->next; - free (t->saved_token); - free (t); - t = t1; - } - expanded_token_stack = (EXPANSION_SAVER *)NULL; -} - #endif /* ALIAS */ - + /* Return a line of text, taken from wherever yylex () reads input. If there is no more input, then we return NULL. If REMOVE_QUOTED_NEWLINE is non-zero, we remove unquoted \ pairs. This is used by @@ -2468,6 +2488,13 @@ read_a_line (remove_quoted_newline) static int buffer_size = 0; int indx = 0, c, peekc, pass_next; +#if defined (READLINE) + if (interactive && bash_input.type != st_string && no_line_editing) +#else + if (interactive && bash_input.type != st_string) +#endif + print_prompt (); + pass_next = 0; while (1) { @@ -2482,17 +2509,15 @@ read_a_line (remove_quoted_newline) /* If there is no more input, then we return NULL. */ if (c == EOF) { + if (interactive && bash_input.type == st_stream) + clearerr (stdin); if (indx == 0) return ((char *)NULL); c = '\n'; } /* `+2' in case the final character in the buffer is a newline. */ - if (indx + 2 > buffer_size) - if (!buffer_size) - line_buffer = xmalloc (buffer_size = 128); - else - line_buffer = xrealloc (line_buffer, buffer_size += 128); + RESIZE_MALLOCED_BUFFER (line_buffer, indx, 2, buffer_size, 128); /* IF REMOVE_QUOTED_NEWLINES is non-zero, we are reading a here document with an unquoted delimiter. In this case, @@ -2542,7 +2567,6 @@ read_secondary_line (remove_quoted_newline) return (read_a_line (remove_quoted_newline)); } - /* **************************************************************** */ /* */ /* YYLEX () */ @@ -2569,21 +2593,56 @@ STRING_INT_ALIST word_token_alist[] = { { "done", DONE }, { "in", IN }, { "function", FUNCTION }, +#if defined (COMMAND_TIMING) + { "time", TIME }, +#endif { "{", '{' }, { "}", '}' }, { "!", BANG }, { (char *)NULL, 0} }; +/* These are used by read_token_word, but appear up here so that shell_getc + can use them to decide when to add otherwise blank lines to the history. */ + +/* The primary delimiter stack. */ +struct dstack dstack = { (char *)NULL, 0, 0 }; + +/* A temporary delimiter stack to be used when decoding prompt strings. + This is needed because command substitutions in prompt strings (e.g., PS2) + can screw up the parser's quoting state. */ +static struct dstack temp_dstack = { (char *)NULL, 0, 0 }; + +/* Macro for accessing the top delimiter on the stack. Returns the + delimiter or zero if none. */ +#define current_delimiter(ds) \ + (ds.delimiter_depth ? ds.delimiters[ds.delimiter_depth - 1] : 0) + +#define push_delimiter(ds, character) \ + do \ + { \ + if (ds.delimiter_depth + 2 > ds.delimiter_space) \ + ds.delimiters = xrealloc \ + (ds.delimiters, (ds.delimiter_space += 10) * sizeof (char)); \ + ds.delimiters[ds.delimiter_depth] = character; \ + ds.delimiter_depth++; \ + } \ + while (0) + +#define pop_delimiter(ds) ds.delimiter_depth-- + /* Return the next shell input character. This always reads characters from shell_input_line; when that line is exhausted, it is time to read the next line. This is called by read_token when the shell is processing normal command input. */ + static int shell_getc (remove_quoted_newline) int remove_quoted_newline; { + register int i; int c; + static int mustpop = 0; QUIT; @@ -2598,10 +2657,6 @@ shell_getc (remove_quoted_newline) if (!shell_input_line || !shell_input_line[shell_input_line_index]) #endif /* !ALIAS */ { - register int i, l; - - restart_read_next_line: - line_number++; restart_read: @@ -2637,16 +2692,14 @@ shell_getc (remove_quoted_newline) /* Allow immediate exit if interrupted during input. */ QUIT; - if (i + 2 > shell_input_line_size) - shell_input_line = - xrealloc (shell_input_line, shell_input_line_size += 256); + RESIZE_MALLOCED_BUFFER (shell_input_line, i, 2, shell_input_line_size, 256); if (c == EOF) { if (bash_input.type == st_stream) clearerr (stdin); - if (!i) + if (i == 0) shell_input_line_terminator = EOF; shell_input_line[i] = '\0'; @@ -2666,11 +2719,23 @@ shell_getc (remove_quoted_newline) shell_input_line_len = i; /* == strlen (shell_input_line) */ #if defined (HISTORY) - if (interactive && shell_input_line && shell_input_line[0]) + if (remember_on_history && shell_input_line && shell_input_line[0]) { char *expansions; - +# if defined (BANG_HISTORY) + int old_hist; + + /* If the current delimiter is a single quote, we should not be + performing history expansion, even if we're on a different + line from the original single quote. */ + old_hist = history_expansion_inhibited; + if (current_delimiter (dstack) == '\'') + history_expansion_inhibited = 1; +# endif expansions = pre_process_line (shell_input_line, 1, 1); +# if defined (BANG_HISTORY) + history_expansion_inhibited = old_hist; +# endif free (shell_input_line); shell_input_line = expansions; @@ -2684,6 +2749,18 @@ shell_getc (remove_quoted_newline) true allocated size of shell_input_line anymore. */ shell_input_line_size = shell_input_line_len; } + /* XXX - this is grotesque */ + else if (remember_on_history && shell_input_line && + shell_input_line[0] == '\0' && + current_command_line_count > 1 && current_delimiter (dstack)) + { + /* We know shell_input_line[0] == 0 and we're reading some sort of + quoted string. This means we've got a line consisting of only + a newline in a quoted string. We want to make sure this line + gets added to the history. */ + maybe_add_history (shell_input_line); + } + #endif /* HISTORY */ if (shell_input_line) @@ -2706,17 +2783,15 @@ shell_getc (remove_quoted_newline) not already end in an EOF character. */ if (shell_input_line_terminator != EOF) { - l = shell_input_line_len; /* was a call to strlen */ - - if (l + 3 > shell_input_line_size) + if (shell_input_line_len + 3 > shell_input_line_size) shell_input_line = xrealloc (shell_input_line, 1 + (shell_input_line_size += 2)); - shell_input_line[l] = '\n'; - shell_input_line[l + 1] = '\0'; + shell_input_line[shell_input_line_len] = '\n'; + shell_input_line[shell_input_line_len + 1] = '\0'; } } - + c = shell_input_line[shell_input_line_index]; if (c) @@ -2726,7 +2801,8 @@ shell_getc (remove_quoted_newline) shell_input_line[shell_input_line_index] == '\n') { prompt_again (); - goto restart_read_next_line; + line_number++; + goto restart_read; } #if defined (ALIAS) @@ -2737,20 +2813,24 @@ shell_getc (remove_quoted_newline) to. */ if (!c && (pushed_string_list != (STRING_SAVER *)NULL)) { - pop_string (); - c = shell_input_line[shell_input_line_index]; - if (c) - shell_input_line_index++; + if (mustpop) + { + pop_string (); + c = shell_input_line[shell_input_line_index]; + if (c) + shell_input_line_index++; + mustpop--; + } + else + { + mustpop++; + c = ' '; + } } #endif /* ALIAS */ if (!c && shell_input_line_terminator == EOF) - { - if (shell_input_line_index != 0) - return ('\n'); - else - return (EOF); - } + return ((shell_input_line_index != 0) ? '\n' : EOF); return ((unsigned char)c); } @@ -2764,7 +2844,15 @@ shell_ungetc (c) shell_input_line[--shell_input_line_index] = c; } -/* Discard input until CHARACTER is seen. */ +static void +shell_ungetchar () +{ + if (shell_input_line && shell_input_line_index) + shell_input_line_index--; +} + +/* Discard input until CHARACTER is seen, then push that character back + onto the input stream. */ static void discard_until (character) int character; @@ -2777,13 +2865,6 @@ discard_until (character) if (c != EOF) shell_ungetc (c); } - -/* Place to remember the token. We try to keep the buffer - at a reasonable size, but it can grow. */ -static char *token = (char *)NULL; - -/* Current size of the token buffer. */ -static int token_buffer_size = 0; void execute_prompt_command (command) @@ -2811,10 +2892,17 @@ execute_prompt_command (command) bind_variable ("_", last_lastarg); FREE (last_lastarg); - if (token_to_read == '\n') + if (token_to_read == '\n') /* reset_parser was called */ token_to_read = 0; } +/* Place to remember the token. We try to keep the buffer + at a reasonable size, but it can grow. */ +static char *token = (char *)NULL; + +/* Current size of the token buffer. */ +static int token_buffer_size; + /* Command to read_token () explaining what we want it to do. */ #define READ 0 #define RESET 1 @@ -2823,10 +2911,10 @@ execute_prompt_command (command) /* Function for yyparse to call. yylex keeps track of the last two tokens read, and calls read_token. */ - +static int yylex () { - if (interactive && (!current_token || current_token == '\n')) + if (interactive && (current_token == 0 || current_token == '\n')) { /* Before we print a prompt, we might have to check mailboxes. We do this only if it is time to do so. Notice that only here @@ -2844,35 +2932,16 @@ yylex () prompt_again (); } + two_tokens_ago = token_before_that; token_before_that = last_read_token; last_read_token = current_token; current_token = read_token (READ); return (current_token); } -/* Called from shell.c when Control-C is typed at top level. Or - by the error rule at top level. */ -reset_parser () -{ - read_token (RESET); -} - /* When non-zero, we have read the required tokens which allow ESAC to be the next one read. */ -static int allow_esac_as_next = 0; - -/* When non-zero, accept single '{' as a token itself. */ -static int allow_open_brace = 0; - -/* DELIMITERS is a stack of the nested delimiters that we have - encountered so far. */ -static char *delimiters = (char *)NULL; - -/* Offset into the stack of delimiters. */ -int delimiter_depth = 0; - -/* How many slots are allocated to DELIMITERS. */ -static int delimiter_space = 0; +static int esacs_needed_count; void gather_here_documents () @@ -2885,32 +2954,16 @@ gather_here_documents () } } -/* Macro for accessing the top delimiter on the stack. Returns the - delimiter or zero if none. */ -#define current_delimiter() \ - (delimiter_depth ? delimiters[delimiter_depth - 1] : 0) - -#define push_delimiter(character) \ - do \ - { \ - if (delimiter_depth + 2 > delimiter_space) \ - delimiters = xrealloc \ - (delimiters, (delimiter_space += 10) * sizeof (char)); \ - delimiters[delimiter_depth] = character; \ - delimiter_depth++; \ - } \ - while (0) - /* When non-zero, an open-brace used to create a group is awaiting a close brace partner. */ -static int open_brace_awaiting_satisfaction = 0; +static int open_brace_count; #define command_token_position(token) \ (((token) == ASSIGNMENT_WORD) || \ ((token) != SEMI_SEMI && reserved_word_acceptable(token))) #define assignment_acceptable(token) command_token_position(token) && \ - (in_case_pattern_list == 0) + ((parser_state & PST_CASEPAT) == 0) /* Check to see if TOKEN is a reserved word and return the token value if it is. */ @@ -2923,101 +2976,217 @@ static int open_brace_awaiting_satisfaction = 0; for (i = 0; word_token_alist[i].word != (char *)NULL; i++) \ if (STREQ (tok, word_token_alist[i].word)) \ { \ - if (in_case_pattern_list && (word_token_alist[i].token != ESAC)) \ + if ((parser_state & PST_CASEPAT) && (word_token_alist[i].token != ESAC)) \ break; \ -\ if (word_token_alist[i].token == ESAC) \ - in_case_pattern_list = 0; \ -\ - if (word_token_alist[i].token == '{') \ - open_brace_awaiting_satisfaction++; \ -\ - if (word_token_alist[i].token == '}' && open_brace_awaiting_satisfaction) \ - open_brace_awaiting_satisfaction--; \ -\ + parser_state &= ~(PST_CASEPAT|PST_CASESTMT); \ + else if (word_token_alist[i].token == CASE) \ + parser_state |= PST_CASESTMT; \ + else if (word_token_alist[i].token == '{') \ + open_brace_count++; \ + else if (word_token_alist[i].token == '}' && open_brace_count) \ + open_brace_count--; \ return (word_token_alist[i].token); \ } \ } \ } while (0) -/* Read the next token. Command can be READ (normal operation) or - RESET (to normalize state). */ +#if defined (ALIAS) + + /* OK, we have a token. Let's try to alias expand it, if (and only if) + it's eligible. + + It is eligible for expansion if the shell is in interactive mode, and + the token is unquoted and the last token read was a command + separator (or expand_next_token is set), and we are currently + processing an alias (pushed_string_list is non-empty) and this + token is not the same as the current or any previously + processed alias. + + Special cases that disqualify: + In a pattern list in a case statement (parser_state & PST_CASEPAT). */ static int -read_token (command) - int command; +alias_expand_token (token) + char *token; { - int character; /* Current character. */ - int peek_char; /* Temporary look-ahead character. */ - int result; /* The thing to return. */ - WORD_DESC *the_word; /* The value for YYLVAL when a WORD is read. */ + char *expanded; + alias_t *ap; - if (token_buffer_size < TOKEN_DEFAULT_GROW_SIZE) + if (((parser_state & PST_ALEXPNEXT) || command_token_position (last_read_token)) && + (parser_state & PST_CASEPAT) == 0) { - FREE (token); - token = xmalloc (token_buffer_size = TOKEN_DEFAULT_GROW_SIZE); + ap = find_alias (token); + + /* Currently expanding this token. */ + if (ap && (ap->flags & AL_BEINGEXPANDED)) + return (NO_EXPANSION); + + expanded = ap ? savestring (ap->value) : (char *)NULL; + if (expanded) + { + push_string (expanded, ap->flags & AL_EXPANDNEXT, ap); + return (RE_READ_TOKEN); + } + else + /* This is an eligible token that does not have an expansion. */ + return (NO_EXPANSION); } + return (NO_EXPANSION); +} +#endif /* ALIAS */ - if (command == RESET) +/* Handle special cases of token recognition: + IN is recognized if the last token was WORD and the token + before that was FOR or CASE or SELECT. + + DO is recognized if the last token was WORD and the token + before that was FOR or SELECT. + + ESAC is recognized if the last token caused `esacs_needed_count' + to be set + + `{' is recognized if the last token as WORD and the token + before that was FUNCTION. + + `}' is recognized if there is an unclosed `{' prsent. +*/ + +static int +special_case_tokens (token) + char *token; +{ + if ((last_read_token == WORD) && +#if defined (SELECT_COMMAND) + ((token_before_that == FOR) || (token_before_that == CASE) || (token_before_that == SELECT)) && +#else + ((token_before_that == FOR) || (token_before_that == CASE)) && +#endif + (token[0] == 'i' && token[1] == 'n' && token[2] == 0)) { - delimiter_depth = 0; /* No delimiters found so far. */ - open_brace_awaiting_satisfaction = 0; - in_case_pattern_list = 0; + if (token_before_that == CASE) + { + parser_state |= PST_CASEPAT; + esacs_needed_count++; + } + return (IN); + } -#if defined (ALIAS) - if (pushed_string_list) + if (last_read_token == WORD && +#if defined (SELECT_COMMAND) + (token_before_that == FOR || token_before_that == SELECT) && +#else + (token_before_that == FOR) && +#endif + (token[0] == 'd' && token[1] == 'o' && token[2] == '\0')) + return (DO); + + /* Ditto for ESAC in the CASE case. + Specifically, this handles "case word in esac", which is a legal + construct, certainly because someone will pass an empty arg to the + case construct, and we don't want it to barf. Of course, we should + insist that the case construct has at least one pattern in it, but + the designers disagree. */ + if (esacs_needed_count) + { + esacs_needed_count--; + if (STREQ (token, "esac")) { - free_string_list (); - pushed_string_list = (STRING_SAVER *)NULL; + parser_state &= ~PST_CASEPAT; + return (ESAC); } + } - if (expanded_token_stack) + /* The start of a shell function definition. */ + if (parser_state & PST_ALLOWOPNBRC) + { + parser_state &= ~PST_ALLOWOPNBRC; + if (token[0] == '{' && token[1] == '\0') /* } */ { - free_expansion_stack (); - expanded_token_stack = (EXPANSION_SAVER *)NULL; + open_brace_count++; + function_bstart = line_number; + return ('{'); /* } */ } + } + + if (open_brace_count && reserved_word_acceptable (last_read_token) && token[0] == '}' && !token[1]) + { + open_brace_count--; /* { */ + return ('}'); + } + + /* Handle -p after `time'. */ + if (last_read_token == TIME && token[0] == '-' && token[1] == 'p' && !token[2]) + return (TIMEOPT); + + return (-1); +} - expand_next_token = 0; +/* Called from shell.c when Control-C is typed at top level. Or + by the error rule at top level. */ +void +reset_parser () +{ + dstack.delimiter_depth = 0; /* No delimiters found so far. */ + open_brace_count = 0; + + parser_state = 0; + +#if defined (ALIAS) + if (pushed_string_list) + { + free_string_list (); + pushed_string_list = (STRING_SAVER *)NULL; + } #endif /* ALIAS */ - if (shell_input_line) - { - free (shell_input_line); - shell_input_line = (char *)NULL; - shell_input_line_size = shell_input_line_index = 0; - } - last_read_token = '\n'; - token_to_read = '\n'; + if (shell_input_line) + { + free (shell_input_line); + shell_input_line = (char *)NULL; + shell_input_line_size = shell_input_line_index = 0; + } + + FREE (word_desc_to_read); + word_desc_to_read = (WORD_DESC *)NULL; + + last_read_token = '\n'; + token_to_read = '\n'; +} + +/* Read the next token. Command can be READ (normal operation) or + RESET (to normalize state). */ +static int +read_token (command) + int command; +{ + int character; /* Current character. */ + int peek_char; /* Temporary look-ahead character. */ + int result; /* The thing to return. */ + + if (command == RESET) + { + reset_parser (); return ('\n'); } if (token_to_read) { - int rt = token_to_read; + result = token_to_read; + if (token_to_read == WORD || token_to_read == ASSIGNMENT_WORD) + yylval.word = word_desc_to_read; token_to_read = 0; - return (rt); + return (result); } #if defined (ALIAS) - /* If we hit read_token () and there are no saved strings on the - pushed_string_list, then we are no longer currently expanding a - token. This can't be done in pop_stream, because pop_stream - may pop the stream before the current token has finished being - completely expanded (consider what happens when we alias foo to foo, - and then try to expand it). */ - if (!pushed_string_list && expanded_token_stack) - { - free_expansion_stack (); - expanded_token_stack = (EXPANSION_SAVER *)NULL; - } - /* This is a place to jump back to once we have successfully expanded a token with an alias and pushed the string with push_string () */ re_read_token: - #endif /* ALIAS */ /* Read a single word from input. Start by skipping blanks. */ - while ((character = shell_getc (1)) != EOF && whitespace (character)); + while ((character = shell_getc (1)) != EOF && whitespace (character)) + ; if (character == EOF) { @@ -3030,17 +3199,7 @@ read_token (command) /* A comment. Discard until EOL or EOF, and then return a newline. */ discard_until ('\n'); shell_getc (0); - - /* If we're about to return an unquoted newline, we can go and collect - the text of any pending here documents. */ - if (need_here_doc) - gather_here_documents (); - -#if defined (ALIAS) - expand_next_token = 0; -#endif /* ALIAS */ - - return ('\n'); + character = '\n'; /* this will take the next if statement and return. */ } if (character == '\n') @@ -3051,31 +3210,30 @@ read_token (command) gather_here_documents (); #if defined (ALIAS) - expand_next_token = 0; + parser_state &= ~PST_ALEXPNEXT; #endif /* ALIAS */ return (character); } - if (member (character, "()<>;&|")) + /* Shell meta-characters. */ + if (shellmeta (character) && ((parser_state & PST_DBLPAREN) == 0)) { #if defined (ALIAS) /* Turn off alias tokenization iff this character sequence would not leave us ready to read a command. */ if (character == '<' || character == '>') - expand_next_token = 0; + parser_state &= ~PST_ALEXPNEXT; #endif /* ALIAS */ - /* Please note that the shell does not allow whitespace to - appear in between tokens which are character pairs, such as - "<<" or ">>". I believe this is the correct behaviour. */ - if (character == (peek_char = shell_getc (1))) + peek_char = shell_getc (1); + if (character == peek_char) { switch (character) { + case '<': /* If '<' then we could be at "<<" or at "<<-". We have to look ahead one more character. */ - case '<': peek_char = shell_getc (1); if (peek_char == '-') return (LESS_LESS_MINUS); @@ -3089,9 +3247,9 @@ read_token (command) return (GREATER_GREATER); case ';': - in_case_pattern_list = 1; + parser_state |= PST_CASEPAT; #if defined (ALIAS) - expand_next_token = 0; + parser_state &= ~PST_ALEXPNEXT; #endif /* ALIAS */ return (SEMI_SEMI); @@ -3100,526 +3258,637 @@ read_token (command) case '|': return (OR_OR); - } - } - else - { - if (peek_char == '&') - { - switch (character) + +#if defined (DPAREN_ARITHMETIC) + case '(': /* ) */ + if (reserved_word_acceptable (last_read_token)) { - case '<': return (LESS_AND); - case '>': return (GREATER_AND); + parser_state |= PST_DBLPAREN; + yylval.word = make_word ("let"); + return (WORD); } + break; +#endif } - if (character == '<' && peek_char == '>') - return (LESS_GREATER); - if (character == '>' && peek_char == '|') - return (GREATER_BAR); - if (peek_char == '>' && character == '&') - return (AND_GREATER); } + else if (character == '<' && peek_char == '&') + return (LESS_AND); + else if (character == '>' && peek_char == '&') + return (GREATER_AND); + else if (character == '<' && peek_char == '>') + return (LESS_GREATER); + else if (character == '>' && peek_char == '|') + return (GREATER_BAR); + else if (peek_char == '>' && character == '&') + return (AND_GREATER); + shell_ungetc (peek_char); /* If we look like we are reading the start of a function definition, then let the reader know about it so that we will do the right thing with `{'. */ - if (character == ')' && - last_read_token == '(' && token_before_that == WORD) + if (character == ')' && last_read_token == '(' && token_before_that == WORD) { - allow_open_brace = 1; + parser_state |= PST_ALLOWOPNBRC; #if defined (ALIAS) - expand_next_token = 0; + parser_state &= ~PST_ALEXPNEXT; #endif /* ALIAS */ + function_dstart = line_number; } - if (in_case_pattern_list && (character == ')')) - in_case_pattern_list = 0; + /* case pattern lists may be preceded by an optional left paren. If + we're not trying to parse a case pattern list, the left paren + indicates a subshell. */ + if (character == '(' && (parser_state & PST_CASEPAT) == 0) /* ) */ + parser_state |= PST_SUBSHELL; + /*(*/ + else if ((parser_state & PST_CASEPAT) && character == ')') + parser_state &= ~PST_CASEPAT; + /*(*/ + else if ((parser_state & PST_SUBSHELL) && character == ')') + parser_state &= ~PST_SUBSHELL; #if defined (PROCESS_SUBSTITUTION) /* Check for the constructs which introduce process substitution. Shells running in `posix mode' don't do process substitution. */ if (posixly_correct || - (((character == '>' || character == '<') && peek_char == '(') == 0)) + ((character != '>' && character != '<') || peek_char != '(')) #endif /* PROCESS_SUBSTITUTION */ return (character); } /* Hack <&- (close stdin) case. */ - if (character == '-') - { - switch (last_read_token) - { - case LESS_AND: - case GREATER_AND: - return (character); - } - } - + if (character == '-' && (last_read_token == LESS_AND || last_read_token == GREATER_AND)) + return (character); + /* Okay, if we got this far, we have to read a word. Read one, and then check it against the known ones. */ - { - /* Index into the token that we are building. */ - int token_index = 0; - - /* ALL_DIGITS becomes zero when we see a non-digit. */ - int all_digits = digit (character); - - /* DOLLAR_PRESENT becomes non-zero if we see a `$'. */ - int dollar_present = 0; - - /* QUOTED becomes non-zero if we see one of ("), ('), (`), or (\). */ - int quoted = 0; - - /* Non-zero means to ignore the value of the next character, and just - to add it no matter what. */ - int pass_next_character = 0; + result = read_token_word (character); +#if defined (ALIAS) + if (result == RE_READ_TOKEN) + goto re_read_token; +#endif + return result; +} - /* Non-zero means parsing a dollar-paren construct. It is the count of - un-quoted closes we need to see. */ - int dollar_paren_level = 0; +/* Match a $(...) or other grouping construct. This has to handle embedded + quoted strings ('', ``, "") and nested constructs. It also must handle + reprompting the user, if necessary, after reading a newline, and returning + correct error values if it reads EOF. */ +static char matched_pair_error; +static char * +parse_matched_pair (qc, open, close, lenp, flags) + int qc; /* `"' if this construct is within double quotes */ + int open, close; + int *lenp, flags; +{ + int count, ch, was_dollar; + int pass_next_character, nestlen, start_lineno; + char *ret, *nestret; + int retind, retsize; - /* Non-zero means parsing a dollar-bracket construct ($[...]). It is - the count of un-quoted `]' characters we need to see. */ - int dollar_bracket_level = 0; + count = 1; + pass_next_character = was_dollar = 0; - /* Non-zero means parsing a `${' construct. It is the count of - un-quoted `}' we need to see. */ - int dollar_brace_level = 0; + ret = xmalloc (retsize = 64); + retind = 0; - /* A level variable for parsing '${ ... }' constructs inside of double - quotes. */ - int delimited_brace_level = 0; + start_lineno = line_number; + while (count) + { + ch = shell_getc (qc != '\'' && pass_next_character == 0); + if (ch == EOF) + { + free (ret); + parser_error (start_lineno, "unexpected EOF while looking for matching `%c'", close); + EOF_Reached = 1; /* XXX */ + return (&matched_pair_error); + } - /* A boolean variable denoting whether or not we are currently parsing - a double-quoted string embedded in a $( ) or ${ } construct. */ - int embedded_quoted_string = 0; + /* Possible reprompting. */ + if (ch == '\n' && interactive && + (bash_input.type == st_stdin || bash_input.type == st_stream)) + prompt_again (); - /* Another level variable. This one is for dollar_parens inside of - double-quotes. */ - int delimited_paren_level = 0; + if (pass_next_character) /* last char was backslash */ + { + pass_next_character = 0; + if (qc != '\'' && ch == '\n') /* double-quoted \ disappears. */ + { + if (retind > 0) retind--; /* swallow previously-added backslash */ + continue; + } - /* The current delimiting character. */ - int cd; + RESIZE_MALLOCED_BUFFER (ret, retind, 2, retsize, 64); + if (ch == CTLESC || ch == CTLNUL) + ret[retind++] = CTLESC; + ret[retind++] = ch; + continue; + } + else if (ch == CTLESC || ch == CTLNUL) /* special shell escapes */ + { + RESIZE_MALLOCED_BUFFER (ret, retind, 2, retsize, 64); + ret[retind++] = CTLESC; + ret[retind++] = ch; + continue; + } + else if (ch == close) /* ending delimiter */ + count--; + else if (ch == open) /* nested begin */ + count++; - for (;;) - { - if (character == EOF) - goto got_token; + /* Add this character. */ + RESIZE_MALLOCED_BUFFER (ret, retind, 1, retsize, 64); + ret[retind++] = ch; - if (pass_next_character) - { - pass_next_character = 0; - goto got_character; - } + if (open == '\'') /* '' inside grouping construct */ + continue; - cd = current_delimiter (); + if (ch == '\\') /* backslashes */ + pass_next_character++; - if (cd && character == '\\' && cd != '\'') - { - peek_char = shell_getc (0); - if (peek_char != '\\') - shell_ungetc (peek_char); - else - { - token[token_index++] = character; - goto got_character; - } - } - - /* Handle backslashes. Quote lots of things when not inside of - double-quotes, quote some things inside of double-quotes. */ - - if (character == '\\' && (!delimiter_depth || cd != '\'')) - { - peek_char = shell_getc (0); - - /* Backslash-newline is ignored in all cases excepting - when quoted with single quotes. */ - if (peek_char == '\n') - { - character = '\n'; - goto next_character; - } - else - { - shell_ungetc (peek_char); + if (open != close) /* a grouping construct */ + { + if (shellquote (ch)) + { + /* '', ``, or "" inside $(...) or other grouping construct. */ + push_delimiter (dstack, ch); + nestret = parse_matched_pair (ch, ch, ch, &nestlen, 0); + pop_delimiter (dstack); + if (nestret == &matched_pair_error) + { + free (ret); + return &matched_pair_error; + } + if (nestlen) + { + RESIZE_MALLOCED_BUFFER (ret, retind, nestlen, retsize, 64); + strcpy (ret + retind, nestret); + retind += nestlen; + } + FREE (nestret); + } + } + /* Parse an old-style command substitution within double quotes as a + single word. */ + /* XXX - sh and ksh93 don't do this - XXX */ + else if (open == '"' && ch == '`') + { + nestret = parse_matched_pair (0, '`', '`', &nestlen, 0); + if (nestret == &matched_pair_error) + { + free (ret); + return &matched_pair_error; + } + if (nestlen) + { + RESIZE_MALLOCED_BUFFER (ret, retind, nestlen, retsize, 64); + strcpy (ret + retind, nestret); + retind += nestlen; + } + FREE (nestret); + } + else if (was_dollar && (ch == '(' || ch == '{' || ch == '[')) /* ) } ] */ + /* check for $(), $[], or ${} inside quoted string. */ + { + if (open == ch) /* undo previous increment */ + count--; + if (ch == '(') /* ) */ + nestret = parse_matched_pair (0, '(', ')', &nestlen, 0); + else if (ch == '{') /* } */ + nestret = parse_matched_pair (0, '{', '}', &nestlen, 0); + else if (ch == '[') /* ] */ + nestret = parse_matched_pair (0, '[', ']', &nestlen, 0); + if (nestret == &matched_pair_error) + { + free (ret); + return &matched_pair_error; + } + if (nestlen) + { + RESIZE_MALLOCED_BUFFER (ret, retind, nestlen, retsize, 64); + strcpy (ret + retind, nestret); + retind += nestlen; + } + FREE (nestret); + } + was_dollar = (ch == '$'); + } - /* If the next character is to be quoted, do it now. */ - if (!cd || cd == '`' || - (cd == '"' && member (peek_char, slashify_in_quotes))) - { - pass_next_character++; - quoted = 1; - goto got_character; - } - } - } - - /* This is a hack, in its present form. If a backquote substitution - appears within double quotes, everything within the backquotes - should be read as part of a single word. Jesus. Now I see why - Korn introduced the $() form. */ - if (delimiter_depth && (cd == '"') && (character == '`')) - { - push_delimiter (character); - goto got_character; - } - - cd = current_delimiter (); /* XXX - may not need */ - if (delimiter_depth) - { - if (character == cd) - { - /* If we see a double quote while parsing a double-quoted - $( ) or ${ }, and we have not seen ) or }, respectively, - note that we are in the middle of reading an embedded - quoted string. */ - if ((delimited_paren_level || delimited_brace_level) && - (character == '"')) - { - embedded_quoted_string = !embedded_quoted_string; - goto got_character; - } - - delimiter_depth--; - goto got_character; - } - } + ret[retind] = '\0'; + if (lenp) + *lenp = retind; + return ret; +} - if (cd != '\'') - { -#if defined (PROCESS_SUBSTITUTION) - if (character == '$' || character == '<' || character == '>') -#else - if (character == '$') -#endif /* !PROCESS_SUBSTITUTION */ - { - /* If we're in the middle of parsing a $( ) or ${ } - construct with an embedded quoted string, don't - bother looking at this character any further. */ - if (embedded_quoted_string) - goto got_character; - - peek_char = shell_getc (1); - shell_ungetc (peek_char); - if (peek_char == '(') - { - if (!delimiter_depth) - dollar_paren_level++; - else - delimited_paren_level++; +static int +read_token_word (character) + int character; +{ + /* The value for YYLVAL when a WORD is read. */ + WORD_DESC *the_word; - pass_next_character++; - goto got_character; - } - else if (peek_char == '[' && character == '$') - { - if (!delimiter_depth) - dollar_bracket_level++; + /* Index into the token that we are building. */ + int token_index; - pass_next_character++; - goto got_character; - } - /* This handles ${...} constructs. */ - else if (peek_char == '{' && character == '$') - { - if (!delimiter_depth) - dollar_brace_level++; - else - delimited_brace_level++; + /* ALL_DIGITS becomes zero when we see a non-digit. */ + int all_digits; - pass_next_character++; - goto got_character; - } - } + /* DOLLAR_PRESENT becomes non-zero if we see a `$'. */ + int dollar_present; - /* If we are parsing a $() or $[] construct, we need to balance - parens and brackets inside the construct. This whole function - could use a rewrite. */ - if (character == '(' && !embedded_quoted_string) - { - if (delimiter_depth && delimited_paren_level) - delimited_paren_level++; + /* QUOTED becomes non-zero if we see one of ("), ('), (`), or (\). */ + int quoted; - if (!delimiter_depth && dollar_paren_level) - dollar_paren_level++; - } + /* Non-zero means to ignore the value of the next character, and just + to add it no matter what. */ + int pass_next_character; - if (character == '[') - { - if (!delimiter_depth && dollar_bracket_level) - dollar_bracket_level++; - } + /* The current delimiting character. */ + int cd; + int result, peek_char; + char *ttok, *ttrans; + int ttoklen, ttranslen; - if (character == '{' && !embedded_quoted_string) - { - if (delimiter_depth && delimited_brace_level) - delimited_brace_level++; + if (token_buffer_size < TOKEN_DEFAULT_GROW_SIZE) + { + FREE (token); + token = xmalloc (token_buffer_size = TOKEN_DEFAULT_GROW_SIZE); + } - if (!delimiter_depth && dollar_brace_level) - dollar_brace_level++; - } + token_index = 0; + all_digits = digit (character); + dollar_present = quoted = pass_next_character = 0; - /* This code needs to take into account whether we are inside a - case statement pattern list, and whether this paren is supposed - to terminate it (hey, it could happen). It's not as simple - as just using in_case_pattern_list, because we're not parsing - anything while we're reading a $( ) construct. Maybe we - should move that whole mess into the yacc parser. */ - if (character == ')' && !embedded_quoted_string) - { - if (delimiter_depth && delimited_paren_level) - delimited_paren_level--; + for (;;) + { + if (character == EOF) + goto got_token; - if (!delimiter_depth && dollar_paren_level) - { - dollar_paren_level--; - goto got_character; - } - } + if (pass_next_character) + { + pass_next_character = 0; + goto got_character; + } - if (character == ']') - { - if (!delimiter_depth && dollar_bracket_level) - { - dollar_bracket_level--; - goto got_character; - } - } + cd = current_delimiter (dstack); - if (character == '}' && !embedded_quoted_string) - { - if (delimiter_depth && delimited_brace_level) - delimited_brace_level--; + /* Handle backslashes. Quote lots of things when not inside of + double-quotes, quote some things inside of double-quotes. */ + if (character == '\\') + { + peek_char = shell_getc (0); - if (!delimiter_depth && dollar_brace_level) - { - dollar_brace_level--; - goto got_character; - } - } - } + /* Backslash-newline is ignored in all cases except + when quoted with single quotes. */ + if (peek_char == '\n') + { + character = '\n'; + goto next_character; + } + else + { + shell_ungetc (peek_char); - if (!dollar_paren_level && !dollar_bracket_level && - !dollar_brace_level && !delimiter_depth && - member (character, " \t\n;&()|<>")) - { - shell_ungetc (character); - goto got_token; - } - - if (!delimiter_depth) - { - if (character == '"' || character == '`' || character == '\'') - { - push_delimiter (character); + /* If the next character is to be quoted, note it now. */ + if (cd == 0 || cd == '`' || + (cd == '"' && member (peek_char, slashify_in_quotes))) + pass_next_character++; - quoted = 1; - goto got_character; - } - } + quoted = 1; + goto got_character; + } + } - if (all_digits) - all_digits = digit (character); - if (character == '$') - dollar_present = 1; +#if defined (DPAREN_ARITHMETIC) + /* Parse a ksh-style ((...)) expression. */ + if (parser_state & PST_DBLPAREN) + { + int exp_lineno; - got_character: + /* If we've already consumed a right paren that should be part of + the expression, push it back so the paren matching code won't + return prematurely. */ + if (character == '(') /* ) */ + shell_ungetc (character); + exp_lineno = line_number; + ttok = parse_matched_pair (0, '(', ')', &ttoklen, 0); + parser_state &= ~PST_DBLPAREN; + if (ttok == &matched_pair_error) + return -1; + /* Check that the next character is the closing right paren. If + not, this is a syntax error. ( */ + if (shell_getc (0) != ')') + { + FREE (ttok); /* ( */ + parser_error (exp_lineno, "missing closing `)' for arithmetic expression"); + return -1; + } + RESIZE_MALLOCED_BUFFER (token, token_index, ttoklen + 4, + token_buffer_size, TOKEN_DEFAULT_GROW_SIZE); + token[token_index++] = '"'; + if (character != '(') /* ) */ + token[token_index++] = character; + strncpy (token + token_index, ttok, ttoklen - 1); + token_index += ttoklen - 1; + token[token_index++] = '"'; + FREE (ttok); + dollar_present = all_digits = 0; + quoted = 1; + goto got_token; + } +#endif /* DPAREN_ARITHMETIC */ - if (character == CTLESC || character == CTLNUL) - token[token_index++] = CTLESC; + /* Parse a matched pair of quote characters. */ + if (shellquote (character)) + { + push_delimiter (dstack, character); + ttok = parse_matched_pair (character, character, character, &ttoklen, 0); + pop_delimiter (dstack); + if (ttok == &matched_pair_error) + return -1; /* Bail immediately. */ + RESIZE_MALLOCED_BUFFER (token, token_index, ttoklen + 2, + token_buffer_size, TOKEN_DEFAULT_GROW_SIZE); + token[token_index++] = character; + strcpy (token + token_index, ttok); + token_index += ttoklen; + all_digits = 0; + quoted = 1; + dollar_present |= (character == '"' && strchr (ttok, '$') != 0); + FREE (ttok); + goto next_character; + } - token[token_index++] = character; + /* If the delimiter character is not single quote, parse some of + the shell expansions that must be read as a single word. */ +#if defined (PROCESS_SUBSTITUTION) + if (character == '$' || character == '<' || character == '>') +#else + if (character == '$') +#endif /* !PROCESS_SUBSTITUTION */ + { + peek_char = shell_getc (1); + /* $(...), <(...), >(...), $((...)), ${...}, and $[...] constructs */ + if (peek_char == '(' || + ((peek_char == '{' || peek_char == '[') && character == '$')) /* ) ] } */ + { + if (peek_char == '{') /* } */ + ttok = parse_matched_pair (cd, '{', '}', &ttoklen, 0); + else if (peek_char == '(') /* ) */ + ttok = parse_matched_pair (cd, '(', ')', &ttoklen, 0); + else + ttok = parse_matched_pair (cd, '[', ']', &ttoklen, 0); + if (ttok == &matched_pair_error) + return -1; /* Bail immediately. */ + RESIZE_MALLOCED_BUFFER (token, token_index, ttoklen + 2, + token_buffer_size, + TOKEN_DEFAULT_GROW_SIZE); + token[token_index++] = character; + token[token_index++] = peek_char; + strcpy (token + token_index, ttok); + token_index += ttoklen; + FREE (ttok); + dollar_present = 1; + all_digits = 0; + goto next_character; + } + /* This handles $'...' and $"..." new-style quoted strings. */ + else if (character == '$' && (peek_char == '\'' || peek_char == '"')) + { + ttok = parse_matched_pair (peek_char, peek_char, peek_char, &ttoklen, 0); + if (ttok == &matched_pair_error) + return -1; + if (peek_char == '\'') + ttrans = ansiexpand (ttok, 0, ttoklen - 1, &ttranslen); + else + ttrans = localeexpand (ttok, 0, ttoklen - 1, &ttranslen); + free (ttok); + RESIZE_MALLOCED_BUFFER (token, token_index, ttranslen + 2, + token_buffer_size, + TOKEN_DEFAULT_GROW_SIZE); + token[token_index++] = peek_char; + strcpy (token + token_index, ttrans); + token_index += ttranslen; + token[token_index++] = peek_char; + FREE (ttrans); + quoted = 1; + all_digits = 0; + goto next_character; + } + else + shell_ungetc (peek_char); + } - if (token_index == (token_buffer_size - 1)) - { - token_buffer_size += TOKEN_DEFAULT_GROW_SIZE; - token = xrealloc (token, token_buffer_size); - } - next_character: - if (character == '\n' && interactive && bash_input.type != st_string) - prompt_again (); +#if defined (ARRAY_VARS) + /* Identify possible compound array variable assignment. */ + else if (character == '=') + { + peek_char = shell_getc (1); + if (peek_char == '(') /* ) */ + { + ttok = parse_matched_pair (cd, '(', ')', &ttoklen, 0); + if (ttok == &matched_pair_error) + return -1; /* Bail immediately. */ + RESIZE_MALLOCED_BUFFER (token, token_index, ttoklen + 2, + token_buffer_size, + TOKEN_DEFAULT_GROW_SIZE); + token[token_index++] = character; + token[token_index++] = peek_char; + strcpy (token + token_index, ttok); + token_index += ttoklen; + FREE (ttok); + all_digits = 0; + goto next_character; + } + else + shell_ungetc (peek_char); + } +#endif - /* We want to remove quoted newlines (that is, a \ pair) - unless we are within single quotes or pass_next_character is - set (the shell equivalent of literal-next). */ - character = shell_getc - ((current_delimiter () != '\'') && (!pass_next_character)); - } + /* When not parsing a multi-character word construct, shell meta- + characters break words. */ + if (shellbreak (character)) + { + shell_ungetc (character); + goto got_token; + } - got_token: + got_character: - token[token_index] = '\0'; - - if ((delimiter_depth || dollar_paren_level || dollar_bracket_level) && - character == EOF) - { - char reporter = '\0'; + all_digits &= digit (character); + dollar_present |= character == '$'; - if (!delimiter_depth) - { - if (dollar_paren_level) - reporter = ')'; - else if (dollar_bracket_level) - reporter = ']'; - } + if (character == CTLESC || character == CTLNUL) + token[token_index++] = CTLESC; - if (!reporter) - reporter = current_delimiter (); + token[token_index++] = character; - report_error ("unexpected EOF while looking for `%c'", reporter); - return (-1); - } + RESIZE_MALLOCED_BUFFER (token, token_index, 1, token_buffer_size, + TOKEN_DEFAULT_GROW_SIZE); - if (all_digits) - { - /* Check to see what thing we should return. If the last_read_token - is a `<', or a `&', or the character which ended this token is - a '>' or '<', then, and ONLY then, is this input token a NUMBER. - Otherwise, it is just a word, and should be returned as such. */ - - if (character == '<' || character == '>' || - last_read_token == LESS_AND || last_read_token == GREATER_AND) - { - yylval.number = atoi (token); - return (NUMBER); - } - } + next_character: + if (character == '\n' && interactive && + (bash_input.type == st_stdin || bash_input.type == st_stream)) + prompt_again (); - /* Handle special case. IN is recognized if the last token - was WORD and the token before that was FOR or CASE. */ - if ((last_read_token == WORD) && -#if defined (SELECT_COMMAND) - ((token_before_that == FOR) || (token_before_that == CASE) || (token_before_that == SELECT)) && -#else - ((token_before_that == FOR) || (token_before_that == CASE)) && -#endif - (token[0] == 'i' && token[1] == 'n' && !token[2])) - { - if (token_before_that == CASE) - { - in_case_pattern_list = 1; - allow_esac_as_next++; - } - return (IN); - } + /* We want to remove quoted newlines (that is, a \ pair) + unless we are within single quotes or pass_next_character is + set (the shell equivalent of literal-next). */ + cd = current_delimiter (dstack); + character = shell_getc (cd != '\'' && pass_next_character == 0); + } /* end for (;;) */ - /* Ditto for DO in the FOR case. */ -#if defined (SELECT_COMMAND) - if ((last_read_token == WORD) && ((token_before_that == FOR) || (token_before_that == SELECT)) && -#else - if ((last_read_token == WORD) && (token_before_that == FOR) && -#endif - (token[0] == 'd' && token[1] == 'o' && !token[2])) - return (DO); - - /* Ditto for ESAC in the CASE case. - Specifically, this handles "case word in esac", which is a legal - construct, certainly because someone will pass an empty arg to the - case construct, and we don't want it to barf. Of course, we should - insist that the case construct has at least one pattern in it, but - the designers disagree. */ - if (allow_esac_as_next) - { - allow_esac_as_next--; - if (STREQ (token, "esac")) - { - in_case_pattern_list = 0; - return (ESAC); - } - } +got_token: - /* Ditto for `{' in the FUNCTION case. */ - if (allow_open_brace) + token[token_index] = '\0'; + + /* Check to see what thing we should return. If the last_read_token + is a `<', or a `&', or the character which ended this token is + a '>' or '<', then, and ONLY then, is this input token a NUMBER. + Otherwise, it is just a word, and should be returned as such. */ + if (all_digits && (character == '<' || character == '>' || + last_read_token == LESS_AND || + last_read_token == GREATER_AND)) { - allow_open_brace = 0; - if (token[0] == '{' && !token[1]) - { - open_brace_awaiting_satisfaction++; - return ('{'); - } + yylval.number = atoi (token); + return (NUMBER); } - if (posixly_correct) - CHECK_FOR_RESERVED_WORD (token); + /* Check for special case tokens. */ + result = special_case_tokens (token); + if (result >= 0) + return result; #if defined (ALIAS) - /* OK, we have a token. Let's try to alias expand it, if (and only if) - it's eligible. + /* Posix.2 does not allow reserved words to be aliased, so check for all + of them, including special cases, before expanding the current token + as an alias. */ + if (posixly_correct) + CHECK_FOR_RESERVED_WORD (token); + + /* Aliases are expanded iff EXPAND_ALIASES is non-zero, and quoting + inhibits alias expansion. */ + if (expand_aliases && quoted == 0) + { + result = alias_expand_token (token); + if (result == RE_READ_TOKEN) + return (RE_READ_TOKEN); + else if (result == NO_EXPANSION) + parser_state &= ~PST_ALEXPNEXT; + } - It is eligible for expansion if the shell is in interactive mode, and - the token is unquoted and the last token read was a command - separator (or expand_next_token is set), and we are currently - processing an alias (pushed_string_list is non-empty) and this - token is not the same as the current or any previously - processed alias. + /* If not in Posix.2 mode, check for reserved words after alias + expansion. */ + if (posixly_correct == 0) +#endif + CHECK_FOR_RESERVED_WORD (token); + + the_word = (WORD_DESC *)xmalloc (sizeof (WORD_DESC)); + the_word->word = xmalloc (1 + token_index); + the_word->flags = 0; + strcpy (the_word->word, token); + if (dollar_present) + the_word->flags |= W_HASDOLLAR; + if (quoted) + the_word->flags |= W_QUOTED; + /* A word is an assignment if it appears at the beginning of a + simple command, or after another assignment word. This is + context-dependent, so it cannot be handled in the grammar. */ + if (assignment (token)) + { + the_word->flags |= W_ASSIGNMENT; + /* Don't perform word splitting on assignment statements. */ + if (assignment_acceptable (last_read_token)) + the_word->flags |= W_NOSPLIT; + } - Special cases that disqualify: - In a pattern list in a case statement (in_case_pattern_list). */ - if (interactive_shell && !quoted && !in_case_pattern_list && - (expand_next_token || command_token_position (last_read_token))) - { - char *alias_expand_word (), *expanded; + yylval.word = the_word; - if (expanded_token_stack && token_has_been_expanded (token)) - goto no_expansion; + result = ((the_word->flags & (W_ASSIGNMENT|W_NOSPLIT)) == (W_ASSIGNMENT|W_NOSPLIT)) + ? ASSIGNMENT_WORD : WORD; - expanded = alias_expand_word (token); - if (expanded) - { - int len = strlen (expanded), expand_next; + if (last_read_token == FUNCTION) + { + parser_state |= PST_ALLOWOPNBRC; + function_dstart = line_number; + } - /* Erase the current token. */ - token_index = 0; + return (result); +} + +/* $'...' ANSI-C expand the portion of STRING between START and END and + return the result. The result cannot be longer than the input string. */ +static char * +ansiexpand (string, start, end, lenp) + char *string; + int start, end, *lenp; +{ + char *temp, *t; + int len, tlen; - expand_next = (expanded[len - 1] == ' ') || - (expanded[len - 1] == '\t'); + temp = xmalloc (end - start + 1); + for (tlen = 0, len = start; len < end; ) + temp[tlen++] = string[len++]; + temp[tlen] = '\0'; - push_string (expanded, expand_next, token); - goto re_read_token; - } - else - /* This is an eligible token that does not have an expansion. */ -no_expansion: - expand_next_token = 0; - } - else - { - expand_next_token = 0; - } -#endif /* ALIAS */ + if (*temp) + { + t = ansicstr (temp, tlen, (int *)NULL); + free (temp); + if (lenp) + *lenp = strlen (t); + return (t); + } + else + { + if (lenp) + *lenp = 0; + return (temp); + } +} - if (!posixly_correct) - CHECK_FOR_RESERVED_WORD (token); +/* $"..." -- Translate the portion of STRING between START and END + according to current locale using gettext (if available) and return + the result. The caller will take care of leaving the quotes intact. + The string will be left without the leading `$' by the caller. + If translation is performed, the translated string will be double-quoted + by the caller. The length of the translated string is returned in LENP, + if non-null. */ +static char * +localeexpand (string, start, end, lenp) + char *string; + int start, end, *lenp; +{ + int len, tlen; + char *temp, *t; - /* What if we are attempting to satisfy an open-brace grouper? */ - if (open_brace_awaiting_satisfaction && token[0] == '}' && !token[1]) - { - open_brace_awaiting_satisfaction--; - return ('}'); - } + temp = xmalloc (end - start + 1); + for (tlen = 0, len = start; len < end; ) + temp[tlen++] = string[len++]; + temp[tlen] = '\0'; - the_word = (WORD_DESC *)xmalloc (sizeof (WORD_DESC)); - the_word->word = xmalloc (1 + token_index); - strcpy (the_word->word, token); - the_word->dollar_present = dollar_present; - the_word->quoted = quoted; - the_word->assignment = assignment (token); - - yylval.word = the_word; - result = WORD; - - /* A word is an assignment if it appears at the beginning of a - simple command, or after another assignment word. This is - context-dependent, so it cannot be handled in the grammar. */ - if (assignment_acceptable (last_read_token) && the_word->assignment) - result = ASSIGNMENT_WORD; - - if (last_read_token == FUNCTION) - allow_open_brace = 1; - } - return (result); + /* If we're just dumping translatable strings, don't do anything. */ + if (dump_translatable_strings) + { + printf ("\"%s\"\n", temp); + if (lenp) + *lenp = tlen; + return (temp); + } + else if (*temp) + { + t = localetrans (temp, tlen, &len); + free (temp); + if (lenp) + *lenp = len; + return (t); + } + else + { + if (lenp) + *lenp = 0; + return (temp); + } } /* Return 1 if TOKEN is a token that after being read would allow @@ -3628,15 +3897,12 @@ static int reserved_word_acceptable (token) int token; { -#if 0 - if (member (token, "\n;()|&{") || -#else if (token == '\n' || token == ';' || token == '(' || token == ')' || token == '|' || token == '&' || token == '{' || -#endif token == '}' || /* XXX */ token == AND_AND || token == BANG || + token == TIME || token == TIMEOPT || token == DO || token == ELIF || token == ELSE || @@ -3662,12 +3928,13 @@ find_reserved_word (token) char *token; { int i; - for (i = 0; word_token_alist[i].word != (char *)NULL; i++) + for (i = 0; word_token_alist[i].word; i++) if (STREQ (token, word_token_alist[i].word)) return i; return -1; } +#if 0 #if defined (READLINE) /* Called after each time readline is called. This insures that whatever the new prompt string is gets propagated to readline's local prompt @@ -3675,11 +3942,11 @@ find_reserved_word (token) static void reset_readline_prompt () { + char *temp_prompt; + if (prompt_string_pointer) { - char *temp_prompt; - - temp_prompt = *prompt_string_pointer + temp_prompt = (*prompt_string_pointer) ? decode_prompt_string (*prompt_string_pointer) : (char *)NULL; @@ -3690,11 +3957,11 @@ reset_readline_prompt () } FREE (current_readline_prompt); - current_readline_prompt = temp_prompt; } } #endif /* READLINE */ +#endif /* 0 */ #if defined (HISTORY) /* A list of tokens which can be followed by newlines, but not by @@ -3702,29 +3969,48 @@ reset_readline_prompt () newline separator for such tokens is replaced with a space. */ static int no_semi_successors[] = { '\n', '{', '(', ')', ';', '&', '|', - CASE, DO, ELSE, IF, IN, SEMI_SEMI, THEN, UNTIL, WHILE, AND_AND, OR_OR, + CASE, DO, ELSE, IF, SEMI_SEMI, THEN, UNTIL, WHILE, AND_AND, OR_OR, IN, 0 }; /* If we are not within a delimited expression, try to be smart about which separators can be semi-colons and which must be - newlines. */ + newlines. Returns the string that should be added into the + history entry. */ char * history_delimiting_chars () { - if (!delimiter_depth) + register int i; + + if (dstack.delimiter_depth != 0) + return ("\n"); + + /* First, handle some special cases. */ + /*(*/ + /* If we just read `()', assume it's a function definition, and don't + add a semicolon. If the token before the `)' was not `(', and we're + not in the midst of parsing a case statement, assume it's a + parenthesized command and add the semicolon. */ + /*)(*/ + if (token_before_that == ')') { - register int i; + if (two_tokens_ago == '(') /*)*/ /* function def */ + return " "; + /* This does not work for subshells inside case statement + command lists. It's a suboptimal solution. */ + else if (parser_state & PST_CASESTMT) /* case statement pattern */ + return " "; + else + return "; "; /* (...) subshell */ + } - for (i = 0; no_semi_successors[i]; i++) - { - if (token_before_that == no_semi_successors[i]) - return (" "); - } - return ("; "); + for (i = 0; no_semi_successors[i]; i++) + { + if (token_before_that == no_semi_successors[i]) + return (" "); } - else - return ("\n"); + + return ("; "); } #endif /* HISTORY */ @@ -3744,7 +4030,7 @@ prompt_again () if (!prompt_string_pointer) prompt_string_pointer = &ps1_prompt; - temp_prompt = (*prompt_string_pointer) + temp_prompt = *prompt_string_pointer ? decode_prompt_string (*prompt_string_pointer) : (char *)NULL; @@ -3780,37 +4066,47 @@ print_prompt () /* Return a string which will be printed as a prompt. The string may contain special characters which are decoded as follows: - - \t the time - \d the date + + \a bell (ascii 07) + \e escape (ascii 033) + \d the date in Day Mon Date format + \h the hostname up to the first `.' + \H the hostname \n CRLF \s the name of the shell + \t the time in 24-hour hh:mm:ss format + \T the time in 12-hour hh:mm:ss format + \@ the time in 12-hour am/pm format + \v the version of bash (e.g., 2.00) + \V the release of bash, version + patchlevel (e.g., 2.00.0) \w the current working directory - \W the last element of PWD + \W the last element of $PWD \u your username - \h the hostname \# the command number of this command \! the history number of this command \$ a $ or a # if you are root - \ character code in octal + \nnn character code nnn in octal \\ a backslash + \[ begin a sequence of non-printing chars + \] end a sequence of non-printing chars */ #define PROMPT_GROWTH 50 char * decode_prompt_string (string) char *string; { - int result_size = PROMPT_GROWTH; - int result_index = 0; - char *result; - int c; - char *temp = (char *)NULL; WORD_LIST *list; - + char *result, *t; + struct dstack save_dstack; #if defined (PROMPT_STRING_DECODE) + int result_size, result_index; + int c, n; + char *temp, octal_string[4]; + time_t the_time; - result = xmalloc (PROMPT_GROWTH); - result[0] = 0; + result = xmalloc (result_size = PROMPT_GROWTH); + result[result_index = 0] = 0; + temp = (char *)NULL; while (c = *string++) { @@ -3831,7 +4127,7 @@ decode_prompt_string (string) string--; /* add_string increments string again. */ goto add_string; } - } + } if (c == '\\') { c = *string; @@ -3846,171 +4142,199 @@ decode_prompt_string (string) case '5': case '6': case '7': - { - char octal_string[4]; - int n; + strncpy (octal_string, string, 3); + octal_string[3] = '\0'; - strncpy (octal_string, string, 3); - octal_string[3] = '\0'; + n = read_octal (octal_string); + temp = xmalloc (3); - n = read_octal (octal_string); - temp = xmalloc (3); + if (n == CTLESC || n == CTLNUL) + { + string += 3; + temp[0] = CTLESC; + temp[1] = n; + temp[2] = '\0'; + } + else if (n == -1) + { + temp[0] = '\\'; + temp[1] = '\0'; + } + else + { + string += 3; + temp[0] = n; + temp[1] = '\0'; + } - if (n == CTLESC || n == CTLNUL) - { - string += 3; - temp[0] = CTLESC; - temp[1] = n; - temp[2] = '\0'; - } - else if (n == -1) - { - temp[0] = '\\'; - temp[1] = '\0'; - } - else - { - string += 3; - temp[0] = n; - temp[1] = '\0'; - } + c = 0; + goto add_string; - c = 0; - goto add_string; - } - case 't': case 'd': + case 'T': + case '@': /* Make the current time/date into a string. */ - { - time_t the_time = time (0); - char *ttemp = ctime (&the_time); - temp = savestring (ttemp); + the_time = time (0); + temp = ctime (&the_time); - if (c == 't') - { - strcpy (temp, temp + 11); - temp[8] = '\0'; - } - else - temp[10] = '\0'; + temp = (c != 'd') ? savestring (temp + 11) : savestring (temp); + temp[(c != 'd') ? 8 : 10] = '\0'; - goto add_string; - } + /* quick and dirty conversion to 12-hour time */ + if (c == 'T' || c == '@') + { + if (c == '@') + { + temp[5] = 'a'; /* am/pm format */ + temp[6] = 'm'; + temp[7] = '\0'; + } + c = temp[2]; + temp[2] = '\0'; + n = atoi (temp); + temp[2] = c; + n -= 12; + if (n > 0) + { + temp[0] = (n / 10) + '0'; + temp[1] = (n % 10) + '0'; + } + if (n >= 0 && temp[5] == 'a') + temp[5] = 'p'; + } + goto add_string; case 'n': - if (!no_line_editing) - temp = savestring ("\r\n"); - else - temp = savestring ("\n"); + temp = xmalloc (3); + temp[0] = no_line_editing ? '\n' : '\r'; + temp[1] = no_line_editing ? '\0' : '\n'; + temp[2] = '\0'; goto add_string; case 's': - { - temp = base_pathname (shell_name); - temp = savestring (temp); - goto add_string; - } - + temp = base_pathname (shell_name); + temp = savestring (temp); + goto add_string; + + case 'v': + case 'V': + temp = xmalloc (8); + if (c == 'v') + strcpy (temp, dist_version); + else + sprintf (temp, "%s.%d", dist_version, patch_level); + goto add_string; + case 'w': case 'W': { - /* Use the value of PWD because it is much more effecient. */ -#define EFFICIENT -#ifdef EFFICIENT - char *polite_directory_format (), t_string[MAXPATHLEN]; + /* Use the value of PWD because it is much more efficient. */ + char t_string[PATH_MAX]; temp = get_string_value ("PWD"); - if (!temp) - getwd (t_string); + if (temp == 0) + { + if (getcwd (t_string, sizeof(t_string)) == 0) + { + t_string[0] = '.'; + t_string[1] = '\0'; + } + } else strcpy (t_string, temp); -#else - getwd (t_string); -#endif /* EFFICIENT */ if (c == 'W') { - char *dir = (char *)strrchr (t_string, '/'); - if (dir && dir != t_string) - strcpy (t_string, dir + 1); - temp = savestring (t_string); + t = strrchr (t_string, '/'); + if (t && t != t_string) + strcpy (t_string, t + 1); } else - temp = savestring (polite_directory_format (t_string)); + strcpy (t_string, polite_directory_format (t_string)); + + /* If we're going to be expanding the prompt string later, + quote the directory name. */ + if (promptvars || posixly_correct) + temp = backslash_quote (t_string); + else + temp = savestring (t_string); + goto add_string; } - + case 'u': - { - temp = savestring (current_user.user_name); - goto add_string; - } + temp = savestring (current_user.user_name); + goto add_string; case 'h': - { - char *t_string; - - temp = savestring (current_host_name); - if (t_string = (char *)strchr (temp, '.')) - *t_string = '\0'; - goto add_string; - } + case 'H': + temp = savestring (current_host_name); + if (c == 'h' && (t = (char *)strchr (temp, '.'))) + *t = '\0'; + goto add_string; case '#': - { - temp = itos (current_command_number); - goto add_string; - } + temp = itos (current_command_number); + goto add_string; case '!': - { #if !defined (HISTORY) - temp = savestring ("1"); + temp = savestring ("1"); #else /* HISTORY */ - temp = itos (history_number ()); + temp = itos (history_number ()); #endif /* HISTORY */ - goto add_string; - } + goto add_string; case '$': - temp = savestring (geteuid () == 0 ? "#" : "$"); + temp = xmalloc (2); + temp[0] = current_user.euid == 0 ? '#' : '$'; + temp[1] = '\0'; goto add_string; #if defined (READLINE) case '[': case ']': - temp = xmalloc(3); + temp = xmalloc (3); temp[0] = '\001'; temp[1] = (c == '[') ? RL_PROMPT_START_IGNORE : RL_PROMPT_END_IGNORE; temp[2] = '\0'; goto add_string; -#endif +#endif /* READLINE */ case '\\': - temp = savestring ("\\"); + temp = xmalloc (2); + temp[0] = c; + temp[1] = '\0'; + goto add_string; + + case 'a': + case 'e': + temp = xmalloc (2); + temp[0] = (c == 'a') ? '\07' : '\033'; + temp[1] = '\0'; goto add_string; default: - temp = savestring ("\\ "); + temp = xmalloc (3); + temp[0] = '\\'; temp[1] = c; + temp[2] = '\0'; add_string: if (c) string++; result = sub_append_string (temp, result, &result_index, &result_size); - temp = (char *)NULL; /* Free ()'ed in sub_append_string (). */ + temp = (char *)NULL; /* Freed in sub_append_string (). */ result[result_index] = '\0'; break; } } else { - while (3 + result_index > result_size) - result = xrealloc (result, result_size += PROMPT_GROWTH); - + RESIZE_MALLOCED_BUFFER (result, result_index, 3, result_size, PROMPT_GROWTH); result[result_index++] = c; result[result_index] = '\0'; } @@ -4019,22 +4343,42 @@ decode_prompt_string (string) result = savestring (string); #endif /* !PROMPT_STRING_DECODE */ + /* Save the delimiter stack and point `dstack' to temp space so any + command substitutions in the prompt string won't result in screwing + up the parser's quoting state. */ + save_dstack = dstack; + dstack = temp_dstack; + dstack.delimiter_depth = 0; + /* Perform variable and parameter expansion and command substitution on the prompt string. */ - list = expand_string_unsplit (result, 1); - free (result); - result = string_list (list); - dispose_words (list); + if (promptvars || posixly_correct) + { + list = expand_string_unsplit (result, Q_DOUBLE_QUOTES); + free (result); + result = string_list (list); + dispose_words (list); + } + else + { + t = dequote_string (result); + free (result); + result = t; + } + + dstack = save_dstack; return (result); } /* Report a syntax error, and restart the parser. Call here for fatal errors. */ +int yyerror () { report_syntax_error ((char *)NULL); reset_parser (); + return (0); } /* Report a syntax error with line numbers, etc. @@ -4045,96 +4389,85 @@ static void report_syntax_error (message) char *message; { + char *msg, *t; + int token_end, i; + char msg2[2]; + if (message) { - if (!interactive) - { - char *name = bash_input.name ? bash_input.name : "stdin"; - report_error ("%s: line %d: `%s'", name, line_number, message); - } - else - { - if (EOF_Reached) - EOF_Reached = 0; - report_error ("%s", message); - } - + parser_error (line_number, "%s", message); + if (interactive && EOF_Reached) + EOF_Reached = 0; last_command_exit_value = EX_USAGE; return; } + /* If the line of input we're reading is not null, try to find the + objectionable token. */ if (shell_input_line && *shell_input_line) { - char *t = shell_input_line; - register int i = shell_input_line_index; - int token_end = 0; + t = shell_input_line; + i = shell_input_line_index; + token_end = 0; - if (!t[i] && i) + if (i && t[i] == '\0') i--; - while (i && (t[i] == ' ' || t[i] == '\t' || t[i] == '\n')) + while (i && (whitespace (t[i]) || t[i] == '\n')) i--; if (i) token_end = i + 1; - while (i && !member (t[i], " \n\t;|&")) + while (i && (member (t[i], " \n\t;|&") == 0)) i--; - while (i != token_end && member (t[i], " \t\n")) + while (i != token_end && (whitespace (t[i]) || t[i] == '\n')) i++; - if (token_end) + /* Print the offending token. */ + if (token_end || (i == 0 && token_end == 0)) { - char *error_token; - error_token = xmalloc (1 + (token_end - i)); - strncpy (error_token, t + i, token_end - i); - error_token[token_end - i] = '\0'; + if (token_end) + { + msg = xmalloc (1 + (token_end - i)); + strncpy (msg, t + i, token_end - i); + msg[token_end - i] = '\0'; + } + else /* one-character token */ + { + msg2[0] = t[i]; + msg2[1] = '\0'; + msg = msg2; + } - report_error ("syntax error near unexpected token `%s'", error_token); - free (error_token); - } - else if ((i == 0) && (token_end == 0)) /* a 1-character token */ - { - char etoken[2]; - etoken[0] = t[i]; - etoken[1] = '\0'; + parser_error (line_number, "syntax error near unexpected token `%s'", msg); - report_error ("syntax error near unexpected token `%s'", etoken); + if (msg != msg2) + free (msg); } - if (!interactive) + /* If not interactive, print the line containing the error. */ + if (interactive == 0) { - char *temp = savestring (shell_input_line); - char *name = bash_input.name ? bash_input.name : "stdin"; - int l = strlen (temp); - - while (l && temp[l - 1] == '\n') - temp[--l] = '\0'; + msg = savestring (shell_input_line); + token_end = strlen (msg); + while (token_end && msg[token_end - 1] == '\n') + msg[--token_end] = '\0'; - report_error ("%s: line %d: `%s'", name, line_number, temp); - free (temp); + parser_error (line_number, "`%s'", msg); + free (msg); } } else { - char *name, *msg; - if (!interactive) - name = bash_input.name ? bash_input.name : "stdin"; - if (EOF_Reached) - msg = "syntax error: unexpected end of file"; - else - msg = "syntax error"; - if (!interactive) - report_error ("%s: line %d: %s", name, line_number, msg); - else - { - /* This file uses EOF_Reached only for error reporting - when the shell is interactive. Other mechanisms are - used to decide whether or not to exit. */ - EOF_Reached = 0; - report_error (msg); - } + msg = EOF_Reached ? "syntax error: unexpected end of file" : "syntax error"; + parser_error (line_number, "%s", msg); + /* When the shell is interactive, this file uses EOF_Reached + only for error reporting. Other mechanisms are used to + decide whether or not to exit. */ + if (interactive && EOF_Reached) + EOF_Reached = 0; } last_command_exit_value = EX_USAGE; } @@ -4144,11 +4477,12 @@ report_syntax_error (message) allocated objects to the memory pool. In the case of no error, we want to throw away the information about where the allocated objects live. (dispose_command () will actually free the command. */ +static void discard_parser_constructs (error_p) int error_p; { } - + /* Do that silly `type "bye" to exit' stuff. You know, "ignoreeof". */ /* A flag denoting whether or not ignoreeof is set. */ @@ -4190,7 +4524,7 @@ handle_eof_input_unit () prompt_again (); last_read_token = current_token = '\n'; return; - } + } } /* In this case EOF should exit the shell. Do it now. */ diff --git a/y.tab.h b/y.tab.h index 7ba3b28..2acc11c 100644 --- a/y.tab.h +++ b/y.tab.h @@ -23,21 +23,23 @@ typedef union { #define FUNCTION 271 #define IN 272 #define BANG 273 -#define WORD 274 -#define ASSIGNMENT_WORD 275 -#define NUMBER 276 -#define AND_AND 277 -#define OR_OR 278 -#define GREATER_GREATER 279 -#define LESS_LESS 280 -#define LESS_AND 281 -#define GREATER_AND 282 -#define SEMI_SEMI 283 -#define LESS_LESS_MINUS 284 -#define AND_GREATER 285 -#define LESS_GREATER 286 -#define GREATER_BAR 287 -#define yacc_EOF 288 +#define TIME 274 +#define TIMEOPT 275 +#define WORD 276 +#define ASSIGNMENT_WORD 277 +#define NUMBER 278 +#define AND_AND 279 +#define OR_OR 280 +#define GREATER_GREATER 281 +#define LESS_LESS 282 +#define LESS_AND 283 +#define GREATER_AND 284 +#define SEMI_SEMI 285 +#define LESS_LESS_MINUS 286 +#define AND_GREATER 287 +#define LESS_GREATER 288 +#define GREATER_BAR 289 +#define yacc_EOF 290 extern YYSTYPE yylval;